SebVb SebVb - 1 month ago 10
Javascript Question

Backbone.js : subview isn't rendered

I have to work with Backbone.js and i'm experimenting an issue on the rendering of a subview

Here's a quick description of my behavior. I've got packages which contains services. I've got a view for :


  • The package list

  • A specific package

  • The inner service list of a package

  • A specific service



Packages and services are stored in collection

Here's my package view :

Backbone.View.extend({
initialize : function() {

this.mainView = this.options.mainView;
this.innerEl = '#' + this.model.attributes.packCode + '-includedServices';
// rendering includedServices using service view
this.servicesView = new PackServicesView({
el : $(this.innerEl),
mainView : this.mainView,
collection : this.model.attributes.includedServices,
packCode : this.model.attributes.packCode
});

// Compile template
this.template = _.template(tmpl);

/*--- binding ---*/
_.bindAll(this, 'render');

this.model.bind('change', this.render);

/*---------------*/
this.render();
}, // initialize

events : {
'click input[type=checkbox]' : 'onCheck'
},
onCheck : function(event) {
this.model.toggleSelected();
this.mainView.setLastClickedPack(this.model);
},
render : function() {
this.$el.html(this.template(this.model.toJSON()));

this.$el.append(this.servicesView.render().el);

return this.$el;
}
});


My PackServicesView :

Backbone.View.extend({
//el: 'myIncludedServices',
initialize: function() {
this.mainView = this.options.mainView;
this.collection.bind('reset', this.render, this);
this.collection.bind('add', this.addPackService, this);
},
render: function() {
this.$el.empty();
this.collection.each(this.addPackService, this);
return this.$el;
},
addPackService: function(item) {
this.$el.append(new PackServiceView({
model: item,
mainView: this.mainView
}).render());
}

});


And my PackServiceView :

Backbone.View.extend({
initialize: function() {

this.mainView = this.options.mainView;
//Compile template
this.template = _.template(tmpl);
//Création des sous vue
this.model.set({
defaultChoice: this.model.attributes.default
});
/*--- binding ---*/
_.bindAll(this, 'render');
this.model.bind('change', this.render);
/*---------------*/
this.render();
}, //initialize
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this.$el;
},
events: {
'click input[type=checkbox]': 'clickEvent'
},
clickEvent: function(event) {
this.model.toggleSelected();
}
});


When debugging with Firefox, i saw that the render function of PackServiceview is rendring fine its template.

I've got a div in my package template with the id set to "<%=packCode%>-includedServices" in order to bind it in the DOM, but from what I've read in different topics, I assume that my issue comes from a DOM attachment issue.. As I have more than one PackView, I have to set a distinct id on each PackServicesView

I'm not very used to Javascript and less used to to BackBone.. so if anyone as an idea, I take it :)

Thanks

EDIT : A little JSFiddle which reproduce the issue https://jsfiddle.net/sebvb/Lex3shw9/14/

Answer

when you call $(this.innerEl) in PackView.initialize() the element has not yet been added to the DOM, the call to this.render(); is several lines later.

I've corrected your JSFiddle here: https://jsfiddle.net/uenut4te/

    this.render();

    // rendering includedServices using service view
    this.servicesView = new PackServicesView({                
        el : $(this.innerEl),
        collection : this.model.get('services'),
        packCode : this.model.get('packCode')
    });

I've changed the order so that the PackView renders before the PackServicesView is instantiated.