Backbone.js görünümlerinde id ve className'i dinamik olarak ayarlama


85

Backbone.js öğrenme ve kullanma sürecindeyim.

Bir Öğe modelim ve karşılık gelen bir Öğe görünümüm var. Her model örneğinin, ilgili görünümün "id" ve "class" öznitelikleri olarak yansıtılmasını istediğim item_class ve item_id öznitelikleri vardır. Bunu başarmanın doğru yolu nedir?

Misal:

var ItemModel = Backbone.Model.extend({      
});

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({       
});

Görünümü nasıl uygulamalıyım ki görünümler şu şekle çevrilsin:

<div id="id1" class="nice"></div>
<div id="id2" class="sad"> </div>

Gördüğüm en örneklerde, görünümün El biri elle 'semantik' kod yazmak zorunda anlamsız bir sarıcı eleman iç olarak hizmet vermektedir.

var ItemView = Backbone.View.extend({
   tagName:  "div",   // I know it's the default...

   render: function() {
     $(this.el).html("<div id="id1" class="nice"> Some stuff </div>");
   }       
});

Böylece işlendiğinde,

<div> <!-- el wrapper -->
    <div id="id1" class="nice"> Some stuff </div>
</div>

Ama bu bir israf gibi görünüyor - neden harici div var? E'nin doğrudan dahili div'e çevirmesini istiyorum !

Yanıtlar:


133

Özet: Model verileriyle dinamik olarak görünüm niteliklerini ayarlama

http://jsfiddle.net/5wd0ma8b/

// View class with `attributes` method
var View = Backbone.View.extend( {
  attributes : function () {
    // Return model data
    return {
      class : this.model.get( 'item_class' ),
      id : this.model.get( 'item_id' )
    };
  }
  // attributes
} );

// Pass model to view constructor
var item = new View( {
  model : new Backbone.Model( {
    item_class : "nice",
    item_id : "id1"
  } )
} );
  • Bu örnek, Backbone'un sizin için bir DOM öğesi oluşturmasına izin verdiğinizi varsayar.

  • attributesGörünüm yapıcı geçirilen özellikler ayarlandıktan sonra yöntemi denir (bu durumda, modelBackbone oluşturmadan önce), dinamik modeli verilerle özelliklerini ayarlamak için izin gününde el.

  • Diğer yanıtlardan bazılarının aksine: görünüm sınıfındaki öznitelik değerlerini sabit kodlamaz, bunları model verilerinden dinamik olarak ayarlar; render()attr değerlerinin ayarlanmasını beklemez defalarca her çağrıda vals attr belirlemez render(); DOM öğesinde gereksiz yere öznitelikleri manuel olarak ayarlamaz.

  • Sınıfı çağırırken Backbone.View.extendveya bir görünüm oluşturucu (örn. new Backbone.View) Ayarlıyorsanız, DOM özellik adını kullanmanız gerektiğini className, ancak bunu attributeskarma / yöntemle ayarlıyorsanız (bu örnekte olduğu gibi) özellik adını kullanmanız gerektiğini unutmayın class.

  • Backbone 0.9.9'dan itibaren:

    Görünüm ilan zaman ... el, tagName, idve classNameonların değerleri zamanında belirlenecek istiyorsanız şimdi, fonksiyonlar olarak tanımlanabilir.

    attributesResimde gösterildiği gibi bir yöntemi kullanmaya alternatif olarak yararlı olacağı bir durum olması durumunda bundan bahsediyorum .

Mevcut bir öğeyi kullanma

Mevcut bir öğe kullanıyorsanız (örneğin el, görünüm oluşturucusuna geçiş) ...

var item = new View( { el : some_el } );

... daha sonra attributesöğeye uygulanmaz. İstenen öznitelikler öğe üzerinde önceden ayarlanmamışsa veya bu verileri görünüm sınıfınızda ve başka bir konumda çoğaltmak istemiyorsanız initialize, görünüm oluşturucunuza geçerli attributesolan bir yöntem eklemek isteyebilirsiniz el. Bunun gibi bir şey (kullanarak jQuery.attr):

View.prototype.initialize = function ( options ) {
  this.$el.attr( _.result( this, 'attributes' ) );
};

Kullanım eloluşturma, sarıcı kaçınarak

Gördüğüm çoğu örnekte, görünümün "anlamı" kodun elle yazılması gereken anlamsız bir sarmalayıcı öğe olarak hizmet ediyor.

view.el"Anlamsız bir sarmalayıcı öğesi" olmaya gerek yok . Aslında, bu genellikle DOM yapısını bozar. Örneğin bir görünüm sınıfı bir <li>öğeyi temsil ediyorsa , bir <li>- olarak oluşturulması gerekir <div>veya başka bir öğe olarak oluşturulması içerik modelini bozabilir. Büyük olasılıkla doğru görünümün eleman kurma (gibi özelliklerini kullanarak odaklanmak isteyeceksiniz tagName, classNameve id) ve daha sonra onun render içeriği bundan sonra.

Omurga görünümü nesnelerinizin DOM ile nasıl etkileşime gireceğine ilişkin seçenekler tamamen açıktır. 2 temel ilk senaryo vardır:

  • Mevcut bir DOM öğesini Backbone görünümüne ekleyebilirsiniz.

  • Backbone'un belgeden bağlantısı kesilen yeni bir öğe oluşturmasına izin verebilir, ardından bunu bir şekilde belgeye ekleyebilirsiniz.

Öğe için içerik oluşturmanın çeşitli yolları vardır (örneğinizde olduğu gibi bir değişmez dize ayarlayın; Bıyık, Gidon vb. Gibi bir şablon oluşturma kitaplığı kullanın). elGörünümün özelliğini nasıl kullanmanız gerektiği, ne yaptığınıza bağlıdır.

Mevcut öğe

İşleme örneğiniz, görünümlerin somut örneğini göstermeseniz de, görünüme atadığınız mevcut bir öğeye sahip olduğunuzu gösteriyor. Durum buysa ve öğe zaten belgenin içindeyse, bunun gibi bir şey yapmak isteyebilirsiniz (içeriğini güncelleyin el, ancak elkendisini değiştirmeyin ):

render : function () {
  this.$el.html( "Some stuff" );
}

http://jsfiddle.net/vQMa2/1/

Oluşturulan öğe

Diyelim ki mevcut bir elementiniz yok ve Backbone'un sizin için bir tane oluşturmasına izin veriyorsunuz. Sen olabilir böyle bir şey yapmak istiyorum (ama senin bakış şey dışarıdan kendisi hakkında bilerek sorumlu tutulamaz böylece mimar şeyler muhtemelen iyidir):

render : function () {
  this.$el.html( "Some stuff" );
  $( "#some-container" ).append( this.el );
}

http://jsfiddle.net/vQMa2/

Şablonlar

Benim durumumda, şablon kullanıyorum, örneğin:

<div class="player" id="{{id}}">
<input name="name" value="{{name}}" />
<input name="score" value="{{score}}" />
</div>
<!-- .player -->

Şablon tam görünümü temsil eder. Diğer bir deyişle, şablonun etrafında bir sarmalayıcı div.playerolmayacak - benim görüşümün kökü veya en dıştaki öğesi olacak.

Oyuncu sınıfım şöyle görünecek (çok basitleştirilmiş bir örnekle render()):

Backbone.View.extend( {
  tagName : 'div',
  className : 'player',

  attributes : function () {
    return {
      id : "player-" + this.model.cid
    };
  },
  // attributes

  render : function {
    var rendered_template = $( ... );

    // Note that since the top level element in my template (and therefore
    // in `rendered_template`) represents the same element as `this.el`, I'm
    // extracting the content of `rendered_template`'s top level element and
    // replacing the content of `this.el` with that.
    this.$el.empty().append( rendered_template.children() );
  }      
} );

Bir işlevle attributes özelliğinin üzerine yazmanın ve bir nesneyi yeniden döndürmenin harika bir yolu!
Kel

2
@Kel evet, bu, görünümlerin somutlaştırıldığı tekrarlayan kodlar kullanmak zorunda kalmadan, sorunun istediği gibi dinamik bir şeyi başarmanın, öznitelikleri model verileriyle doldurmanın iyi bir yoludur. Muhtemelen bunu biliyorsunuzdur, ancak açık olmaması durumunda attributes, bir işlev veya başka bir işlev olarak sağlanabilen diğer birçok Omurga özelliği gibi, değeri olarak bir karma döndüren bir işlev kullanabileceğiniz bir Omurga özelliğidir. değer türü. Bu durumlarda Backbone, değerin bir işlev olup olmadığını kontrol eder, onu çağırır ve dönüş değerini kullanır.
JMM

95

Sana göre böyle bir şey yap

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'); 
   }       
});

Bu sorunun doğru cevabı bu ve kabul edilmelidir
reach4thelasers

13
Bu cevap, model verilerine dayalı olarak görünüm özniteliklerini dinamik olarak ayarlamayı göstermez, yalnızca öznitelik değerlerini sabit kodlamanın alternatif bir yöntemini gösterir.
JMM

3
@JMM - Örnek kodu model verilerini de kullanmıyor. Bu cevap, örnek koduna göre çalışır. Açıkçası, model verileri değerler yerine kullanılabilir.
Clint

5
@Clint, bunun OP için bariz olduğuna güvenmem. "Onun örnek kodu da model verilerini kullanmıyor." - çünkü nasıl yapılacağını bilmiyor ve bu yüzden neden yardım istedi. Bana öyle görünüyor ki, model verilerini kullanarak view.el çekimlerinin nasıl ayarlanacağını soruyor ve bunun nasıl yapılacağı hakkında hiçbir fikri yok. Cevap bunun nasıl yapılacağını bile göstermiyor ve neden yine de yapmak için render edene kadar bekleyesiniz veya her render ettiğinizde tekrar yaparsınız? "Bu cevap işe yarıyor ..." - nasıl çalışıyor? Bu şekilde yaratılan her görünüm aynı özelliklere sahip olacaktır. Gösterdiği tek şey, paketleyiciden nasıl kaçınılacağıdır.
JMM

OP, 12 Şubat'tan beri yok. :( Bu yanıt için bir +1 daha var.
Almo

27

Özellikleri classNameve idkök öğede ayarlayabilirsiniz : http://documentcloud.github.com/backbone/#View-extend

var ItemView = Backbone.View.extend({
   tagName:  "div",   // I know it's the default...
   className : 'nice',
   id : 'id1',
   render: function() {
     $(this.el).html("Some stuff");
   }       
});

DÜZENLE Yapıcı parametrelerine dayalı olarak kimlik ayarlama örneği dahildir

Görünümler belirtildiği gibi oluşturulmuşsa:

var item1 = new ItemModel({item_class: "nice", item_id: "id1"});
var item2 = new ItemModel({item_class: "sad", item_id: "id2"});

Daha sonra değerler şu şekilde ayarlanabilir:

// ...
className: function(){
    return this.options.item_class;
},
id: function(){
    return this.options.item_id;
}
// ...

3
Bu cevabı doğru hissetmiyorum çünkü o zaman herkesin ItemViewalacağı id: 'id1'. Bu hesaplanmalıdır yürütme zamanında dayanır model.id.
fguillen

Elbette kimliği istediğiniz gibi ayarlayabilirsiniz. Bir işlev, değişken veya herhangi bir şey kullanın. Kodum, kök öğede değerin nasıl ayarlanacağına işaret eden bir örnek içeriyor.
Jørgen

Yapıcı parametrelerine göre değerlerin nasıl dinamik olarak ayarlanacağını açıklayan bir örnek ekledim.
Jürgen

Bu doğru cevap. Problemi çözmek için Backbone özelliklerini doğru kullanır.
Marc-Antoine Lemieux

6

Bunun eski bir soru olduğunu biliyorum, ancak referans olarak eklendi. Yeni omurga sürümlerinde bu daha kolay görünüyor. Backbone 1.1'de id ve className özellikleri, fonksiyonda alt çizgi kullanılarak değerlendirilir ensureElement( kaynağa bakın ), _.resulteğer bir fonksiyonsa classNameveya idbir fonksiyonsa, çağrılır, aksi takdirde değeri kullanılır.

Böylece, doğrudan yapıcıda className verebilir, className'de kullanılacak başka bir parametre verebilirsiniz, vb ... Pek çok seçenek

yani bu çalışmalı

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'); }
});

id: function() { return this.model.get('item_id'); })
Örneğiniz

4

Diğer örnekler, verilerin modelden nasıl alınacağını göstermiyor. Modelin verilerinden dinamik olarak id ve sınıf eklemek için:

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'); 
   }       
});

Bu "this.className" veya "this.class" mı?
Gabe Rainbow

2

TagName'i kaldırmanız ve bir el belirtmeniz gerekir.

'tagName', omurganın bir eleman yaratmasını istediğinizi belirtir. Öğe DOM'da zaten mevcutsa, başka bir şey belirtebilirsiniz:

el: $('#emotions'),

ve sonra:

render: function() { 
     $(this.el).append(this.model.toJSON());
}

2

Başlatma yönteminde değerleri atamayı deneyin, bu dinamik olarak div niteliğine doğrudan id ve sınıfı atayacaktır.

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" ) ); 
    }
} );

@Michel pleasae, bu belgelerin katlanmak backbonejs.org/#View-constructor
Hemanth

0

Görünüm öğesinin sınıfını bir model aracılığıyla dinamik olarak değiştirmenin ve model değişikliklerinde güncellemenin minimal bir yolu.

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 });
        }
    }
});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.