Skip to content

Commit

Permalink
Fixes jashkenas#563. Initial draft of 'wait: true' for pessimistic in…
Browse files Browse the repository at this point in the history
…stead of optimistic save() create() and destroy(). Makes it easier to have your asynchronous UI and eat it too.
  • Loading branch information
jashkenas committed Jan 17, 2012
1 parent cdce2ec commit cea56e5
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 14 deletions.
31 changes: 21 additions & 10 deletions backbone.js
Expand Up @@ -302,11 +302,13 @@
}

options = options ? _.clone(options) : {};
if (attrs && !this.set(attrs, options)) return false;
if (attrs && !this[options.wait ? '_performValidation' : 'set'](attrs, options)) return false;
var model = this;
var success = options.success;
options.success = function(resp, status, xhr) {
if (!model.set(model.parse(resp, xhr), options)) return false;
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);
} else {
Expand All @@ -319,22 +321,30 @@
},

// Destroy this model on the server if it was already persisted.
// Upon success, the model is removed from its collection, if it has one.
// Optimistically removes the model from its collection, if it has one.
// If `wait: true` is passed, waits for the server to respond before removal.
destroy : function(options) {
options = options ? _.clone(options) : {};
if (this.isNew()) return this.trigger('destroy', this, this.collection, options);
var model = this;
var success = options.success;
options.success = function(resp) {

var triggerDestroy = function() {
model.trigger('destroy', model, model.collection, options);
};

if (this.isNew()) return triggerDestroy();
options.success = function(resp) {
if (options.wait) triggerDestroy();
if (success) {
success(model, resp);
} else {
model.trigger('sync', model, resp, options);
}
};
options.error = Backbone.wrapError(options.error, model, options);
return (this.sync || Backbone.sync).call(this, 'delete', this, options);
var xhr = (this.sync || Backbone.sync).call(this, 'delete', this, options);
if (!options.wait) triggerDestroy();
return xhr;
},

// Default URL for the model's representation on the server -- if you're
Expand Down Expand Up @@ -580,17 +590,18 @@
return (this.sync || Backbone.sync).call(this, 'read', this, options);
},

// Create a new instance of a model in this collection. After the model
// has been created on the server, it will be added to the collection.
// Returns the model, or 'false' if validation on a new model fails.
// Create a new instance of a model in this collection. Add the model to the
// collection immediately, unless `wait: true` is passed, in which case we
// wait for the server to agree.
create : function(model, options) {
var coll = this;
options = options ? _.clone(options) : {};
model = this._prepareModel(model, options);
if (!model) return false;
if (!options.wait) coll.add(model, options);
var success = options.success;
options.success = function(nextModel, resp, xhr) {
coll.add(nextModel, options);
if (options.wait) coll.add(nextModel, options);
if (success) {
success(nextModel, resp);
} else {
Expand Down
2 changes: 1 addition & 1 deletion test/collection.js
Expand Up @@ -346,7 +346,7 @@ $(document).ready(function() {
});

test("Collection: create", function() {
var model = col.create({label: 'f'});
var model = col.create({label: 'f'}, {wait: true});
equals(lastRequest[0], 'create');
equals(lastRequest[1], model);
equals(model.get('label'), 'f');
Expand Down
3 changes: 2 additions & 1 deletion test/model.js
Expand Up @@ -356,7 +356,8 @@ $(document).ready(function() {
attrs = { 'foo': 1, 'bar': 2, 'baz': 3};
a = new Backbone.Model(attrs);
a.sync = function() { throw "should not be called"; };
ok(a.destroy(), "non-persisted model should not call sync");
a.destroy();
ok(true, "non-persisted model should not call sync");
});

test("Model: validate", function() {
Expand Down
4 changes: 2 additions & 2 deletions test/sync.js
Expand Up @@ -36,7 +36,7 @@ $(document).ready(function() {
});

test("sync: create", function() {
library.add(library.create(attrs));
library.create(attrs, {wait: false});
equals(lastRequest.url, '/library');
equals(lastRequest.type, 'POST');
equals(lastRequest.dataType, 'json');
Expand Down Expand Up @@ -106,7 +106,7 @@ $(document).ready(function() {
});

test("sync: destroy", function() {
library.first().destroy();
library.first().destroy({wait: true});
equals(lastRequest.url, '/library/2-the-tempest');
equals(lastRequest.type, 'DELETE');
equals(lastRequest.data, null);
Expand Down

0 comments on commit cea56e5

Please sign in to comment.