Podsumowanie: dynamiczne ustawianie atrybutów widoku z danymi modelu
http://jsfiddle.net/5wd0ma8b/
var View = Backbone.View.extend( {
attributes : function () {
return {
class : this.model.get( 'item_class' ),
id : this.model.get( 'item_id' )
};
}
} );
var item = new View( {
model : new Backbone.Model( {
item_class : "nice",
item_id : "id1"
} )
} );
Ten przykład zakłada, że pozwalasz Backbone wygenerować dla Ciebie element DOM.
attributes
Metoda jest wywoływana po właściwości przekazany do konstruktora widok są ustawione (w tym przypadku model
), co pozwala na dynamiczne ustawianie atrybutów z danymi modelu przed tworzy Backbone el
.
W przeciwieństwie do niektórych innych odpowiedzi: nie koduje na stałe wartości atrybutów w klasie widoku, ustawia je dynamicznie na podstawie danych modelu; nie czeka aż render()
do ustawienia wartości atr; nie ustawia wielokrotnie wartości atr w każdym wywołaniu do render()
; nie ustawia niepotrzebnie ręcznie wartości atrybutów w elemencie DOM.
Zauważ, że jeśli ustawienie klasę podczas wywoływania Backbone.View.extend
lub konstruktor widok (na przykład new Backbone.View
), trzeba użyć nazwy własność dom, className
ale jeśli ustawienie go za pomocą attributes
skrótu / metody (jak w tym przykładzie) trzeba użyć nazwy atrybutu class
.
Od wersji Backbone 0.9.9:
Podczas deklarowania View ... el
, tagName
, id
i className
może teraz być zdefiniowane jako funkcje, jeśli chcesz ich wartość należy określić w czasie wykonywania.
Wspominam o tym na wypadek sytuacji, w której byłoby to przydatne jako alternatywa dla attributes
metody przedstawionej na ilustracji.
Korzystanie z istniejącego elementu
Jeśli używasz istniejącego elementu (np. Przekazując el
do konstruktora widoku) ...
var item = new View( { el : some_el } );
... wtedy attributes
nie zostanie zastosowany do elementu. Jeśli żądane atrybuty nie są jeszcze ustawione w elemencie lub nie chcesz powielać tych danych w klasie widoku i innej lokalizacji, możesz dodać initialize
metodę do konstruktora widoku, która ma zastosowanie attributes
do el
. Coś takiego (używając jQuery.attr
):
View.prototype.initialize = function ( options ) {
this.$el.attr( _.result( this, 'attributes' ) );
};
Użycie el
, renderowanie, unikanie opakowania
W większości przykładów, które widziałem, el widoku służy jako bezsensowny element opakowania, w którym trzeba ręcznie wpisać kod „semantyczny”.
Nie ma powodu, view.el
aby być „bezsensownym elementem opakowania”. W rzeczywistości często powodowałoby to uszkodzenie struktury DOM. Jeśli <li>
na przykład klasa widoku reprezentuje element, musi być renderowana jako <li>
- renderowanie jej jako elementu <div>
lub dowolnego innego elementu spowodowałoby uszkodzenie modelu zawartości. Będziesz prawdopodobnie chcesz skupić się na prawidłowej konfiguracji elementu widoku danych (za pomocą właściwości jak tagName
, className
i id
), a następnie renderowania jej zawartości później.
Opcje dotyczące interakcji obiektów widoku Backbone z DOM są szeroko otwarte. Istnieją 2 podstawowe scenariusze początkowe:
Możesz dołączyć istniejący element DOM do widoku Backbone.
Możesz zezwolić Backbone na utworzenie nowego elementu, który jest odłączony od dokumentu, a następnie w jakiś sposób wstawić go do dokumentu.
Istnieje wiele sposobów generowania zawartości elementu (ustaw ciąg literału, jak w przykładzie; użyj biblioteki szablonów, takiej jak Mustache, Handlebars itp.). Sposób korzystania z el
właściwości widoku zależy od tego, co robisz.
Istniejący element
Twój przykład renderowania sugeruje, że masz istniejący element, który przypisujesz do widoku, chociaż nie pokazujesz instancji widoków. Jeśli tak jest, a element jest już w dokumencie, możesz chcieć zrobić coś takiego (zaktualizuj zawartość el
, ale nie zmieniaj el
samego siebie):
render : function () {
this.$el.html( "Some stuff" );
}
http://jsfiddle.net/vQMa2/1/
Wygenerowany element
Powiedzmy, że nie masz istniejącego elementu i pozwalasz, aby Backbone wygenerował jeden za Ciebie. Ty może chcesz zrobić coś takiego (ale to może lepiej do rzeczy architektonicznych tak, że widok nie jest odpowiedzialna za wiedząc o samej zewnątrz cokolwiek):
render : function () {
this.$el.html( "Some stuff" );
$( "#some-container" ).append( this.el );
}
http://jsfiddle.net/vQMa2/
Szablony
W moim przypadku korzystam z szablonów np:
<div class="player" id="{{id}}">
<input name="name" value="{{name}}" />
<input name="score" value="{{score}}" />
</div>
<!-- .player -->
Szablon przedstawia cały widok. Innymi słowy, szablon nie będzie otaczał - div.player
będzie to główny lub najbardziej zewnętrzny element mojego widoku.
Moja klasa gracza będzie wyglądać mniej więcej tak (z bardzo uproszczonym przykładem render()
):
Backbone.View.extend( {
tagName : 'div',
className : 'player',
attributes : function () {
return {
id : "player-" + this.model.cid
};
},
render : function {
var rendered_template = $( ... );
this.$el.empty().append( rendered_template.children() );
}
} );
attributes
, na przykład szereg innych właściwości Backbone, które mogą być dostarczone jako funkcja lub inna rodzaj wartości. W takich przypadkach Backbone sprawdza, czy wartość jest funkcją, wywołuje ją i używa wartości zwracanej.Twoim zdaniem po prostu zrób coś takiego
var ItemView = Backbone.View.extend({ tagName: "div", // I know it's the default... render: function() { $(this.el).attr('id', 'id1').addClass('nice').html('Some Stuff'); } });
źródło
Możesz ustawić właściwości
className
iid
element główny: http://documentcloud.github.com/backbone/#View-extendvar ItemView = Backbone.View.extend({ tagName: "div", // I know it's the default... className : 'nice', id : 'id1', render: function() { $(this.el).html("Some stuff"); } });
EDYCJA Dołączony przykład ustawienia id na podstawie parametrów konstruktora
Jeśli widoki są zbudowane jak wspomniano:
var item1 = new ItemModel({item_class: "nice", item_id: "id1"}); var item2 = new ItemModel({item_class: "sad", item_id: "id2"});
Wtedy wartości można ustawić w ten sposób:
// ... className: function(){ return this.options.item_class; }, id: function(){ return this.options.item_id; } // ...
źródło
ItemView
będzie miałid: 'id1'
. Należy to obliczyć w czasie realizacji w oparciu omodel.id
.Wiem, że to stare pytanie, ale dodane w celach informacyjnych. Wydaje się, że jest to łatwiejsze w nowych wersjach szkieletowych. W Backbone 1.1 właściwości id i className są oceniane w funkcji
ensureElement
(patrz źródło ) przy użyciu podkreślenia,_.result
co oznacza, że jeśli funkcja jestclassName
lubid
jest, zostanie wywołana, w przeciwnym razie zostanie użyta jej wartość.Możesz więc podać className bezpośrednio w konstruktorze, podać inny parametr, który byłby użyty w className, itp ... Wiele opcji
więc to powinno działać
var item1 = new ItemModel({item_class: "nice", item_id: "id1"}); var item2 = new ItemModel({item_class: "sad", item_id: "id2"}); var ItemView = Backbone.View.extend({ id: function() { return this.model.get('item_id'); }, className: function() { return this.model.get('item_class'); } });
źródło
id: function() { return this.model.get('item_id'); })
Inne przykłady nie pokazują, jak faktycznie pobrać dane z modelu. Aby dynamicznie dodać identyfikator i klasę z danych modelu:
var ItemView = Backbone.View.extend({ tagName: "div", render: function() { this.id = this.model.get('item_id'); this.class = this.model.get('item_class'); $(this.el).attr('id',this.id).addClass(this.class).html('Some Stuff'); } });
źródło
Musisz usunąć tagName i zadeklarować el.
„tagName” oznacza, że chcesz, aby szkielet utworzył element. Jeśli element już istnieje w DOM, możesz określić el, na przykład:
el: $('#emotions'),
i później:
render: function() { $(this.el).append(this.model.toJSON()); }
źródło
Spróbuj przypisać wartości w metodzie initialize, co spowoduje bezpośrednie dynamiczne przypisanie id i klasy do atrybutu div.
var ItemView = Backbone.View.extend( { tagName : "div", id : '', class : '', initialize : function( options ) { if ( ! _.isUndefined( options ) ) { this.id = options.item_id; this.class= options.item_class; } }, render : function() { $( this.el ).html( this.template( "stuff goes here" ) ); } } );
źródło
Oto minimalny sposób dynamicznej zmiany klasy elementu widoku za pośrednictwem modelu i aktualizowania go przy zmianach modelu.
var VMenuTabItem = Backbone.View.extend({ tagName: 'li', events: { 'click': 'onClick' }, initialize: function(options) { // auto render on change of the class. // Useful if parent view changes this model (e.g. via a collection) this.listenTo(this.model, 'change:active', this.render); }, render: function() { // toggle a class only if the attribute is set. this.$el.toggleClass('active', Boolean(this.model.get('active'))); this.$el.toggleClass('empty', Boolean(this.model.get('empty'))); return this; }, onClicked: function(e) { if (!this.model.get('empty')) { // optional: notify our parents of the click this.model.trigger('tab:click', this.model); // then update the model, which triggers a render. this.model.set({ active: true }); } } });
źródło