Подтвердить что ты не робот

Обновление частичной модели Backbone.js

Можно ли отправлять измененные свойства модели при сохранении изменений?

Кстати, есть ли "официальная" группа/список рассылки Backbone.js, чтобы задать такие вопросы?

4b9b3361

Ответ 1

В настоящее время базовая станция не поддерживает отправку части модели на сервер. Это было бы интересным дополнением, хотя.

Если вы просмотрите источник, вы увидите, что Backbone.sync (часть магистрали, которая отвечает за связь с хранилищем данных) один из простейших компонентов в магистрали и просто обертывает поддержку ajax в jQuery или Zepto.


UPDATE

начиная базовую версию 0.9.10, частичное обновление модели поддерживается изначально через

model.save(attrs, {patch: true})

Ответ 2

Backbone не поддерживает это из коробки, но у вас есть все инструменты, чтобы это произошло. Если вы посмотрите на Backbone.sync, вы увидите, что он вызывает JSON на вашей модели, чтобы получить фактические данные для отправки. Теперь вам, возможно, придется откорректировать это, но вот суть этого:

initialize: function(){
  this.dirtyAttributes = {}
},
set: function(attrs, options){
  Backbone.Model.prototype.set.call(this, attrs, options);
  _.extend(this.dirtyAttributes, attrs);
},
toJSON : function(){
  json = this.dirtyAttributes;
  this.dirtyAttributes = {};
  return json;
}

Если вы хотите получить полное решение, вам нужно применить ту же логику для отмены, очистки, сохранения и т.д. Но я думаю, вы понимаете, как это сделать. Я поместил reset из грязных атрибутов в функцию toJSON, но он действительно должен быть в обратном вызове успеха (при вызове save).

Ответ 3

UPDATE: начальная базовая версия 0.9.10, частичное обновление поддерживается изначально через

model.save(attrs, {patch: true})


До 0.9.9 Подход без прямого редактирования файла библиотеки backbone.js. Просто добавьте следующий код в файл приложения js и загрузите его после загрузки backbone.js.

//override the Backbone.sync to send only the changed fields for update (PUT) request
var Original_BackboneSync = Backbone.sync;

Backbone.sync = function(method, model, options) {
    /* just handle the data picking logic for update method */
    if (!options.data && model && method == 'update') {
        options.contentType = 'application/json';
        options.data = JSON.stringify(model.changedAttributes() || {});
    }

    //invoke the original backbone sync method
    return Original_BackboneSync.apply(this, arguments);
};

//Tested in Backbone.js 0.9.1

Ответ 4

Я попробовал несколько методов, которые были предложены здесь, но, в конце концов, решил напрямую изменить Backbone.Model и Backbone.sync. То, что я хотел предоставить, было минимально инвазивным методом для обеспечения этой функциональности, которая не требовала инструктирования разработчиков в моей команде по переопределению базовых методов; слишком подвержен ошибкам. Мое решение включает только передачу опции методу "сохранить" модели. Например:

//Note that this could be from your view or anywhere you're invoking model.save
saveToModel : function() {
    this.model.save({
        field1 : field1Value,
        field2 : field2Value,
        field3 : field3Value
    }, {partialUpdate : true}
}

Теперь, чтобы включить эту функциональность, я внес некоторые незначительные изменения в Backbone.Model.save и Backbone.sync. Здесь изменение в Backbone.Model.save:

//If a partialUpdate is required, create a member on the options
//hash called updateAttrs and set it to attrs
if (options.partialUpdate != "undefined" && options.partialUpdate) {
    options.updateAttrs = attrs;
}
//--->>>Put the block above right above the return line
return (this.sync || Backbone.sync).call(this, method, this, options);

Что происходит, так это то, что если partialUpdate передается как опция, то в хэшеле параметров создается новый член, называемый updateAttrs. Хэш параметров автоматически передается на Backbone.sync.

Для Backbone.sync я изменил следующее условие:

// Ensure that we have the appropriate request data.
if (!params.data && model && (method == 'create' || method == 'update')) {
    params.contentType = 'application/json';
    params.data = JSON.stringify(model.toJSON());
}

чтобы...

// Ensure that we have the appropriate request data.
if (!params.data && model && (method == 'create' || method == 'update')) {
    params.contentType = 'application/json';

    //If doing a partial model update, then grab the updateAttrs member
    //from options. Will not interfere with line directly below as params.data
    //will have been set.
    params.data = (options.partialUpdate != "undefined" && options.partialUpdate)
                ? params.data = JSON.stringify(options.updateAttrs)
                : params.data = JSON.stringify(model.toJSON());
}

Добавление дополнительных условных проверок, чтобы определить, был ли partialUpdate установлен, тогда, если это так, установите params.data в options.updateAttrs. Затем это будет передано в метод jquery Ajax.

Ответ 5

Вместо перезаписи Backbone.sync вы можете просто сделать это внутри метода Model.sync. Поскольку вы не можете получить доступ к model.changedAttributes() там, обязательно верните false внутри этого метода.

sync: (method, model, options) ->
  if method is "update"
    options.contentType = 'application/json'
    changedData = {}
    for attr in _.keys(options.changes)
      changedData[attr] = model.get(attr)
    options.data = JSON.stringify changedData

  Backbone.sync method, model, options

Ответ 6

Если вам нужно отправить запрос на обновление на сервер с определенными атрибутами, вы можете сделать что-то подобное:

saveAttributes: (attributes, options={}) ->
  data = {}
  _(attributes).each (attribute) =>
    data[attribute] = @get(attribute)

  params =
    data: $.param(data)

  _.extend(params, options)

  Backbone.sync('update', null, params)

Подробнее об этом: https://github.com/documentcloud/backbone/pull/573

Вы можете расширить его с помощью _.extend Backbone.Model.prototype

Ответ 7

Большинство ответов здесь прямо или косвенно изменяют функцию sync. Вот мой маленький трюк, чтобы преодолеть это:

Когда вы вызываете свой model.save, вы можете передать второй параметр, который будет передан вместе с $.ajax, когда Backbone пытается вызвать синхронизацию. Я сделал частичное обновление, как это, более явно указывая, какие поля отправить:

/**
 * On user clicking on "mark important"
 */
onMarkImportantBtnClick: function() {
    var marked = this.model.get('UserFeed.marked_important'),
        data = {
            UserFeed: {
                marked_important: !marked
            }
        };
    this.model.save(data, {data: JSON.stringify(data), contentType: 'application/json'});
}

Это действие правильно обновило мои атрибуты модели, а также отправило на сервер только данные, указанные в JSON.stringify. contentType здесь требуется, лучше

Это связано с тем, что Backbone.sync имеет эти строки, и мы отрицаем его, передавая атрибут data:

if (!options.data && model && (method == 'create' || method == 'update')) {
    params.contentType = 'application/json';
    params.data = JSON.stringify(model.toJSON());
}

Кредит на эту страницу: https://plus.google.com/103858073822961240171/posts/1gTcu6avmWQ

Примечание. Эта модель унаследована от powmedia DeepModel для поддержки вложенных атрибутов модели


Edit

Так как добавлена ​​опция Backbone 0.9.9, patch, этот трюк применим только к предыдущей версии.

Чтобы отправить только грязные данные на ваш сервер, поставьте {patch: true} в свой save, чтобы

this.model.save(modifiedData, {patch: true});

Спасибо @Lincoln B за указание на это.

Ответ 8

Используя (очень хороший) ответ Jayyy V, я немного переписал его, чтобы заставить функцию синхронизации взять белый список, чтобы вы могли дать ему массив ключей, которые будут сохранены.

var Original_BackboneSync = Backbone.sync;
Backbone.sync = function(method, model, options) {
    /* check if a whitelist was in options */
    if (options.whitelist) {
      options.contentType = 'application/json';
      /* use underscore method for picking only whitelisted attributes to save */
      options.data = JSON.stringify(_.pick(model.attributes, options.whitelist));
    }

    //invoke the original backbone sync method
    return Original_BackboneSync.apply(this, arguments);
};

Ответ 9

Основываясь на сообщении @Julien: Вы можете добавить это в свою модель, и она будет отправлять только те атрибуты, которые вы передаете, в отличие от всей модели. Вы можете использовать сохранение для поведения по умолчанию, и вы можете использовать partialSave, когда хотите просто отправить те атрибуты, которые вы передаете в качестве параметра. Я проверил это, и это сработало для меня.

  partialSave: function(attr, options) { //use this method instead of save()
    this.dirtyAttributes = attr;
    this.save(attr, options);
  },

  toJSON: function() { //overrides Backbone.Model.prototype.toJSON
    if (this.dirtyAttributes) {
      var attr = this.dirtyAttributes;
      this.dirtyAttributes = null;
      return attr;
    }
    return Backbone.Model.prototype.toJSON.apply(this, arguments);
  },

Ответ 10

Фактически существует гораздо более простой способ достижения этого

если вы посмотрите на строку backbone.js 1145, вы увидите, что

// Ensure that we have the appropriate request data.
    if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
      params.contentType = 'application/json';
      params.data = JSON.stringify(options.attrs || model.toJSON(options));
    }

Это означает, что вы можете переопределить часть данных xhr, поместив данные в свои параметры

Так как для сохранения базы требуется model.save([attributes], [options])

Но помните, что атрибуты, такие как id, могут быть необходимы для правильного сохранения

Пример

model.save( {}, { data: JSON.stringify(data) } ) ; 

Итак, вы должны делать что-то вроде этого

var data = { id : model.id , otherAttributes : 'value' }  ;  

или

var data = model.toJSON () ;
remove data.tempData ; 

Наконец

model.save( {}, { data : JSON.stringify(data) } );

Это хорошо подходит для меня и может использоваться с любой основой с xhr, например, с помощью fetch, save, delete,...

Посылка с помощью save, sync или toJSON выглядит так неправильно

Ответ 11

Я создал расширенную модель.

var CModel = Backbone.Model.extend({
    save: function(attributes, options) {
        if(_.isUndefined(options)) {
            options = {};
        }

        var isNeedAttrsRefresh = false,
            basicAttributes = null;

        if(!_.isUndefined(options.fields)) {
            basicAttributes = _.clone(this.attributes);
            var newAttributes = {};
            _.each(this.attributes, function(value, name) {
                if(options.fields.indexOf(name) > -1) {
                    newAttributes[name] = value;
                }
            });
            this.attributes = newAttributes;
            isNeedAttrsRefresh = true;
        }

        this.isSaving = true;
        var result = Backbone.Model.prototype.save.apply(this, arguments);
        this.isSaving = false;

        if(isNeedAttrsRefresh) {
            this.attributes = basicAttributes;
        }

        return result;
    }
});

Пример использования:

var CommentModel = CModel.extend({ ... }

И разрешенные поля для сохранения:

comment.save(null, {    fields: ['message', 'entry_id', 'module_id', 'parent_id'] });