2012-04-19 12 views
8

Ich arbeite mit der Todos Beispielanwendung bundled with the latest version of Backbone (0.9.2) beim Lernen über Backbone.js. Meine Frage ist, warum ist die App so konzipiert, dass das Render-Ereignis zweimal ausgelöst wird, wenn ein Modell zur Todos-Sammlung hinzugefügt wird?Backbone.js feuert Render zweimal auf Sammlung hinzufügen

Wenn Ich stelle diese Linie in der Funktion des TodoView machen: "Rendering"

// Re-render the titles of the todo item. 
render: function() { 
    console.log("Rendering!"); 
    this.$el.html(this.template(this.model.toJSON())); 

Dann erscheint zweimal in der Konsole. Ich verstehe dies, weil die Ansicht des Änderungsereignis Modell bindet die Ansicht des Render:

initialize: function() { 
    this.model.bind('change', this.render, this); 

Und macht in ADDone genannt wird, die zu den Todos' add Ereignis gebunden ist:

addOne: function(todo) { 
    var view = new TodoView({model: todo}); 
    this.$("#todo-list").append(view.render().el); 
}, 

Aber sind diese doppelte Rendering-Design-Standard-Praxis? Es scheint, als ob die Ansicht bei der Erstellung (oder dem Eintritt in das DOM) gerendert werden sollte, und dann wieder, wenn sich das zugrunde liegende Modell ändert. In diesem Fall wird nichts geändert, aber Render wird zweimal aufgerufen.

Noch einmal, ich lerne gerade Backbone, also kann ich ein grundlegendes Missverständnis haben, das zu meiner Verwirrung führt.

Antwort

5

Hm, hatte einen schnellen Blick. Sie haben Recht, dass dies geschieht, und nein, es ist nicht Standardpraxis. Der Grund ist ein bisschen obskur, also ertragen Sie mit mir;)

Die Todo App verwendet Backbone-Localstorage. Wenn Sie versuchen, ein neues Element in der App das Hinzufügen nennt es:

createOnEnter: function(e) { 
    if (e.keyCode != 13) return; 
    if (!this.input.val()) return; 

    Todos.create({title: this.input.val()}); 
    this.input.val(''); 
}, 

Beachten Sie die Todos.create. Normalerweise fügt ein create der Sammlung ein Modell hinzu und speichert es auf dem Server. Das Ereignis add wird somit ausgelöst. Es geschieht aber, dass Rückgrat-local tut folgendes auf create:

create: function(model) { 
    if (!model.id) model.set(model.idAttribute, guid()); 
    this.data[model.id] = model; 
    this.save(); 
    return model; 
}, 

Beachten Sie die model.set dem Modell eine ID zu geben. Dies löst das (zweite) Ereignis change aus.

Sie können das verhindern, indem zu tun Wechsel erstellen:

if (!model.id) model.id = guid();

+1

netter Fang! .. Sie können auch '{silent: true}' verwenden, um das Auslösen von Ereignissen zu vermeiden. – fguillen

+1

Sie haben Recht, deshalb wird das Änderungsereignis ausgelöst. Wenn Sie jedoch den Code in der von Ihnen vorgeschlagenen Weise ändern, wird das Ereignis gestoppt, aber auch die Funktionalität (ich kann Elemente nicht mehr löschen). Offensichtlich ist das für die Beantwortung meiner Frage nicht wichtig, aber nur für den Fall, dass dies jemand in der Zukunft liest, wollte ich darauf hinweisen. – jcady

+0

Elemente löschen _permanently_ das ist. Nach dem Löschen, wenn ich sie aktualisiere, existieren sie noch. – jcady

1

Die Rendern sollte nicht passieren.

Versuchen Sie debug ein wenig mehr. Versuchen Sie, das Änderung Ereignis zu einem Wrappermethode zu binden wie:

initialize: function(){ 
    this.model.bind("change", this.renderWrapper, this); 
}, 

renderWrapper: function(){ 
    console.log("in the renderWrapper"); 
    this.render(); 
} 

sicher zu sein, die zweiten render() für das Änderungsereignis binden gemacht wurde und nicht aus anderen Gründen.

+0

Sie richtig sind. Ich hätte in meiner Frage feststellen sollen, dass ich dies ursprünglich eingeengt habe, indem ich 'console.log ('Change!')' Anstelle von 'this.render()' gesetzt habe. Daher war ich mir sicher, dass das Change-Event ausgelöst wurde. – jcady

Verwandte Themen