Backbone.js и FormData

Можно ли каким-либо образом использовать Backbone.js и его модельную архитектуру, чтобы я мог отправить объект formdata на сервер? Проблема, с которой я сталкиваюсь, заключается в том, что все, что отправляет Backbone, кодируется как JSON, поэтому объект formdata не отправляется должным образом (очевидно).

Я временно работаю над этим, делая прямой запрос jQuery ajax и включая объект formdata в качестве свойства данных, но это далеко не идеально.


person Leonidas    schedule 07.02.2013    source источник
comment
Вы можете переопределить sync глобально, для каждой модели или для каждой коллекции, чтобы общаться с сервером любым удобным для вас способом. .   -  person mu is too short    schedule 07.02.2013
comment
Эй, ваше предложение было подходом, который я выбрал. Не стесняйтесь представить это как ответ, и я одобрю его.   -  person Leonidas    schedule 23.03.2013


Ответы (7)


Вот решение, переопределяющее метод 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);
  }
});

ИЗМЕНИТЬ:

Чтобы отслеживать ход загрузки, вы можете добавить опцию 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;
  }
});

...
person Koen.    schedule 17.01.2014
comment
Это хороший ответ, IMO лучший на этой странице. Правильный способ обработки связи с сервером - отредактировать метод синхронизации, здесь на уровне модели, но это не требует обширного исправления обезьяны это: просто отредактируйте хэш параметров (удерживая параметры данных и xhr), и все готово. - person chikamichi; 03.07.2014

Просто чтобы добавить ответ на этот вопрос, вот как я это сделал, не переопределяя 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,
});

В этот момент я переопределяю data jQuery своим объектом FormData.

person Prisoner    schedule 23.08.2013

У меня было подобное требование, и вот что я сделал:

С учетом :

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");
            }
        });
    }
});    

Надеюсь это поможет.

person Roy M J    schedule 10.01.2014

Я была такая же проблема. Вы можете видеть выше, как я это решаю.

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;
};
person George Siggouroglou    schedule 23.08.2014

Просто используйте Backbone.emulateJSON = true;: http://backbonejs.org/#Sync-emulateJSON

приведет к сериализации JSON под параметром модели, а запрос будет выполнен с типом MIME application/x-www-form-urlencoded, как если бы он был из HTML-формы.

person Yuriy Gatilin    schedule 27.03.2015
comment
Но это сериализует JSON в строку и отображается как объект, похожий на строку. - person Rahil Wazir; 24.12.2015
comment
Он создает объект formData и отправляет его на сервер - person Yuriy Gatilin; 21.07.2016

Ни один из ответов не сработал для меня, ниже приведено простое и простое решение. Переопределяя метод 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);
}
person Rahil Wazir    schedule 24.12.2015

Простой будет, надеюсь, это поможет кому-то.

  1. Создайте объект Backbone Model:

    var importModel = new ImportModel();
    
  2. Вызовите метод Save[POST] модели Backbone и передайте объект 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) { }
    });
    
person Siddharth    schedule 11.08.2017