Resumo: definir atributos de visualização dinamicamente com dados do modelo
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"
} )
} );
Este exemplo assume que você está permitindo que o Backbone gere um elemento DOM para você.
O attributes
método é chamado depois que as propriedades passadas para o construtor de visão são definidas (neste caso, model
), permitindo que você defina dinamicamente os atributos com os dados do modelo antes da criação do Backbone el
.
Em contraste com algumas das outras respostas: não codifica valores de atributo na classe de visualização, os define dinamicamente a partir dos dados do modelo; não espera até render()
definir os atributos; não define atributos repetidamente em cada chamada para render()
; não define manualmente os atributos desnecessários no elemento DOM.
Observe que se definir a classe ao chamar Backbone.View.extend
ou um construtor de visualização (por exemplo new Backbone.View
), você deve usar o nome da propriedade DOM className
, mas se defini-lo por meio do attributes
método hash / (como neste exemplo), você deve usar o nome do atributo class
,.
A partir do Backbone 0.9.9:
Ao declarar a View ... el
, tagName
, id
e className
agora podem ser definidas como funções, se você quiser seus valores a ser determinado em tempo de execução.
Menciono isso no caso de haver uma situação em que isso seja útil como alternativa ao uso de um attributes
método conforme ilustrado.
Usando um elemento existente
Se você estiver usando um elemento existente (por exemplo, passando el
para o construtor de visualização) ...
var item = new View( { el : some_el } );
... então attributes
não será aplicado ao elemento. Se os atributos desejados ainda não estiverem configurados no elemento, ou você não quiser duplicar os dados em sua classe de visão e em outro local, você pode querer adicionar um initialize
método ao seu construtor de visão que se aplique attributes
a el
. Algo assim (usando jQuery.attr
):
View.prototype.initialize = function ( options ) {
this.$el.attr( _.result( this, 'attributes' ) );
};
Uso de el
, renderização, evitando o invólucro
Na maioria dos exemplos que vi, o el do modo de exibição serve como um elemento de invólucro sem sentido dentro do qual é necessário escrever manualmente o código "semântico".
Não há razão view.el
para ser "um elemento de invólucro sem sentido". Na verdade, isso freqüentemente quebrava a estrutura do DOM. Se uma classe de visão representa um <li>
elemento, por exemplo, ela precisa ser renderizada como um<li>
- renderizá-la como um <div>
ou qualquer outro elemento quebraria o modelo de conteúdo. É provável que você deseja focar corretamente configurar elemento do seu ponto de vista (usando propriedades como tagName
, className
, e id
) e depois de proferir a sua conteúdo posteriormente.
As opções de como fazer com que seus objetos de visualização do Backbone interajam com o DOM estão totalmente abertas. Existem 2 cenários iniciais básicos:
Você pode anexar um elemento DOM existente a uma visualização do Backbone.
Você pode permitir que o Backbone crie um novo elemento desconectado do documento e, em seguida, insira-o de alguma forma no documento.
Existem várias maneiras de gerar o conteúdo para o elemento (definir uma string literal, como no seu exemplo; usar uma biblioteca de modelos como Mustache, Handlebars, etc.). Como você deve usar oel
propriedade da visualização depende do que você está fazendo.
Elemento existente
Seu exemplo de renderização sugere que você tem um elemento existente que está atribuindo à visualização, embora você não mostre a instanciação das visualizações. Se for esse o caso, e o elemento já estiver no documento, você pode querer fazer algo assim (atualizar o conteúdo el
, mas não se alterar el
):
render : function () {
this.$el.html( "Some stuff" );
}
http://jsfiddle.net/vQMa2/1/
Elemento gerado
Digamos que você não tenha um elemento existente e permita que o Backbone gere um para você. Você pode querer fazer algo assim (mas provavelmente é melhor arquitetar as coisas para que sua visão não seja responsável por saber nada sobre si mesma):
render : function () {
this.$el.html( "Some stuff" );
$( "#some-container" ).append( this.el );
}
http://jsfiddle.net/vQMa2/
Modelos
No meu caso, estou usando modelos, por exemplo:
<div class="player" id="{{id}}">
<input name="name" value="{{name}}" />
<input name="score" value="{{score}}" />
</div>
<!-- .player -->
O modelo representa a visão completa. Em outras palavras, não haverá wrapper em torno do modelo -div.player
será a raiz ou o elemento mais externo da minha visão.
Minha classe de jogador será parecida com isto (com um exemplo muito simplificado de 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
, como várias outras propriedades do Backbone que podem ser fornecidas como uma função ou alguma outra tipo de valor. Nesses casos, o Backbone verifica se o valor é uma função, a chama e usa o valor de retorno.Na sua opinião, faça algo assim
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'); } });
fonte
Você pode definir as propriedades
className
eid
no elemento raiz: 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"); } });
EDIT Incluir exemplo de configuração de id com base nos parâmetros do construtor
Se as vistas forem construídas conforme mencionado:
var item1 = new ItemModel({item_class: "nice", item_id: "id1"}); var item2 = new ItemModel({item_class: "sad", item_id: "id2"});
Então, os valores podem ser definidos desta forma:
// ... className: function(){ return this.options.item_class; }, id: function(){ return this.options.item_id; } // ...
fonte
ItemView
terãoid: 'id1'
. Isso deve ser calculado em tempo de execução com base nomodel.id
.Eu sei que é uma pergunta antiga, mas adicionada para referência. Isso parece ser mais fácil em novas versões de backbone. No Backbone 1.1 as propriedades id e className são avaliadas na função
ensureElement
(veja da fonte ) usando o_.result
significado de sublinhado seclassName
ouid
for uma função, ela será chamada, caso contrário, seu valor será usado.Então você poderia dar className diretamente no construtor, dar outro parâmetro que seria usado no className, etc ... Muitas opções
então isso deve funcionar
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'); } });
fonte
id: function() { return this.model.get('item_id'); })
Os outros exemplos não mostram como realmente obter os dados do modelo. Para adicionar dinamicamente o id e a classe dos dados do modelo:
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'); } });
fonte
Você precisa remover tagName e declarar um el.
'tagName' significa que você deseja que o backbone crie um elemento. Se o elemento já existe no DOM, você pode especificar um el como:
el: $('#emotions'),
e depois:
render: function() { $(this.el).append(this.model.toJSON()); }
fonte
Tente atribuir os valores no método de inicialização, isso atribuirá diretamente id e classe ao atributo div dinamicamente.
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" ) ); } } );
fonte
Aqui está uma maneira mínima de alterar a classe do elemento da visualização dinamicamente por meio de um modelo e atualizá-lo nas alterações do modelo.
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 }); } } });
fonte