Backbone.js и FormData
Есть ли способ использовать Backbone.js и модельную архитектуру, чтобы я мог отправить объект formdata на сервер? Проблема, с которой я сталкиваюсь, заключается в том, что все сообщения Backbone кодируются как JSON, поэтому объект formdata не отправляется должным образом (очевидно).
Я временно работаю над этим, создавая прямой запрос ajax jQuery и включающий объект formdata в качестве свойства данных, но это меньше, чем идеально.
Ответы
Ответ 1
Вот решение, переопределив метод sync
, который я использую, чтобы разрешить загрузку файлов.
В этом случае я переопределяю метод модели sync
, но это также может быть метод Backbone.sync
.
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:
Чтобы отслеживать процесс загрузки, вы можете добавить опцию xhr
к параметрам:
...
_.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
Просто чтобы добавить ответ на этот вопрос, вот как я обходился, не оборачивая sync
:
На мой взгляд, у меня есть что-то вроде:
$('#' + $(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);
});
Что затем запускает функцию в контроллере, которая делает это:
var picture_entity = new appManager.Entities.ProfilePicture();
picture_entity.save(null, {
data: data,
contentType: false,
processData: false,
});
В этот момент я переопределяю jQuery data
с моим объектом FormData
.
Ответ 3
У меня было аналогичное требование, и вот что я сделал:
В представлении:
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");
}
});
}
});
Надеюсь, что это поможет.
Ответ 4
У меня была такая же проблема. Вы можете видеть, как я его решаю.
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
}
}));
hasFile - это настраиваемый метод, который расширяет функции JQuery.
$.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;
};
Ответ 5
Просто используйте Backbone.emulateJSON = true;
: http://backbonejs.org/#Sync-emulateJSON
приведет к тому, что JSON будет сериализован под параметром модели, и запрос, который должен быть выполнен с типом MIME приложения /x -www-form-urlencoded, как будто из HTML-формы.
Ответ 6
Ни один из ответов не работал у меня, ниже - простое и легкое решение. Переопределяя метод sync
и options.contentType
следующим образом:
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);
}
Ответ 7
Простой будет, надеюсь, это поможет кому-то.
-
Создайте объект Backbone Model:
var importModel = new ImportModel();
-
Вызовите Save [POST] метод базовой модели и передайте объект FormData.
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) { }
});