Steven
Steven

Reputation: 1586

Backbone Marionette / ItemView tag

I want to render a <select> with <option>'s based on a collection using Marionette's ItemView. Because the options need to have actual "values" in order for my App to work, I'm a bit unsure as to how I get Marionette to handle this? If I set a tagName: 'option' in my ItemView, I'm not sure how to add the option after rendering. I thought I could just let the <option value="<%= id %>"> in the template, but that causes a double <option> element to render because I had already specified it in the tagName attribute of my ItemView. What's a best practice for doing this? My template looks like this:

<script type="text/template" id="sport-item-view">
    <option value="<%= id %>"><%= name %></option>
</script>

Upvotes: 3

Views: 3860

Answers (3)

Derick Bailey
Derick Bailey

Reputation: 72858

Are you using a CollectionView as the parent view type to render the collection of models in to the select? If you are, you shouldn't be.

Since the option items need everything in attributes, rendering a template for each option becomes painful as you've already encountered. Instead, use a single ItemView for the entire select box. An ItemView can take a collection in to it, and you can access that collection at items inside of the template. This makes it very trivial to create a select box out of a collection, with a single view:

<script type="text/html" id="select-template">
  <% _.each(items, function(item){ %>
    <option value="<%= item.id %>"><%= item.get("someValue") %></option>
  <% }) %>
</script>

var SelectView = Marionette.ItemView.extend({
  tagName: "select"
});

var s = new SelectView({
  collection: myData
});

s.render();

The downside to this is that you only have 1 view for your select box, which means you have to read the selected value from the select box to figure out which model you are dealing with. But this is only a couple of lines of code, and it saves a ton of headache otherwise.

Upvotes: 7

Vitalii Petrychuk
Vitalii Petrychuk

Reputation: 14225

You can simply use attributes.

You can override constructor in this way:

constructor : function (options) {
  this.attributes = {
    value : options.model.id
  };
  ItemView.prototype.constructor.apply(this, arguments);
}

And your template will be like this:

<%= name %>

http://jsfiddle.net/vpetrychuk/6Bk9T/

Upvotes: 1

dbrin
dbrin

Reputation: 15673

Perhaps it's better to handle this type of view in a more traditional sense by just adding options after render or perhaps on a triggered event. Here is what I did to add options dynamically based on fetched data:

        var mySelect = this.ui.mySelect; // a reference to select from ui hash
        mySelect.html('');  //clear

        //for each data item add an option
        _.each(items, function (item) { 
            mySelect .append($('<option/>', {
                value: item.id,
                text: item.description
            }));
        });

Upvotes: 0

Related Questions