Merge pull request #3488 from platinumazure/include-updated-options-in-sync-callback

Include updated options in sync callbacks
This commit is contained in:
Adam Krebs
2015-02-17 19:20:02 -05:00
3 changed files with 113 additions and 11 deletions

View File

@@ -533,7 +533,7 @@
// If the server returns an attributes hash that differs, the model's
// state will be `set` again.
save: function(key, val, options) {
var attrs, method, xhr, attributes = this.attributes;
var attrs, method, xhr, attributes = this.attributes, wait;
// Handle both `"key", value` and `{key: value}` -style arguments.
if (key == null || typeof key === 'object') {
@@ -544,18 +544,19 @@
}
options = _.extend({validate: true}, options);
wait = options.wait;
// If we're not waiting and attributes exist, save acts as
// `set(attr).save(null, opts)` with validation. Otherwise, check if
// the model will be valid when the attributes, if any, are set.
if (attrs && !options.wait) {
if (attrs && !wait) {
if (!this.set(attrs, options)) return false;
} else {
if (!this._validate(attrs, options)) return false;
}
// Set temporary attributes if `{wait: true}`.
if (attrs && options.wait) {
if (attrs && wait) {
this.attributes = _.extend({}, attributes, attrs);
}
@@ -568,7 +569,7 @@
// Ensure attributes are restored during synchronous saves.
model.attributes = attributes;
var serverAttrs = model.parse(resp, options);
if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
if (wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
return false;
}
@@ -582,7 +583,7 @@
xhr = this.sync(method, this, options);
// Restore attributes.
if (attrs && options.wait) this.attributes = attributes;
if (attrs && wait) this.attributes = attributes;
return xhr;
},
@@ -594,6 +595,7 @@
options = options ? _.clone(options) : {};
var model = this;
var success = options.success;
var wait = options.wait;
var destroy = function() {
model.stopListening();
@@ -601,7 +603,7 @@
};
options.success = function(resp) {
if (options.wait || model.isNew()) destroy();
if (wait || model.isNew()) destroy();
if (success) success.call(options.context, model, resp, options);
if (!model.isNew()) model.trigger('sync', model, resp, options);
};
@@ -613,7 +615,7 @@
wrapError(this, options);
var xhr = this.sync('delete', this, options);
if (!options.wait) destroy();
if (!wait) destroy();
return xhr;
},
@@ -973,13 +975,14 @@
// wait for the server to agree.
create: function(model, options) {
options = options ? _.clone(options) : {};
var wait = options.wait;
if (!(model = this._prepareModel(model, options))) return false;
if (!options.wait) this.add(model, options);
if (!wait) this.add(model, options);
var collection = this;
var success = options.success;
options.success = function(model, resp) {
if (options.wait) collection.add(model, options);
if (success) success.call(options.context, model, resp, options);
options.success = function(model, resp, callbackOptions) {
if (wait) collection.add(model, callbackOptions);
if (success) success.call(callbackOptions.context, model, resp, callbackOptions);
};
model.save(null, options);
return model;

View File

@@ -530,6 +530,29 @@
equal(col.create({"foo":"bar"}, {validate:true}), false);
});
test("create will pass extra options to success callback", 1, function () {
var SpecialSyncModel = Backbone.Model.extend({
sync: function (method, model, options) {
_.extend(options, { specialSync: true });
return Backbone.Model.prototype.sync.call(this, method, model, options);
}
});
var SpecialSyncCollection = Backbone.Collection.extend({
model: SpecialSyncModel,
url: '/test'
});
var collection = new SpecialSyncCollection();
var onSuccess = function (model, response, options) {
ok(options.specialSync, "Options were passed correctly to callback");
};
collection.create({}, { success: onSuccess });
this.ajaxSettings.success();
});
test("a failing create returns model with errors", function() {
var ValidatingModel = Backbone.Model.extend({
validate: function(attrs) {
@@ -1199,6 +1222,25 @@
Backbone.ajax = ajax;
});
test("fetch will pass extra options to success callback", 1, function () {
var SpecialSyncCollection = Backbone.Collection.extend({
url: '/test',
sync: function (method, collection, options) {
_.extend(options, { specialSync: true });
return Backbone.Collection.prototype.sync.call(this, method, collection, options);
}
});
var collection = new SpecialSyncCollection();
var onSuccess = function (collection, resp, options) {
ok(options.specialSync, "Options were passed correctly to callback");
};
collection.fetch({ success: onSuccess });
this.ajaxSettings.success();
});
test("`add` only `sort`s when necessary", 2, function () {
var collection = new (Backbone.Collection.extend({
comparator: 'a'

View File

@@ -590,12 +590,50 @@
equal(this.ajaxSettings.url, '/collection/42');
});
test("save will pass extra options to success callback", 1, function () {
var SpecialSyncModel = Backbone.Model.extend({
sync: function (method, model, options) {
_.extend(options, { specialSync: true });
return Backbone.Model.prototype.sync.call(this, method, model, options);
},
urlRoot: '/test'
});
var model = new SpecialSyncModel();
var onSuccess = function (model, response, options) {
ok(options.specialSync, "Options were passed correctly to callback");
};
model.save(null, { success: onSuccess });
this.ajaxSettings.success();
});
test("fetch", 2, function() {
doc.fetch();
equal(this.syncArgs.method, 'read');
ok(_.isEqual(this.syncArgs.model, doc));
});
test("fetch will pass extra options to success callback", 1, function () {
var SpecialSyncModel = Backbone.Model.extend({
sync: function (method, model, options) {
_.extend(options, { specialSync: true });
return Backbone.Model.prototype.sync.call(this, method, model, options);
},
urlRoot: '/test'
});
var model = new SpecialSyncModel();
var onSuccess = function (model, response, options) {
ok(options.specialSync, "Options were passed correctly to callback");
};
model.fetch({ success: onSuccess });
this.ajaxSettings.success();
});
test("destroy", 3, function() {
doc.destroy();
equal(this.syncArgs.method, 'delete');
@@ -605,6 +643,25 @@
equal(newModel.destroy(), false);
});
test("destroy will pass extra options to success callback", 1, function () {
var SpecialSyncModel = Backbone.Model.extend({
sync: function (method, model, options) {
_.extend(options, { specialSync: true });
return Backbone.Model.prototype.sync.call(this, method, model, options);
},
urlRoot: '/test'
});
var model = new SpecialSyncModel({ id: 'id' });
var onSuccess = function (model, response, options) {
ok(options.specialSync, "Options were passed correctly to callback");
};
model.destroy({ success: onSuccess });
this.ajaxSettings.success();
});
test("non-persisted destroy", 1, function() {
var a = new Backbone.Model({ 'foo': 1, 'bar': 2, 'baz': 3});
a.sync = function() { throw "should not be called"; };