Backbone.js Application Walkthrough Part 2: Views and Templates – Video Tutorial

We’re moving right along in our video series of tutorials walking you through the process of writing a Backbone.js application. Today we cover the views and embedded templates. There are a number of views here, all pulling from the same models and collections of wine. You’ll see each view, what it’s for, and how it works its magic. Click on through for this long look at Backbone.js views and templates.

Before you watch the video, there a few things I discovered while recording and after recording that I want to bring to your attention. First off, I realized that I forgot to increase the font size of the editor so that it could be more easily seen on small screens, so you’ll definitely want to watch this in full screen on a non-mobile device. Next, there was a line of code that was used a couple times in wine-list.js that I decided to refactor into its own function. Finally, as I mention in the video $(this.el) can be swapped out with this.$el, which is faster because it is already cached. You can see these changes represented in the code given below the video.

Just as a note, after I’m done with this whole project, I will be placing all the code up on GitHub for everyone to download and view.

Backbone.js Video Tutorial Series

HTML Code

index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>Backbone Cellar</title>
<link rel="stylesheet" href="css/styles.css" />
</head>
<body>

<div id="header"></div>

<div id="sidebar"></div>

<div id="content">
<h2>Welcome to Backbone Cellar</h2>
<p>This is a sample application designed to teach people with the basic knowledge of Backbone.js how to use it in a real application.</p>
</div>

<script type="text/javascript" src="js/libs/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="js/libs/underscore-min.js"></script>
<script type="text/javascript" src="js/libs/backbone-min.js"></script>

<script src="js/utils.js"></script>
<script src="js/models/wine-model.js"></script>
<script src="js/views/header.js"></script>
<script src="js/views/wine-list.js"></script>
<script src="js/views/wine-details.js"></script>
<script src="js/main.js"></script>

<script type="text/template" id="header-template">
<button class="new">New Wine</button>
</script>


<script type="text/template" id="wine-details-template">
<div class="form-left-col">
<label>Id:</label>
<input id="wineId" name="id" type="text" value="<%= id %>" disabled />

<label>Name:</label>
<input type="text" id="name" name="name" value="<%= name %>" required/>

<label>Grapes:</label>
<input type="text" id="grapes" name="grapes" value="<%= grapes %>"/>

<label>Country:</label>
<input type="text" id="country" name="country" value="<%= country %>"/>

<label>Region:</label>
<input type="text" id="region" name="region" value="<%= region %>"/>

<label>Year:</label>
<input type="text" id="year" name="year" value="<%= year %>"/>

<button class="save">Save</button>
<button class="delete">Delete</button>
</div>

<div class="form-right-col">
<img height="300" src="images/<%= picture %>"/>
<label>Notes:</label>
<textarea id="description" name="description"><%= description %></textarea>
</div>
</script>


<script type="text/template" id="wine-list-item-template">
<a href='#wines/<%= id %>'><%= name %></a>
</script>


</body>
</html>

JavaScript Code

js/main.js
1
2
3
4
5
6
7
8
9
10
Backbone.View.prototype.close = function() {
console.log( 'Closing view ' + this );

if ( this.beforeClose ) {
this.beforeClose();
}

this.remove();
this.unbind();
}
js/views/header.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
window.HeaderView = Backbone.View.extend({

initialize: function() {
this.template = _.template( $('#header-template').html() );
},

render: function() {
this.$el.html( this.template() );

return this.el;
},

events: {
"click .new" : "newWine"
},

newWine: function() {
app.navigate('wines/new', true);

return false;
}
});
js/views/wine-list.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
window.WineListView = Backbone.View.extend({

tagName: 'ul',

initialize: function() {
this.model.bind( 'reset', this.render, this);
this.model.bind( 'add', this.appendNewWine, this);
},

render: function() {
_.each( this.model.models, function( wine ) {
this.appendNewWine( wine );
}, this);

return this.el;
},

appendNewWine: function( wine ) {
this.$el.append(new WineListItemView({model:wine}).render());
}

});

window.WineListItemView = Backbone.View.extend({

tagName: 'li',

initialize: function() {
this.template = _.template( $('#wine-list-item-template').html() );

this.model.bind( 'change', this.render(), this);
this.model.bind( 'destroy', this.close(), this);
},

render: function() {
this.$el.html( this.template( this.model.toJSON()));

return this.el;
}

});
js/views/wine-details.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
window.WineView = Backbone.View.extend({

initialize: function() {
this.template = _.template( $('#wine-details-template').html() );

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

render: function() {
this.$el.html( this.template(this.model.toJSON()));

return this.el;
},

events: {
'click .save': 'saveWine',
'click .delete': 'deleteWine',
},

saveWine: function() {
this.model.set({
name: $('#name').val(),
grapes: $('#grapes').val(),
country: $('#country').val(),
region: $('#region').val(),
year: $('#year').val(),
description: $('#description').val()
});

if ( this.model.isNew() ) {
var self = this;

app.wineList.create( this.model, {
success: function() {
app.navigate( 'wines/' + self.model.id, false);
}
});

} else {
this.model.save();
}

return false;
},

deleteWine: function() {
this.model.destroy({
success: function() {
alert('Wine was deleted successfully');
window.history.back();
}
});

return false;
}

});

Backbone.js Video Tutorial Series

Wrapping Up

I hope you all are learning. I know this isn’t exactly the way that someone would proceed through making a web app, but this is a logical way of showing things to you – though, not the only logical way. I’m looking forward to the next piece of this puzzle, as I hope you are also. God bless and Happy Coding!

Author: Joe Zimmerman

Author: Joe Zimmerman Joe Zimmerman has been doing web development ever since he found an HTML book on his dad's shelf when he was 12. Since then, JavaScript has grown in popularity and he has become passionate about it. He also loves to teach others though his blog and other popular blogs. When he's not writing code, he's spending time with his wife and children and leading them in God's Word.