Search code examples
backbone.jsunderscore.jsunderscore.js-templating

Underscore template can't access model data


I am trying to render a collection of views from a template, but I can't access my model data in the view template. If I place a <% debugger %> call in the template, I can see the patient variable in local scope as an object, and can also access properties of the model from the console, eg. patients.first_name. But I've tried every permutation I can think of in the template to access model values and can't seem to get the data (ie. <%= patient.first_name %>, <%= patient['first_name'] %> result in "Can't find variable: patient").

Notably, the click handler in the PatientView outputs the correct 'id' property for the individual view, so the model data is clearly getting passed into the view.

        (function () {
        Patient = Backbone.Model.extend({});
        PatientCollection = Backbone.Collection.extend({
            model: Patient
        });

        PatientListView = Backbone.View.extend({
            tagName: "div",

            initialize: function () {
                _.bindAll(this, "renderPatient");
            },

            renderPatient: function (model) {
                console.log(model); //<--object with 'attributes' property containing patient model
                var patientView = new PatientView({model: model});
                patientView.render();
                $(this.el).append(patientView.el);
            },

            render: function () {
                this.collection.each(this.renderPatient);
            }
        });

        PatientView = Backbone.View.extend({
            tagName: "div",
            events: {
                "click button": "clicked"
            },

            clicked: function (e) {
                //e.preventDefault();
                var id = this.model.get("id");
                console.log(id);
            },

            render: function () {
                console.log(this.model.toJSON()); //<--object with all model properties
                var template = _.template($("#patients-item-view").text());
                template({patient: this.model.toJSON()});
                $(this.el).append(template);
            }
        });

        var items = new PatientCollection(patientData.data);

        var view = new PatientListView({collection: items});

        view.render();

        $("#patient-data").html(view.el);
    })();

Template is large, but abbreviated for now and has only one reference to model data:

<script type="text/template" id="patients-item-view">
    <div class="container-fluid patient-data-bar">
        <div class="row">
            <div class="col-md-1">
                <%= patient.first_name %>
            </div>
</script>

When run, patient is showing as undefined/can't find in console. What is going on here?


Solution

  • _.template returns a function that you then use to transform data into an interpolated string. In your render method you feed that function to jQuery.append but it does not have access to the data at that point.

    Try

    render: function () {
        var template = _.template($("#patients-item-view").text());
        var html = template({patient: this.model.toJSON()});
        this.$el.append(html); // views have a cached version of the element 
    }