Backbone: A list of views inside a view

2019-02-16 01:39发布

问题:

Let me show what I need first so you can understand my problem. I have a contact view like:

ContactView = Backbone.View.extend({
    template: _.template("Name: <%= name %>
                          E-mail: <%= email %>
                          Phones
                          <%= label1 %> - <%= number1 %>
                          <%= label2 %> - <%= number2 %>"),
    render: function() {
       var contact = this.template(this.model.toJSON());
       this.$el.html(contact);
    }
});

So far so good, the problem is that the phones part is a list, my model holds an array of phones, and I need to put it dynamically in that template.

What I thought was to create another model and view Phone and PhoneView just for this. And then in the ContactView I would create a method render_phones, like:

render_phones: function() {
    var phones = this.model.get('phones');
    var phones_str = "";
    for (var i in phones) {
        var phone = new Phone(phones[i]);
        var phoneView = new PhoneView({model: phone});
        phones_str += phoneView.render();
    }
    return phones_str;
}

I changed the ContactView template to this:

template: _.template("Name: <%= name %>
                      E-mail: <%= email %>
                      Phones
                      <%= phones %>"),

But how to make my render method get the phone list rendered and put inside the template?

I couldn't find a pattern to deal with situations like this. And the code is starting to look not so good.

ps: This is just an example, there are several other parts of my application that I need this, a view that need to generate subviews with content in a list.

回答1:

It looks like you are using underscore.js to render your templates, underscore.js provides a way for rendering a collection within a template (look at the second example). for example

template: _.template("Name: <%= name %>
                          E-mail: <%= email %>
                          Phones
                <% _.each(phones, function (phone) { %>
                 <%= label %> - <%= number %>
                <% }); %>"),

You can also render an individual view for each model and in the same render model modify the el to render it there, but unless you need the view (for example the content will change or you're listening to events) it probably doesn't pay to do it that way. Here's an example of how you could accomplish that

render: function () {
  this.$el.html(this.model.toJSON());
  _.each(this.model.get('phones'), function(phone) {
    this.$el.find('.phoneArea').append(new phoneView({model: phone}).render().el));
  },this);
  return this;
}

Also if you were to go this route then note that it would probably pay to cache the views, but again if all you need is to render the content then it would probably pay to just keep the phone numbers as an array and render it within the template.