Setting id and className dynamically in Backbone.js views

后端 未结 8 1808
生来不讨喜
生来不讨喜 2021-01-29 19:24

I am in process of learning and using Backbone.js.

I have an Item model and a corresponding Item view. Each model instance has item_class and item_id attributes, that I

相关标签:
8条回答
  • 2021-01-29 19:56

    In your view just do something like this

    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'); 
       }       
    });
    
    0 讨论(0)
  • 2021-01-29 20:08

    Summary: dynamically set view attributes with model data

    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"
      } )
    } );
    
    • This example assumes that you're allowing Backbone to generate a DOM element for you.

    • The attributes method is called after the properties passed to the view constructor are set (in this case, model), allowing you to dynamically set the attributes with the model data before Backbone creates el.

    • In contrast to some of the other answers: doesn't hard-code attribute values in the view class, dynamically sets them from model data; doesn't wait until render() to set attr vals; doesn't repeatedly set attr vals in every call to render(); doesn't unnecessarily manually set attr vals on DOM element.

    • Note that if setting the class when calling Backbone.View.extend or a view constructor (e.g. new Backbone.View), you have to use the DOM property name, className, but if setting it via the attributes hash / method (as in this example) you have to use the attribute name, class.

    • As of Backbone 0.9.9:

      When declaring a View...el, tagName, id and className may now be defined as functions, if you want their values to be determined at runtime.

      I mention this in case there's a situation where that would be useful as an alternative to using an attributes method as illustrated.

    Using an existing element

    If you're using an existing element (e.g. passing el to the view constructor)...

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

    ...then attributes won't be applied to the element. If the desired attributes aren't already set on the element, or you don't want to duplicate that data in your view class and another location, then you may want to add an initialize method to your view constructor that applies attributes to el. Something like this (using jQuery.attr):

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

    Usage of el, rendering, avoiding the wrapper

    In most examples I have seen, the view's el serves as a meaningless wrapper element inside which one has to manually write the 'semantic' code.

    There's no reason view.el needs to be "a meaningless wrapper element". In fact, that would often break the DOM structure. If a view class represents a <li> element for example, it needs to be rendered as an <li> -- rendering it as a <div> or any other element would break the content model. You'll likely want to focus on correctly setting up your view's element (using properties like tagName, className, and id) and then rendering its content thereafter.

    The options for how to have your Backbone view objects interact with the DOM are wide open. There are 2 basic initial scenarios:

    • You can attach an existing DOM element to a Backbone view.

    • You can allow Backbone to create a new element that is disconnected from the document, then somehow insert it into the document.

    There are various ways you can generate the content for the element (set a literal string, as in your example; use a templating library like Mustache, Handlebars, etc.). How you should use the el property of the view depends what you're doing.

    Existing element

    Your rendering example suggests that you have an existing element that you're assigning to the view, although you don't show instantiation of the views. If that's the case, and the element is already in the document, then you may want to do something like this (update the content of el, but don't alter el itself):

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

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

    Generated element

    Let's say you don't have an existing element and you allow Backbone to generate one for you. You may want to do something like this (but it's likely better to architect things so that your view isn't responsible for knowing about anything outside itself):

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

    http://jsfiddle.net/vQMa2/

    Templates

    In my case, I'm using templates, e.g.:

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

    The template represents the complete view. In other words, there will be no wrapper around the template -- div.player will be the root or outermost element of my view.

    My player class will look something like this (with very simplified example of 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() );
      }      
    } );
    
    0 讨论(0)
  • 2021-01-29 20:08

    The other examples are not showing how to actually grab the data from the model. To dynamically add id and class from the model's data:

    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'); 
       }       
    });
    
    0 讨论(0)
  • 2021-01-29 20:09

    You can set the properties className and id on the root element: 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 Included example of setting id based on constructor parameters

    If the views are constructed as mentioned:

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

    Then the values could be set this way:

    // ...
    className: function(){
        return this.options.item_class;
    },
    id: function(){
        return this.options.item_id;
    }
    // ...
    
    0 讨论(0)
  • 2021-01-29 20:09

    Try to assign the values in initialize method this will directly assign id and class to the div attribute dynamically.

    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" ) ); 
        }
    } );
    
    0 讨论(0)
  • 2021-01-29 20:11

    Here's a minimal way to change the class of the view's element dynamically via a model and update it on model changes.

    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 讨论(0)
提交回复
热议问题