user846062
user846062

Reputation:

How to most easily render both i18n text AND model attributes (using Handlebars template) in Backbone.Marionette View

Rendering templates is a piece of cake when the data displayed within the template is either internationalized text OR model attributes, but when it comes to rendering BOTH within one template, I can't seem to find a clean solution.

For reference, I'm utilizing i18n via Require.js's i18n plugin.

Let's assume I have a simple template:

<h3>{{displayText.load}} #{{id}}</h3>

<h4 id="loading-load-data">{{displayText.loadingLoadData}}...</h4>

The displayText object represents i18n text, while the id item represents a Backbone Model attribute.

Using Backbone's template property on a View, I can do the following in order to render a template with i18n text, but without Model attribute data:

return Backbone.Marionette.ItemView.extend({
    template: function () {
        var compiledTemplate = Handlebars.compileClean(template);

        // localizedText represents the i18n localization object, using the Require.js i18n plugin
        return compiledTemplate(localizedText);
    },
    // some more View properties and methods
});

However, once I want to also display the Model data, this no longer works, primarily due to this being undefined within the template attribute (so I can't reference this.model.attributes), and it seems that I have to fall back to overriding the render() method, passing both the i18n object AND Model attributes to the template, as such:

return Backbone.Marionette.ItemView.extend({
    template: Handlebars.compileClean(template),
    render: function() {
        var templateParams = _.extend({}, this.model.attributes, localizedText),
            renderedTemplate = this.template(templateParams);

        this.$el.html(renderedTemplate);

        this.bindUIElements();
        this.delegateEvents();

        return this;
    }
});

I'd really love to leave Marionette's default handling of render() in place, and solely use the template property to render both i18n text AND the Model data. Is this possible?

BONUS: Assuming I DO have to override render(), I'm noticing that while doing so, the this.ui attribute, provided on Marionette Views, no longer wraps each item as a jQuery object. This means that:

this.ui.loadingNotification.show();

stops functioning, throwing an Uncaught TypeError: Object #loading-load-data has no method 'show'. Why is this, and how can I restore proper this.ui jQuery-wrapping functionality?

EDIT: Solved the BONUS; simply have to toss in a this.bindUIElements() call within the render() method to properly bind the elements to the ui hash. See the render() example above.

Upvotes: 4

Views: 1351

Answers (1)

user846062
user846062

Reputation:

SOLVED: So the answer is embarrassingly simple. Turns out you can pass a parameter into the template: property when used as a function, and this parameter represents the Model associated with that View/template:

template: function (model) {
    var templateParams = _.extend({}, model, localizedText),
        renderedTemplate = Handlebars.compileClean(template);

    return renderedTemplate(templateParams);
},

The render() method then no longer needs to be overwritten, and both i18n text and Model data can be rendered into the template as expected.

Upvotes: 2

Related Questions