Можно ли отправлять измененные свойства модели при сохранении изменений?
Кстати, есть ли "официальная" группа/список рассылки Backbone.js, чтобы задать такие вопросы?
Можно ли отправлять измененные свойства модели при сохранении изменений?
Кстати, есть ли "официальная" группа/список рассылки Backbone.js, чтобы задать такие вопросы?
В настоящее время базовая станция не поддерживает отправку части модели на сервер. Это было бы интересным дополнением, хотя.
Если вы просмотрите источник, вы увидите, что Backbone.sync
(часть магистрали, которая отвечает за связь с хранилищем данных) один из простейших компонентов в магистрали и просто обертывает поддержку ajax в jQuery или Zepto.
UPDATE
начиная базовую версию 0.9.10, частичное обновление модели поддерживается изначально через
model.save(attrs, {patch: true})
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).
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
Я попробовал несколько методов, которые были предложены здесь, но, в конце концов, решил напрямую изменить 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.
Вместо перезаписи 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
Если вам нужно отправить запрос на обновление на сервер с определенными атрибутами, вы можете сделать что-то подобное:
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
Большинство ответов здесь прямо или косвенно изменяют функцию 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 за указание на это.
Используя (очень хороший) ответ 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);
};
Основываясь на сообщении @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);
},
Фактически существует гораздо более простой способ достижения этого
если вы посмотрите на строку 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 выглядит так неправильно
Я создал расширенную модель.
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'] });