Search code examples
backbone.jsunderscore.js-templating

underscore template does NOT compile the model I pass in argument


I am doing internationalisation of an app I built. Basically, on clic of a flag an event is triggered and a callback function will fetch a json file containing the translated labels of the app. Then I set the json data to a model. That just works fine. Finally I compile the template with the model and I render it. But I just get a blank page, no error in the console, just a blank page. I console.log the model and the string that template() returns and they do NOT match.

here a simplified sample (the app is originally built in french *):

var app_multi_lang_model = Backbone.Model.extend({

    MODE_AVANCE : "mode: AVANCE",
    MODE_OPERATEUR: "mode : OPERATEUR",
    MENU: "Menu",
    LANGUE: "langue",
    FRANCAIS: "Français",
    ANGLAIS: "Anglais",
    CHINOIS:"Chinois",
    ANNULER: "annuler",
    VALIDER: "valider"
});

var app_view= Backbone.View.extend({
        el:"#app_template_placeholder" ,
        template: _.template($('#app_template').html()),
        events:{
            "click #us_flag":"us_flag_clicked"
        },

    us_flag_clicked: function(){

        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (xhttp.readyState == 4 && xhttp.status == 200) {
                app_multi_lang_model_instance.set(JSON.parse(xhttp.responseText)); 
                app_view_instance.render();
            }
        };
        xhttp.open("GET", "../languages/english.js", true); //loading the json file
        xhttp.send();

    },

    render: function(){

        console.log(this.model);
        this.$el.html(this.template(this.model));
        console.log(this.template(this.model));
    }
});

var app_multi_lang_model_instance= new app_multi_lang_model();
var app_view_instance= new app_view({model:app_multi_lang_model_instance});

and this is how english.js looks like:

{

    "MODE_AVANCE": "mode: AVANCED",
    "MODE_OPERATEUR": "mode : OPERATOR",
    "MENU": "Menu",
    "LANGUE": "language",
    "FRANCAIS": "French",
    "ANGLAIS": "English",
    "CHINOIS":"Chinese",
    "ANNULER": "cancel"
}

and here are the screen of this.model just before .template(this.model) call:

and here a sample of the string that .template() returns

we see that the model attributes are now translated in english but the html which is supposed to be rendered still in french. what am I doing wrong? why does template() is still returning the template with the former model whereas I passed it the updated one. And why the browser doesn't display the string returned by template()?


Solution

  • Okay I found out what was wrong! the problem is the way I've declared the model.

    var app_multi_lang_model = Backbone.Model.extend({
    
    MODE_AVANCE : "mode: AVANCE",
    MODE_OPERATEUR: "mode : OPERATEUR",
    MENU: "Menu",
    LANGUE: "langue",
    FRANCAIS: "Français",
    ANGLAIS: "Anglais",
    CHINOIS:"Chinois",
    ANNULER: "annuler",
    VALIDER: "valider"
    });
    

    the attributes are not wrapped in "default{...}" so my attributes are not considered as backbone attributes (I cannot access them using model.get). But they exist because I can do "app_multi_lang_model_instance.VALIDER" for example. When I fetch the JSON file and set data to my model using model.set I am not changing my attributes, I'm creating new one wrapped in "defaults:{...}" so my model looks like this:

    var app_multi_lang_model = Backbone.Model.extend({
    defaults:{
       MODE_AVANCE : "mode: AVANCED",
       MODE_OPERATEUR: "mode : OPERATOR",
       MENU: "Menu",
       LANGUE: "language",
       FRANCAIS: "French",
       ANGLAIS: "English",
       CHINOIS:"Chinese",
       ANNULER: "cancel",
       VALIDER: "ok"
    }
    MODE_AVANCE : "mode: AVANCE",
    MODE_OPERATEUR: "mode : OPERATEUR",
    MENU: "Menu",
    LANGUE: "langue",
    FRANCAIS: "Français",
    ANGLAIS: "Anglais",
    CHINOIS:"Chinois",
    ANNULER: "annuler",
    VALIDER: "valider"
    });
    

    So when I pass it to _.template it will populate my html with the attributes it finds first, the unwrapped attributes.

    I fixed that wrapping my attributes in "defaults:{...}" and replace this line:this.$el.html(this.template(this.model)); by this one: this.$el.html(this.template(this.model.toJSON())); otherwise the attributes won't be accessible.

    But still, event if the returned html is now correct the browser doesn't display anything. why?