2012-10-25 12 views
5

Ich würde gerne in der Lage sein, jQuery's Deferred-Objekt zu verwenden, um das Laden von Daten über Backbone Collections und Models zu betreiben. Gibt es eine Möglichkeit, die Argumente zu ändern, die für die Rückrufaktionen done und fail bereitgestellt werden, um die Model- oder Collection-Instanz einzuschließen? Ich bin etwas Vorstellungsvermögen wie folgt aus:Kann ich die deferred.pipe-Methode von jQuery verwenden, um die Argumente für aufgelöste/fehlgeschlagene Callbacks zu ändern?

var _sync = Backbone.sync; 

Backbone.sync = function() { 
    var jqXhr = _sync.apply(this, arguments); 

    var self = this; 
    return jqXhr.pipe(function() { 
     var cbArgs = [self]; 
     cbArgs.push.apply(cbArgs, arguments); 
     return cbArgs; 
    } 
} 

... 
var c = new Backbone.Collection(); 
c.url = "/path/to/resources"; 
c.fetch().then(function(collection, data, textStatus, jqXhr) { 
    // do stuff with collection 
}); 

Natürlich, da Filter ein Array zurückgibt, die getan Rückruf wird mit einem Array aufgerufen, anstatt die aufgezählten Argumente. Soweit ich sehen kann, kann Pipe nur die angegebenen Argumente modifizieren, nicht hinzufügen. Irgendwelche Vorschläge würden geschätzt werden.

Edit: Dies ist ein sehr vereinfachtes Beispiel; Da eine Schließung über der ursprünglichen Sammlung erstellt wurde, konnte ich einfach daran arbeiten. Der Anwendungsfall ist jedoch, dass sich mehrere Backbone-Ansichten auf die gleichen Daten beziehen, die abgerufen werden. Daher möchte ich das jQuery Deferred-Objekt nur diesen Sichten und nicht nur der verzögerten und der Sammlungsinstanz zur Verfügung stellen.

Andere Edit: Posted eine Lösung unten, aber andere Vorschläge willkommen.

Antwort

2

Ich habe festgestellt, ich dies erreichen kann die .pipe Methode einen neuen $ zurückgeben .Deferred, indem die sofort die geändertenen Argumente behoben:

var _sync = Backbone.sync; 

Backbone.sync = function() { 
    var jqXhr = _sync.apply(this, arguments); 

    var self = this; 
    var deferred = jqXhr.pipe(function() { 
     var cbArgs = [self]; 
     cbArgs.push.apply(cbArgs, arguments); 
     var deferred = new $.Deferred(); 
     return deferred.resolve.apply(deferred, cbArgs); 
    }); 
    return $.extend(true, jqXhr, deferred); 
}; 
+0

Edite d um das ursprüngliche jqXhr um das neue $ .Deferred zu erweitern, wobei die Unterstützung für alle AJAX-spezifischen Methoden (.success, .abort, etc.) erhalten bleibt. – philm

1

Eine Lösung sehr ähnlich wie Ihre Antwort, aber ohne Rohr, da Sie nicht wirklich brauchen die Ergebnisse zu filtern: ich kehre direkt einen neuen aus Backbone.sync latenten statt kochend ein

latenten Resolved
Backbone.originalSync = Backbone.sync; 
Backbone.sync = function(method, model, options) { 
    var xhr = Backbone.originalSync.call(this, method, model, options); 

    var dfd = $.Deferred(); 
    xhr.done(function() { 
     var cbArgs = [model].concat(_.toArray(arguments)); 
     dfd.resolve.apply(dfd, cbArgs); 
    }); 
    xhr.fail(function() { 
     var cbArgs = [model].concat(_.toArray(arguments)); 
     dfd.reject.apply(dfd, cbArgs); 
    }); 

    return dfd; 
}; 

Und eine Fiddle http://jsfiddle.net/d8FqA/

Eine einfachere Variante, wenn Sie bereit sind, this zum Modell/Sammlung in Ihre Rückrufe gebunden zu haben, die die Funktionssignaturen unberührt lässt:

Backbone.originalSync = Backbone.sync; 
Backbone.sync = function(method, model, options) { 
    var xhr = Backbone.originalSync.call(this, method, model, options); 

    var dfd = $.Deferred(); 
    xhr.done(function() { 
     dfd.resolveWith(model, arguments); 
    }); 
    xhr.fail(function() { 
     dfd.rejectWith(model, arguments); 
    }); 

    return dfd; 
}; 

var c=new Backbone.Collection(); 
c.fetch().done(function() { 
    console.log(this); 
    console.log(arguments); 
}); 

http://jsfiddle.net/d8FqA/1/

, die das Modell führt uns passieren, wie Zusammenhang auf die Ajax-Anfrage:

Backbone.originalSync = Backbone.sync; 
Backbone.sync = function(method, model, options) { 
    options || (options={}) ; 
    options.context = model; 
    return Backbone.originalSync.call(this, method, model, options); 
}; 

var c=new Backbone.Collection(); 
c.fetch().done(function() { 
    console.log(this); 
}); 

http://jsfiddle.net/d8FqA/2/

+0

Interessant ... definitiv eine ähnliche Lösung. Eine Sache, von der beide Lösungen profitieren könnten, wäre, das ursprüngliche jqXhr-Objekt um die neuen Deferred zu erweitern, so dass sich die Antwort von Backbone.sync überhaupt nicht ändert (mit Ausnahme des Versprechens) ex.) Return $ .extend (wahr, xhr, dfd); – philm

+0

@phil Ich denke, wir können die Dinge viel vereinfachen, indem wir den Kontext in den Rückrufen verwenden und das xhr-Objekt in Ruhe lassen. Meine Antwort wurde mit einer Lösung aktualisiert – nikoshr

+0

Eines der Probleme, das sich hieraus ergibt, besteht darin, dass, wenn wir darauf warten, dass mehrere Abgrenzungen aufgelöst werden, an welche Sammlung der Kontext gebunden wird? ex :) var col1 = neu Bacbkone.Collection(), col2 = neu Backbone.Collection(); $ .when (col1.fetch(), col2.fetch()). then (function() {...}); – philm