Search code examples
javascriptbackbone.jsunderscore.js

Not sure how to template object of arrays using Backbone and Underscore templates


I have a collection where the data is returned looking like:

{
  "departments": ["Customer Support", "Marketing"],
  "classes": ["Planning", "Drawing"]
}

I'm not overly sure how to use underscore template loops to output each of the departments, right now I'm using ._each but my output is object Object. Can anyone advise how to resolve this?

Fiddle: http://jsfiddle.net/kyllle/aatc70Lo/7/

Template

<script type="text/template" class="js-department">
    <select>
        <% _.each(departments, function(department) { %>
            <option value="<% department %>"><% department %></option>
        <% }) %>
    </select>
</script>

JS

var Department = Backbone.Model.extend();

var Departments = Backbone.Collection.extend({
    model: Department,
    parse: function(response) {
        return response;
    }
});

var DepartmentView = Backbone.View.extend({
    template: '.js-department',

    initialize: function() {
        console.log('DepartmentView::initialize', this.collection.toJSON());
    },

    render: function() {
        this.$el.html( this.template( this.collection.toJSON() ) );
    }
});

var departments = new Departments({
  "departments": ["Customer Support", "Marketing"]
}, {parse:true});

var departmentView = new DepartmentView({
    collection: departments
});

document.body.innerHTML = departmentView;

Solution

    1. You are not even calling render(), so your template is never even executed, and the object Object output has nothing to do to your template.
    2. After you run render() you will realize
      template: '.js-department'
      doesn't work, because it is not Marionette, and Backbone will not compile the html by a selector for you. So you will replace it with something like this:
      template: _.template($('.js-department').html())
    3. Then you will have to realize this.collection is an array, that only has one item, so if you just want to render that first item, you will send to it to template:
      this.$el.html( this.template( this.collection.first().toJSON() ) );
    4. Then you will have to realize departmentView is a Backbone.View instance object, and isn't html itself. It has the el property which is the DOM element of this view instance, and $el property, which is the same DOM element wrapped with jQuery.
    5. document.body.innerHTML = departmentView.el still will not work, because innerHTML expects a string. So you could instead do something like
      document.body.appendChild( departmentView.el ); or
      departmentView.$el.appendTo( document.body ); with jquery.
      (For the last one to work render must return this)

    Working jsfiddle: http://jsfiddle.net/yuraji/zuv01arh/