简体   繁体   中英

Underscore templating help needed - templating collections

I'm using underscore.js for templating. Here is a sample template.

<script id="discussion-template" type="text/html">
    [[ _.each(discussions, function(topic){ ]]
       <li>
           <article id="{{ topic.htmlId() }}">
               <a class="section-arrow mir" href="#">toggle</a>
               <h3>{{ topic.get('text') }}</h3>
               <ol></ol>
           </article>           
       </li>
    [[ }); ]]
</script>

Inside a backbone.js view.render() I'm passing a collection to the template.

this.el.append(this.template({ discussions: this.collection.models }));

My question here is , do I have to write the looping code? Can I not just pass in a collection and underscore be smart enough to render one item per item in collection? Also does underscore.js provide something for nesting templates? Each item in the collection actually has a collection of items I will need to render as well. How can I call another template from within this template. Any links, tips, and or tutorials are of course greatly appreciated.

Thanks!

I think you do have to write the looping code, but you could clean it up by having the loop in the view rather than the template. So you'd have one template for the container (that holds the <ol> ) and another for rendering <li> s.

For the each item being a collection of items you can use the same technique, with those models appending to the <ol class="topic-collection-will-append-to-this"> in the topic item template.

I didn't test the code below so I'm not 100% it's not bug free, but it should give you idea of a way to tackle it :)

window.TopicView = Backbone.View.extend({
    template: _.template($("#topic-template").html()),
    tag: 'li',
    className: 'topic',

    initialize: function() {
        _.bindAll(this, 'render');
    },

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

window.DiscussionView = Backbone.View.extend({
    tagName: 'section',
    className: 'discussion',
    template: _.template($('#discussion-template').html()),

    initialize: function() {
        _.bindAll(this, 'render');
        this.collection.bind('reset', this.render);
    },

    render: function() {
        var $topics,
        collection = this.collection;

        $(this.el).html(this.template({}));
        $topics = this.$(".topics");
        this.collection.each(function(topic) {
            var view = new TopicView({
                model: topic
            });
            $topics.append(view.render().el);
        });

        return this;
    }
});

<script id="topic-template" type="text/html">
    <article id="{{ topic.htmlId() }}">
        <a class="section-arrow mir" href="#">toggle</a>
        <h3>{{ topic.get('text') }}</h3>
        <ol class="topic-collection-will-append-to-this">
        </ol>
    </article>           
</script>

<script type="text/template" id="discussion-template">
    ...
    <ol class="topics">
    </ol>
</script>

You can have two templates, one for the list and one for the inner elements. And in the list template just print the result of the inner one: http://jsfiddle.net/dira/hRe77/8/

Underscore's templates are very very simple and don't have any smart behaviour/magic attached: http://documentcloud.github.com/underscore/docs/underscore.html#section-120

What you're looking for is a more competent templating system. Underscore's templating is very minimal, without built-in support for looping and such. Maybee Mustache templates is more for you? (Sidenote: it's called logic-less for some strange reason. With both recursion and lambda support I'd say you're at least half-way to Scheme, but I digress..)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM