web-dev-qa-db-de.com

ID und Klassenname dynamisch in den Backbone.js-Ansichten festlegen

Ich lerne und verwende Backbone.js.

Ich habe ein Item-Modell und eine entsprechende Item-Ansicht. Jede Modellinstanz verfügt über die Attribute item_class und item_id, die ich als die 'id' - und 'class'-Attribute der entsprechenden Ansicht widerspiegeln möchte der richtige Weg, um dies zu erreichen? 

Beispiel:

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

Wie soll ich die Ansicht implementieren, damit die Ansichten der Ansichten übersetzt werden in:

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

In den meisten Beispielen habe ich die Ansicht gesehen el dient als bedeutungsloses Wrapper-Element, in das der "semantische" Code manuell geschrieben werden muss.

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

Wenn also gerendert wird, bekommt man 

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

Aber das scheint eine Verschwendung zu sein - warum haben wir das externe Div? Ich will das el um direkt in das interne div zu übersetzen!

84
Nadav

Zusammenfassung: Dynamisch gesetzte Ansichtsattribute mit Modelldaten

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"
  } )
} );
  • In diesem Beispiel wird davon ausgegangen, dass Sie Backbone erlauben, ein DOM-Element für Sie zu generieren.

  • Die attributes-Methode wird aufgerufen, nachdem die an den Ansichtskonstruktor übergebenen Eigenschaften festgelegt wurden (in diesem Fall model), sodass Sie die Attribute dynamisch mit den Modelldaten festlegen können, bevor Backbone el erstellt.

  • Im Gegensatz zu einigen anderen Antworten: Attributwerte in der Ansichtsklasse nicht hartcodieren, dynamisch aus Modelldaten setzen; Wartet nicht bis render(), um die Werte einzustellen. setzt bei jedem Aufruf nicht wiederholt attr vals auf render(); attr vals für das DOM-Element nicht unnötig manuell festgelegt.

  • Beachten Sie, dass Sie beim Festlegen der Klasse beim Aufruf von Backbone.View.extend oder eines Ansichtskonstruktors (z. B. new Backbone.View) den DOM-Eigenschaftennamen className verwenden müssen. Wenn Sie die Klasse jedoch über die attributes-Methode (wie in diesem Beispiel) festlegen, müssen Sie die Attributname, class.

  • Stand Backbone 0.9.9:

    Bei der Deklaration einer View ...el können nun tagName, id und className als Funktionen definiert werden, wenn ihre Werte zur Laufzeit bestimmt werden sollen.

    Ich erwähne dies für den Fall, dass es eine Situation gibt, in der dies als Alternative zur Verwendung einer attributes-Methode (siehe Abbildung) nützlich ist.

Vorhandenes Element verwenden

Wenn Sie ein vorhandenes Element verwenden (z. B. el an den Ansichtskonstruktor übergeben) ...

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

... dann wird attributes nicht auf das Element angewendet. Wenn die gewünschten Attribute für das Element nicht bereits festgelegt sind oder Sie diese Daten in Ihrer Ansichtsklasse und an einem anderen Speicherort nicht duplizieren möchten, möchten Sie möglicherweise Ihrem initialize-Verfahren Ihren View-Konstruktor hinzufügen, der attributes auf el anwendet. So etwas (mit jQuery.attr):

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

Verwendung von el, Rendern, Vermeidung des Wrappers

In den meisten Beispielen, die ich gesehen habe, dient das el der Ansicht als bedeutungsloses Wrapper-Element, in das der "semantische" Code manuell geschrieben werden muss.

Es gibt keinen Grund, dass view.el "ein bedeutungsloses Wrapper-Element" sein muss. In der Tat würde das oft die DOM-Struktur zerstören. Wenn eine Ansichtsklasse beispielsweise ein <li>-Element darstellt, muss es als <li> dargestellt werden - das Rendern als <div> oder ein anderes Element würde das Inhaltsmodell beschädigen. Wahrscheinlich möchten Sie sich darauf konzentrieren, das Element Ihrer Ansicht richtig einzurichten (mit Eigenschaften wie tagName, className und id) und anschließend content zu rendern.

Die Optionen für die Interaktion Ihrer Backbone-Ansichtsobjekte mit dem DOM sind weit offen. Es gibt zwei grundlegende Ausgangsszenarien:

  • Sie können ein vorhandenes DOM-Element an eine Backbone-Ansicht anhängen.

  • Sie können zulassen, dass Backbone ein neues Element erstellt, das vom Dokument getrennt wird, und es dann irgendwie in das Dokument einfügt.

Es gibt verschiedene Möglichkeiten, den Inhalt für das Element zu generieren (setzen Sie einen Literal-String wie in Ihrem Beispiel; verwenden Sie eine Vorlagenbibliothek wie Mustache, Handlebars usw.). Wie Sie die el-Eigenschaft der Ansicht verwenden, hängt davon ab, was Sie tun.

Bestehendes Element

In Ihrem Rendering-Beispiel wird vorgeschlagen, dass Sie über ein vorhandenes Element verfügen, das Sie der Ansicht zuweisen, obwohl Sie keine Instantiierung der Ansichten anzeigen. Wenn dies der Fall ist und das Element bereits im Dokument enthalten ist, möchten Sie möglicherweise Folgendes tun (Aktualisieren Sie den Inhalt von el, ändern Sie jedoch nicht el selbst):

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

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

Erzeugtes Element

Nehmen wir an, Sie haben kein vorhandenes Element und erlauben Backbone, eines für Sie zu generieren. Sie mai möchten so etwas tun (aber es ist wahrscheinlich besser, die Dinge so zu gestalten, dass Ihre Sicht nicht dafür verantwortlich ist, etwas außerhalb von sich selbst zu wissen):

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

http://jsfiddle.net/vQMa2/

Vorlagen

In meinem Fall verwende ich Vorlagen, z.

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

Die Vorlage repräsentiert die vollständige Ansicht. Mit anderen Worten, es wird kein Wrapper um die Vorlage gelegt - div.player ist das Stammelement oder das äußerste Element meiner Ansicht.

Meine Spielerklasse sieht ungefähr so ​​aus (mit einem sehr vereinfachten Beispiel von 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() );
  }      
} );
132
JMM

Machen Sie aus Ihrer Sicht einfach so etwas

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

Sie können die Eigenschaften className und id im Stammelement festlegen: 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");
   }       
});

EDIT Enthaltenes Beispiel zum Festlegen einer auf Konstruktorparametern basierenden ID

Wenn die Ansichten wie angegeben aufgebaut sind:

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

Dann könnten die Werte so eingestellt werden:

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

Ich weiß, es ist eine alte Frage, aber als Referenz hinzugefügt. Dies scheint in neuen Backbone-Versionen einfacher zu sein. In Backbone 1.1 werden die Eigenschaften id und className in der Funktion ensureElement (siehe from source ) mit Unterstrich _.result ausgewertet. Wenn className oder id eine Funktion ist, wird diese aufgerufen.

Sie können also className direkt im Konstruktor angeben, einen anderen Parameter angeben, der in className verwendet wird, usw. ... Viele Optionen

also sollte das funktionieren

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

Die anderen Beispiele zeigen nicht, wie die Daten tatsächlich aus dem Modell übernommen werden. So fügen Sie ID und Klasse dynamisch aus den Daten des Modells hinzu:

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

Sie müssen tagName entfernen und ein el deklarieren.

'tagName' bedeutet, dass das Backbone ein Element erstellen soll. Wenn das Element bereits im DOM vorhanden ist, können Sie ein el wie folgt angeben:

el: $('#emotions'),

und später:

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

Versuchen Sie, die Werte in der initialize-Methode zuzuweisen. Dadurch werden id und class dynamisch dem div-Attribut zugewiesen.

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

Hier ist eine minimale Möglichkeit, die Klasse des Elements der Ansicht über ein Modell dynamisch zu ändern und bei Modelländerungen zu aktualisieren. 

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 });
        }
    }
});
0
Emile Bergeron