2013-02-07 10 views
12

Gibt es eine Möglichkeit, Backbone.js und seine Modellarchitektur zu verwenden, dass ich ein Formdata-Objekt an den Server senden kann? Das Problem, auf das ich stoße, ist, dass alles, was Backbone sendet, als JSON kodiert ist, so dass das formdata-Objekt (offensichtlich) nicht richtig gesendet wird.Backbone.js und FormData

Ich arbeite vorübergehend um dies, indem Sie eine direkte jQuery Ajax Anfrage und einschließlich der Formdata-Objekt als Daten-Eigenschaft, aber das ist weniger als ideal.

+0

Sie können außer Kraft setzen [ 'sync'] (http://backbonejs.org/#Sync) global, pro-Modell oder pro-Sammlung an den Server, wie Sie wollen reden. –

+0

Hey, dein Vorschlag war der Ansatz, mit dem ich ging. Fühlen Sie sich frei, das als Antwort einzureichen, und ich werde es genehmigen. – Leonidas

Antwort

7

einfach eine Antwort auf diese Frage hinzufügen möchten, heres, wie ich es ging, ohne die sync außer Kraft zu setzen mit:

Aus meiner Sicht habe ich somethign wie:

$('#' + $(e.currentTarget).data('fileTarget')).trigger('click').unbind('change').bind('change', function(){ 
    var form_data = new FormData(); 
    form_data.append('file', $(this)[0].files[0]); 
    appManager.trigger('user:picture:change', form_data); 
}); 

, die dann ein Trigger Funktion in einer Steuerung, das dies tut:

var picture_entity = new appManager.Entities.ProfilePicture(); 
picture_entity.save(null, { 
    data: data, 
    contentType: false, 
    processData: false, 
}); 

an diesem Punkt bin ich zwingende jQuery data mit meinem FormData Objekt.

7

Ich hatte eine ähnliche Anforderung und hier ist das, was ich tat:

In Aussicht:

var HomeView = Backbone.View.extend({ 
    el: "#template_loader", 
    initialize: function() { 
     console.log('Home View Initialized'); 
    }, 
    render: function() { 
     var inputData = { 
      cId: cId, 
      latitude: latitude, 
      longitude: longitude 
     }; 

     var data = new FormData(); 

     data.append('data', JSON.stringify(inputData)); 

     that.model.save(data, { 
      data: data, 
      processData: false, 
      cache: false, 
      contentType: false, 
      success: function (model, result) { 
       alert("Success"); 
      }, 
      error: function() { 
       alert("Error"); 
      } 
     }); 
    } 
});  

Hoffnung, das hilft.

16

Hier ist eine Lösung durch Überschreiben der sync-Methode, die ich verwenden, um Dateiuploads zu ermöglichen.

In diesem Fall überschreibe ich die sync Methode des Modells, aber dies kann auch die Backbone.sync Methode sein.

var FileModel = Backbone.Model.extend({ 

    urlRoot: CMS_ADMIN_URL + '/config/files', 

    sync: function(method, model, options){ 

    // Post data as FormData object on create to allow file upload 
    if(method == 'create'){ 
     var formData = new FormData(); 

     // Loop over model attributes and append to formData 
     _.each(model.attributes, function(value, key){ 
     formData.append(key, value); 
     }); 

     // Set processData and contentType to false so data is sent as FormData 
     _.defaults(options || (options = {}), { 
     data: formData, 
     processData: false, 
     contentType: false 
     }); 
    } 
    return Backbone.sync.call(this, method, model, options); 
    } 
}); 

EDIT:

Um Upload-Fortschritt zu verfolgen, können Sie eine xhr Option Optionen hinzufügen:

... 

_.defaults(options || (options = {}), { 
    data: formData, 
    processData: false, 
    contentType: false 
    xhr: function(){ 
    // get the native XmlHttpRequest object 
    var xhr = $.ajaxSettings.xhr(); 
    // set the onprogress event handler 
    xhr.upload.onprogress = function(event) { 
     if (event.lengthComputable) { 
     console.log('%d%', (event.loaded/event.total) * 100); 
     // Trigger progress event on model for view updates 
     model.trigger('progress', (event.loaded/event.total) * 100); 
     } 
    }; 
    // set the onload event handler 
    xhr.upload.onload = function(){ 
     console.log('complete'); 
     model.trigger('progress', 100); 
    }; 
    // return the customized object 
    return xhr; 
    } 
}); 

... 
+2

Dies ist eine gute Antwort, IMO die beste auf dieser Seite. Die richtige Art und Weise, Server Kommunikation zu behandeln, ist die Synchronisierungsmethode, hier auf der Modell-Ebene zu bearbeiten, aber es erfordert * nicht * erfordern ausgiebig Affe-Patch es: nur bearbeiten Der Optionen-Hash (mit den Daten und XHR-Optionen), und Sie sind fertig. – chikamichi

2

Ich hatte das gleiche Problem. Sie können über den Weg sehen, wie ich es löse.

var $form = $("myFormSelector"); 

//==> GET MODEL FROM FORM 
var model = new MyBackboneModel(); 
var myData = null; 
var ajaxOptions = {}; 
// Check if it is a multipart request. 
if ($form.hasFile()) { 
    myData = new FormData($form[0]); 
    ajaxOptions = { 
     type: "POST", 
     data: myData, 
     processData: false, 
     cache: false, 
     contentType: false 
    }; 
} else { 
    myData = $form.serializeObject(); 
} 

// Save the model. 
model.save(myData, $.extend({}, ajaxOptions, { 
    success: function(model, data, response) { 
     //==> INSERT SUCCESS 
    }, 
    error: function(model, response) { 
     //==> INSERT ERROR 
    } 
})); 

Die hasFile ist eine benutzerdefinierte Methode, die die JQuery-Funktionen erweitert.

$.fn.hasFile = function() { 
    if ($.type(this) === "undefined") 
     return false; 

    var hasFile = false; 
    $.each($(this).find(":file"), function(key, input) { 
     if ($(input).val().length > 0) { 
      hasFile = true; 
     } 
    }); 

    return hasFile; 
}; 
2

Gerade Backbone.emulateJSON = true; benutzen http://backbonejs.org/#Sync-emulateJSON

bewirkt, dass der JSON unter einem Modellparameter serialisiert werden, und die Anfrage mit einer Anwendung/x-www-form-urlencoded MIME-Typ hergestellt werden soll, wie aus einem HTML-Formular.

+0

Aber dies serialisiert JSON in String und wird als stringähnliches Objekt angezeigt. –

+0

Er erstellt das formData-Objekt und sendet es an den Server –

1

Keine der Antworten funktionierte für mich, unten ist einfache und einfache Lösung. Durch das Überschreiben sync Verfahren und options.contentType wie folgt aus:

sync: function(method, model, options) { 
    options = _.extend({ 
     contentType : 'application/x-www-form-urlencoded;charset=UTF-8' 
    }, options); 

    options.data = jQuery.param(model.toJSON()); 

    return Backbone.sync.call(this, method, model, options); 
} 
0

Ein einfaches sein wird, hoffen, dass dies jemand helfen.

  1. ein Objekt von Backbone Modell erstellen:

    var importModel = new ImportModel(); 
    
  2. Anruf speichern [POST] Methode von Backbone Modell und das Objekt Formdata Pass.

    var objFormData = new FormData(); 
    objFormData.append('userfile', files[0]); 
    
    importModel.save(objFormData, { 
    contentType: false, 
    data: objFormData, 
    processData: false, 
    success: function(data, status, xhr) { }, 
    error: function(xhr, statusStr) { } 
    });