I have a few different problems going on, I hope though this example is easy to follow. The code uses an HTML template with elements hidden by default (using CSS). The Backbone View uses data in a Model to display appropriate values OR hide the UI element if no value is present in the Mode.
Given a template where everything is hidden by default (using CSS), for example:
<script type="text/template" id="Person-Template">
<span class="fname" title="FirstName"></span>
<span class="lname" title="LastName"></span>
<span class="age" title="Age"></span>
</script>
To hide each UI element the CSS is:
span.fname,
span.lname,
span.age {
display:none;
}
My Backbone.js Model would therefore be:
PersonModel = Backbone.Model.extend({
defaults: {
fname: undefined,
lname: undefined,
age: undefined
}
});
The View (simplified) would be:
PersonView = Backbone.View.extend({
tagName: 'div',
initialize: function() {
this.model.on("fname", this.updateFName, this);
this.model.on("lname", this.updateLName, this);
this.model.on("age", this.updateAge, this);
},
updateFName: function() {
// Pseudo code
Get 'new' value from Model
Obtain reference to DOM element span.fname
Update span.fname
if (model value is empty) {
Hide UI element.
}
},
updateLName: function() {
// Same as above
},
updateAge: function() {
// Same as above
},
render: function() {
// Get model values to display
var values = {
FirstName : this.model.get('fname'),
LastName : this.model.get('lname'),
Age: this.model.get('age'),
};
// Load HTML template
var template = $('#Person-Template').html();
// Populate template with values
var t = _.template(template, values);
// Show / hide UI elements
this.updateFname();
this.updateLName();
this.updateAge();
}
}
Finally, the question: It seems hacky calling each updateXYZ() method from render() just to determine whether the UI element should be set to hidden or visible. I have a lot of attributes in my model and the code just seems a little absurd really.
I have been told on SO that the View should not be responsible for determining what should or should be displays. My questions is, well then what is responsible? The user may perform some (valid) aciton which clears the First Name, in which case I don’t want my View displaying ‘First name:’ followed by no value.
First of all, you don’t need to build your
valuesby hand, just usetoJSON:Then, you have to add your filled in template to your view’s
el:and your template should probably include something to display in your template:
You don’t separate functions for each of the three parts, you could just loop through them in your
render:Now back to your events. There is no such thing as an
"fname"event unless you’ve added a custom one. But there’s no need for that, the model will trigger"change"and"change:fname"events when thefnameis changed; you only need to care about"change"though:I’ve also bound
renderto your view instance using_.bindAllso that you don’t have to worry about the third argument tothis.model.on.Now you have something that works: http://jsfiddle.net/ambiguous/46puP/
You can also push the “should this be displayed” logic into the template:
and simplify your
render:Demo: http://jsfiddle.net/ambiguous/W9cnJ/
This approach would probably be the most common and there’s nothing wrong with it. I think you’re misunderstanding what the previous answer was trying to tell you. The template chooses what pieces of information to display through
<%= ... %>already so there’s no good reason that it shouldn’t see iffname, for example, is set before trying to display it. Depending on the nature of your data, you might want to useif(!_(fname).isUndefined())and such in your template but a simple truthiness check is probably fine; theagemight be an issue in some cases though so you might want to be a bit stricter with that.