Backbone Views — Rendering Data to the Screen
In this tutorial, you will learn about Backbone Views. We cover key concepts, practical examples, and best practices to help you master this topic.
Backbone Views are responsible for rendering data to the DOM. They manage a single DOM element (el), bind to Models or Collections, render templates, and handle user interactions. Views are the bridge between data and interface.
What You'll Learn
You'll learn how to define Views, bind them to Models, render templates, manage the el property, and structure View hierarchies for complex UIs.
Why It Matters
Views keep UI logic separate from data logic. A Model does not care how it is displayed. A View does not care how data is stored. This separation makes code testable, maintainable, and easier to debug.
Real-World Use
A security dashboard has multiple Views: an AlertListView renders the alert collection, an AlertDetailView shows a single alert's details, and a FilterView manages search and filter controls. Each View operates independently.
flowchart LR
A[Model] -->|change event| B[View.render]
B --> C[Template]
C --> D[DOM element]
D -->|user action| E[View event]
E -->|set| A
The el Property
Every View has an el — a reference to a DOM element. You can create a new element or reference an existing one from the page.
var TaskView = Backbone.View.extend({
// Create a new element
tagName: 'li',
className: 'task-item',
id: 'task-1',
render: function() {
this.$el.html('<span>Task Content</span>');
return this;
}
});
var view = new TaskView();
console.log('Tag:', view.el.tagName);
console.log('Class:', view.el.className);
console.log('ID:', view.el.id);
view.render();
$('#app').append(view.el);
Expected output:
Tag: LI
Class: task-item
ID: task-1
Binding Views to Models
A View typically binds to a Model or Collection and re-renders when data changes.
var Task = Backbone.Model.extend({
defaults: { title: '', completed: false }
});
var TaskView = Backbone.View.extend({
tagName: 'li',
className: 'task-item',
initialize: function(options) {
this.model = options.model;
// Re-render when model changes
this.model.on('change', this.render, this);
},
render: function() {
this.$el.html(
'<input type="checkbox" ' +
(this.model.get('completed') ? 'checked' : '') +
'> ' +
this.model.get('title')
);
return this;
}
});
var task = new Task({ title: 'Learn Backbone', completed: false });
var view = new TaskView({ model: task });
view.render();
console.log('Rendered HTML:', view.el.outerHTML);
Expected output:
Rendered HTML: <li class="task-item"><input type="checkbox"> Learn Backbone</li>
Using Templates
Backbone does not include a templating engine. Underscore's _.template is the most common choice.
var Task = Backbone.Model.extend({
defaults: { title: '', completed: false, priority: 'medium' }
});
var TaskView = Backbone.View.extend({
tagName: 'li',
className: 'task-item',
// Underscore template
template: _.template(
'<input type="checkbox" <%= completed ? "checked" : "" %>> ' +
'<span class="<%= priority %>"><%= title %></span>'
),
initialize: function(options) {
this.model = options.model;
this.model.on('change', this.render, this);
},
render: function() {
var html = this.template(this.model.toJSON());
this.$el.html(html);
return this;
}
});
var task = new Task({
title: 'Write documentation',
completed: true,
priority: 'high'
});
var view = new TaskView({ model: task });
view.render();
console.log('Template output:', view.el.outerHTML);
Expected output:
Template output: <li class="task-item"><input type="checkbox" checked> <span class="high">Write documentation</span></li>
Rendering Collections
A Collection View renders a list by creating child Views for each Model.
var Task = Backbone.Model.extend({
defaults: { title: '' }
});
var TaskView = Backbone.View.extend({
tagName: 'li',
render: function() {
this.$el.text(this.model.get('title'));
return this;
}
});
var TaskListView = Backbone.View.extend({
tagName: 'ul',
id: 'task-list',
initialize: function(options) {
this.collection = options.collection;
this.collection.on('add', this.addOne, this);
this.collection.on('reset', this.render, this);
},
render: function() {
this.$el.empty();
this.collection.each(function(task) {
this.addOne(task);
}, this);
return this;
},
addOne: function(task) {
var view = new TaskView({ model: task });
this.$el.append(view.render().el);
}
});
var tasks = new (Backbone.Collection.extend({ model: Task }))([
{ title: 'Task A' },
{ title: 'Task B' },
{ title: 'Task C' }
]);
var listView = new TaskListView({ collection: tasks });
listView.render();
console.log(listView.el.outerHTML);
Expected output:
<ul id="task-list"><li>Task A</li><li>Task B</li><li>Task C</li></ul>
View Lifecycle: initialize and remove
The initialize method sets up the View. The remove method cleans up — removes the DOM element and unbinds events.
var TimerView = Backbone.View.extend({
tagName: 'div',
initialize: function() {
this.count = 0;
this.interval = setInterval(function() {
this.count++;
this.$el.text('Count: ' + this.count);
}.bind(this), 1000);
console.log('Timer started');
},
remove: function() {
clearInterval(this.interval);
console.log('Timer cleaned up');
Backbone.View.prototype.remove.call(this);
}
});
var view = new TimerView();
$('#app').html(view.render().el);
// After 3 seconds, remove the view
setTimeout(function() {
view.remove();
}, 3000);
Expected output (immediate):
Timer started
Expected output (after 3 seconds):
Timer cleaned up
View Events: Declarative Event Binding
Use the events property to bind DOM events declaratively.
var TaskView = Backbone.View.extend({
tagName: 'li',
events: {
'click .delete': 'removeTask',
'click .toggle': 'toggleComplete'
},
initialize: function() {
this.template = _.template(
'<span class="toggle"><%= title %></span> ' +
'<button class="delete">Delete</button>'
);
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
toggleComplete: function() {
this.model.set('completed', !this.model.get('completed'));
},
removeTask: function() {
this.model.destroy();
this.remove();
}
});
This View responds to clicks without manual jQuery binding. The events hash handles delegation automatically.
Common Mistakes
- Forgetting
return thisinrender(). Backbone convention returnsthisfromrender()to enable chaining. The View is unusable in parent views without it. - Not calling
remove()on parent Views. Removing a parent View without callingremove()on child Views causes memory leaks from orphaned event listeners. - Using inline HTML instead of templates. Hardcoding HTML in the View makes it hard to change. Use Underscore templates or separate template files.
- Binding events in
render()instead ofeventshash. Binding inrender()creates duplicate listeners on every render. Use theeventshash for DOM events. - Forgetting to pass
{model: model}in initialize. The View needs a reference to its Model. Always pass options through the constructor.
Practice Questions
- What does the
elproperty represent in a Backbone View? - Why should
render()returnthis? - How do you clean up a View when it is no longer needed?
- What is the advantage of using the
eventshash over jQuery event binding? - Challenge: Create a
CollectionViewthat renders a list of models, supports adding new items, and removes items on click. Use event delegation for efficiency.
FAQ
Mini Project
Build a ContactListView that renders a collection of contacts (name, email, phone). Each contact has a ContactView with click-to-expand details. Include an addContact form View. Wire everything together in a main AppView.
What's Next
Now that you understand Views, learn Backbone View Events for detailed event handling. Then explore Backbone View Rendering for advanced rendering patterns.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro