Backbone.js | Wie kann ich später Elemente einer Aussicht zum Abrufen speichern?
-
13-10-2019 - |
Frage
Dies ist mein erster Versuch, Backbone.js zu verwenden. Daher habe ich mich für eine einfache Testanwendung entschieden, die ein Restaurantmenü mit Menüpunkten simuliert. Ich folgte mit Dieser coole Blog -Beitrag von Andyet.net.
Ich habe ein Problem, wenn ich ein Modell zu einer Sammlung hinzufüge. Ich habe eine Ansichtsmethode an das Add -Ereignis der Sammlung gebunden, mit dem die Ansicht aktualisiert werden sollte. Hier ist der Code mit so viel irrelevantem Code wie möglich.
(Hinweis: Ich habe Dinge wie den lokalen Bereich entfernt var
Erklärungen und Schließungen aus Kürze. Das Folgende ist noch ein wenig lang, und ich weiß, dass das ärgerlich ist, aber es sollte ziemlich einfach und leicht zu verstehen sein):
MenuItem = Backbone.Model.extend({
// initialize functions removed for brevity
});
Menu = Backbone.Model.extend({
// initialize functions removed for brevity
// MenuSelection property is defined here.
});
MenuSelection = Backbone.Collection.extend({ model: MenuItem });
MenuItemView = Backbone.View.extend({
// render template
});
/**
* This is unaltered from the code. The error occurs here.
*/
RestaurantAppView = Backbone.View.extend({
addMenuItem : function (MenuItem) {
var view = new MenuItemView({ model : MenuItem });
this.menuList.append(view.render().el);
// ERROR occurs here. error: "this.menuList is undefined"
},
initialize : function () {
this.model.MenuSelection.bind('add', this.addMenuItem);
},
render : function () {
$(this.el).html(ich.app(this.model.toJSON()));
this.menuList = this.$('#menuList'); // IT IS DEFINED HERE
return this;
}
});
/**
* Everything after this I left in just-in-case you need to see it.
*/
RestaurantAppController = {
init : function (spec) {
this.config = { connect : true };
_.extend(this.config, spec);
this.model = new Menu({
name : this.config.name,
});
this.view = new RestaurantAppView({ model : this.model });
return this;
}
};
$(function() {
// simulating ajax JSON response.
var json = {
Menu : {
name : 'Appetizers',
MenuItem : [
{
name : 'toast',
description : 'very taosty',
price : '$20.00'
},
{
name : 'jam',
description : 'very jammy',
price : '$10.00'
},
{
name : 'butter',
description : 'very buttery',
price : '$26.00'
}
]
}
};
window.app = RestaurantAppController.init({
name : json.Menu.name
});
$('body').append(app.view.render().el);
app.model.MenuSelection.add(json.Menu.MenuItem);
});
Ich habe mit Kommentaren den problematischen Bereich markiert. Nach dem Backbone -Dokumentation:
Wenn JQuery oder Zepto auf der Seite enthalten ist, verfügt jede Ansicht über eine $ -Funktion, in der Abfragen ausgelegt werden, die im Element der Ansicht verteilt sind.
Also, wenn ich setze this.menuList = this.$('#menuList');
Warum kann ich in der Render -Methode nicht zugreifen? this.menuList
in dem addMenuItem
Methode? Die Demo, mit der ich oben verlinkt habe, macht sie so vergrößert. Auch wenn ich auszehne this.menuList
Für einen JQuery -Selektor wie SO:
addMenuItem : function (MenuItem) {
var view = new MenuItemView({ model : MenuItem });
$('#menuList').append(view.render().el);
}
Alles funktioniert gut. Aber ich nicht wollen Jedes Mal die Menuist-ID neu auszuwählen addMenuItem
wird ausgeführt. Der richtige WegTm ist es nach dem Rendern zu rendern.
Hinweis auch: Ich dachte, vielleicht war das Problem bei der Icanhaz -Vorlage, die nicht schnell genug zurückkehrt, aber dann this.menuList
wäre ein leeres Array, nicht undefined
, Das ist es nicht.
Lösung
Sie rennen mit JavaScript in die Nr. 1 Gotcha - die dynamisch abgeschöpften this
Stichwort. Wenn Sie abziehen this.addMenuItem
Als Referenz ohne Bindung, die, die addMenuItem
Funktion verliert ihren Begriff von this
. Es gibt zwei einfache Möglichkeiten, es in Ihrem Code zu beheben, entweder diese Zeile ersetzen:
this.model.MenuSelection.bind('add', this.addMenuItem);
Mit diesem:
this.model.MenuSelection.bind('add', _.bind(this.addMenuItem, this));
Oder fügen Sie diese Zeile an die Spitze Ihrer Initialisierungsfunktion hinzu, die effektiv dasselbe erreicht:
_.bindAll(this, 'addMenuItem');
Andere Tipps
Wahrscheinlich wird die AddMenuitem -Methode aufgerufen, bevor die Render -Methode aufgerufen wird, und daher fehlt die Definition für die Menulistin im AddMenuitem.
Warum drückst du nicht? this.menulist = this. $ ('#Menulist'); zu initialisieren Methode und versuchen?