Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternating between 2 different templates in backbone.js

I have 2 different templates for my model's views. Each time the models are fetched from the database, the first 3 models (#1, 2, 3) fetched from the backend will have the view created using the first template, the next 4 models (#4, 5, 6, 7) will use the second template, the next 3 models (#8, 9, 10) will use the first template and so on.

Problem: How will I introduce this alternating template using backbone.js?

JS Code

// Views

PhotoListView = Backbone.View.extend({
    el: '#photo_list',

    render: function() {
        $(this.el).html('');
        _.each(this.model.models, function(photo) {
            $(this.el).append(new PhotoListItemView({ model: photo }).render().el);
        }, this);
        return this;
    }
});

PhotoListItemView = Backbone.View.extend({
    tagNAme: 'div',
    className: 'photo_box',

    template: _.template( $('#tpl_PhotoListView').html() ),

    initialize: function() {
        this.model.bind('destroy', this.close, this);
    },

    render: function() {
        $(this.el).html( this.template( this.model.toJSON() ) );
        return this;
    },

    close: function() {
        this.unbind();
        this.remove();
    }
});
like image 830
Nyxynyx Avatar asked Jul 04 '12 20:07

Nyxynyx


1 Answers

First of all, your PhotoListView is wrapping a collection so you should be using this.collection inside the view and new PhotoListView({ collection: c }) to create it. Views treat the collection option similarly to how they treat model:

constructor / initialize new View([options])

[...] There are several special options that, if passed, will be attached directly to the view: model, collection, el, id, className, tagName and attributes.

Using the right names will help prevent confusion. Also, views have some Underscore methods already mixed in so you can say this.collection.each(...) instead of _.each(this.collection.models, ...) or _(this.collection.models).each(...). You can also use this.$el instead of $(this.el).

And now on to your real problem. You can add two templates to your per-model view:

PhotoListItemView = Backbone.View.extend({
    template0: _.template($('#the-first-template-id').html()),
    template1: _.template($('#the-other-template-id').html()),
    //...
});

and an option to tell it which one to use:

initialize: function(options) {
    this.template = this['template' + options.template_number];
    //...
}

Then you just need to specify the group option from the collection view. Underscore's each passes the iteration index to the callback function as the second argument so you just need a bit of integer math to figure out which template_number to use:

this.collection.each(function(photo, i) {
    // Grouped in threes and you're alternating between two templates.
    var n = Math.floor(i / 3) % 2; 
    var v = new PhotoListItemView({ model: photo, template_number: n });
    this.$el.append(v.render().el);
}, this);
like image 61
mu is too short Avatar answered Sep 28 '22 12:09

mu is too short