我的网络应用中有拖放功能。当用户在拖放之后释放鼠标时,使用Backbone在模型上的save()方法将对象的位置保存到服务器。当服务器响应时,它会触发模型上带有返回属性的set()。但是,在服务器处理请求的时间内,用户可能已经再次将对象拖动到其他位置。这会导致问题,因为来自服务器的响应现在将覆盖浏览器中对象的设置。
在save()之后从服务器获得响应后,有没有办法防止Backbone执行set()?
答案 0 :(得分:3)
在执行系统之前有类似的用例,虽然这样比较麻烦,因此我们需要真正覆盖模型set()
函数。虽然在这种情况下可以使用几种相对简单的方法。
您可以覆盖模型parse()功能。或者,您可以在abort()
调用返回的jqXHR对象上调用save()
。
答案 1 :(得分:2)
查看“等待”选项,默认情况下应将其设置为false,这意味着应在调用save()后立即设置模型字段。在设置更新的模型字段值之前,您可以设置{wait:true}以使主干等待服务器回复。
根据您描述的行为,听起来在应用程序中等待选项设置为true。
更多详情:http://backbonejs.org/#Model-save
另一个要记住的重要事项是,backbone只设置从被调用的webservice返回的更新字段的子集,所以如果你不返回任何,则将设置。
答案 2 :(得分:2)
Model.save
将使用相同的Model.parse
参数调用收到的数据options
。
您可以使用自定义标记(例如Model.save
)调用position: true
,表示Model.parse
可以放弃服务器返回的内容。
例如,假设您的坐标为x
和y
var M = Backbone.Model.extend({
parse: function(data, options) {
if (options && options.position)
data = _.omit(data, 'x', 'y');
return data;
}
});
var m = new M();
m.save({x: 10, y:10}, {position: true});
m.save({x: 20, y:20}, {position: true});
答案 3 :(得分:0)
我们使用了冻结UI的方法,直到执行了ajax请求。我们在保存之前和从服务器接收到应答后触发的模型中添加了两个额外的事件冻结/解冻。
答案 4 :(得分:0)
尝试覆盖'.sync()'方法。在覆盖您传入的成功回调之后,Backbone.save()委托给Backbone.sync()。这就是模型更新的来源。
从Backbone.save()方法的源代码:
var success = options.success;
options.success = function(resp) {
// Ensure attributes are restored during synchronous saves.
model.attributes = attributes;
var serverAttrs = model.parse(resp, options);
if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
return false;
}
if (success) success(model, resp, options);
model.trigger('sync', model, resp, options);
};
wrapError(this, options);
method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
if (method === 'patch') options.attrs = attrs;
xhr = this.sync(method, this, options);
您可以在调用'.save()'时传递自定义选项,然后查找该选项并覆盖'.sync()'中的options.success回调。可能是这样的事情吗?
MyModel = Backbone.Model.extend({
sync: function (method, context, options) {
if (options.skipUpdateOnResponse) {
options.success = myCusomSuccessFunction;
}
}
});
myModel = new MyModel();
myModel.save({...}, {skipUpdateOnResponse: true})
答案 5 :(得分:0)
服务器响应的属性是什么? Backbone使用的默认成功回调是:
if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) { ... }
遵循此逻辑,如果您的服务器未返回对象,则不应在您的模型上调用set
。
或者,如果您修改服务器响应,以便它不返回传入的位置信息(这是您的问题的根本原因,并且不了解您的要求,也似乎有点多余)这些属性不应该在调用set
时会被覆盖。
除非这些选项,覆盖{@ 1}}为@Uselessinfo建议或在sync
中添加一些技巧可能是您的下一个最佳选择。
答案 6 :(得分:0)
在模型上使用validate方法:
validate: function(attrs) {
var errors = [];
if (attrs.position !== this.get('position')) {
errors.push('Outdated info!');
}
return _.any(errors) ? errors : null;
}
这样,您可以将服务器响应与模型中的现有数据进行比较。如果服务器响应与模型中的数据不同,则返回错误,并且不会调用set
方法。这可能需要wait: true
方法选项中的save
。通过这种方法,我认为您应该在进行实际保存之前在模型上设置位置。
在保存之前调用validate,但也可以在设置{if:true}
之前调用
答案 7 :(得分:0)
Backbone保存成功回调:
options.success = function(resp, status, xhr) {
done = true;
var serverAttrs = model.parse(resp, xhr);
if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
if (!model.set(serverAttrs, options)) return false;
if (success) success(model, resp, options);
model.trigger('sync', model, resp, options);
};
所以它在调用触发器'sync'之前和调用用户成功函数之前调用all allways。 没有办法阻止Backbone做集,但有一种方法可以解决你的问题。 您可以像这样覆盖模型中的“set”函数:
set: function() {
if (this.skipSetOperation()) return false;
return Backbone.Model.prototype.set.apply(this, arguments);
},
skipSetOperation: function() {
//this function should return stage - can model set attributes in this moment or not
}
希望它有所帮助。
答案 8 :(得分:0)
我现在使用以下解决方案:
覆盖模型的默认解析方法:
Backbone.Model.prototype.parse = function(resp, options) {
if(options.parse)
return resp;
};
现在,您可以使用save方法并将属性'parse'设置为false,以防止ajax响应覆盖您当前的值:
MyModel.save({}, { parse: false });
答案 9 :(得分:-1)
为您的保存编写另一个功能,而不是使用保存使用您的功能。
模特中的:
var myModel = Backbone.Model.extend({
savePosition: function(){
var model = this;
$.ajax({
type : "POST",
cache: false,
dataType : 'json',
contentType : 'application/json',
data:JSON.stringify(data),
url : "urlToSave",
success:function(responseText,statusText){
model.trigger('saved',responseText);
},
error : function(error, dataObj, xhr) {
alert('Error');
}
});
}
}
这里在视图中保存绑定方法,并在保存后触发方法。
this.model.on('saved',function(){
// do call back stuff
});
this.model.savePosition({data:{...}});