In this article we create an application in which we can exchange the position of images in a table using backbone.js. This tutorial create a CSS, "main.css", and adds some images to the project in the images folder. When we click on the move up and move down button then the images exchange positions.
Use the following procedure to create the application.
Now add an HTML page to the project.
<!DOCTYPE html>
<html>
<head>
<title>BACKBONE Tutorial 3: Collections</title>
<!-- requirements. -->
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.1/underscore-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js"></script>
<script src="main.js"></script>
<script>
$(document).ready(function () {
var pictures = new NaturePictures([
new NaturePicture({ name: 'Winter', image_path: 'images/winter.jpg' }),
new NaturePicture({ name: 'Flower', image_path: 'images/flower.jpg' }),
new NaturePicture({ name: 'Running Tiger', image_path: 'images/tiger.jpg' })
]);
// Add new images in the table.
pictures.add([new NaturePicture({ name: 'Sun Shine', image_path: 'images/sun.jpg' })]);
// Create View
var picturesView = new NaturePicturesView({ collection: pictures });
picturesView.render();
});
</script>
<link href="../bootstrap.css" rel="stylesheet">
<!-- customizations for the table, imgs/buttons, etc. -->
<link href="main.css" rel="stylesheet">
</head>
<body>
<div id="contents">
<table id='nature_pictures' class='table-striped table-bordered'>
<tr class='header'>
<th class='rank_h'>Numbering</th>
<th class='name_h'>Image_Name</th>
<th class='image_h'>Image</th>
<th class='move_rank'>Move</th>
</tr>
</table>
<!-- Templates -->
<!-- *Remember, anything that you want to register an event on must be part of your view!* -->
<script type="text/template" id="nature_picture-template">
<td class='rank'><%= rank %></td>
<td class='name'><%= name %></td>
<td class='image'><img class='nature_picture_pic' src='<%= image_path %>' /></td>
<td class='move_rank'>
<div class='rank_up'><img class='rank_up <%= id %>' src='images/up.gif' /></div>
<div class='rank_down'><img class='rank_down <%= id %>' src='images/down.gif' /></div>
</td>
</script>
</div>
</body>
</html>
$(document).ready(function () {
window.NaturePicture = Backbone.Model.extend({
defaults: {
rank: 0,
move: ''
},
rank_up: function () { this.set('move', 'up') },
rank_down: function () { this.set('move', 'down') }
});
// Collection
window.NaturePictures = Backbone.Collection.extend({
model: NaturePicture,
initialize: function (pictures) {
_.each(pictures, function (picture) {
// This is the *same* line of code as is in set_rank. How do I call that here?
picture.set('rank', _.max(pictures, function (picture) { return picture.get('rank') }).get('rank') + 1);
});
// If we are added via the 'add' method:
this.on('add', this.set_rank);
this.sort();
},
comparator: function (picture) {
return picture.get('rank');
},
trade_rank: function (move_picture, direction) {
var old_rank = move_picture.get('rank');
var new_rank = '';
(direction == 'up') ? new_rank = old_rank - 1 : new_rank = old_rank + 1;
var push_picture = _.find(this.models, function (picture) { return picture.get('rank') == new_rank });
if (new_rank < 1 || new_rank > this.models.length) {
return;
}
move_picture.set('rank', new_rank);
push_picture.set('rank', old_rank);
this.sort();
},
set_rank: function (picture) {
picture.set('rank', _.max(this.models, function (picture) { return picture.get('rank') }).get('rank') + 1);
}
});
window.NaturePictureView = Backbone.View.extend({
// This is responsible for automatically updating the UI
// in response to changes in the model
initialize: function () {
this.model.on('change', this.render, this);
},
tagName: 'tr',
className: 'nature_picture',
render: function () {
$(this.el).html(_.template($('#nature_picture-template').html(), {
id: this.model.cid,
rank: this.model.get('rank'),
name: this.model.get('name'),
image_path: this.model.get('image_path')
}));
return this;
}
});
// The Overall "App" View
window.NaturePicturesView = Backbone.View.extend({
el: $("div#contents"),
events: {
'click img.rank_up': 'rank_up',
'click img.rank_down': 'rank_down'
},
rank_up: function (event) {
this.collection.trade_rank(this.find_move_picture(event, 'up'), 'up');
this.render();
},
rank_down: function (event) {
this.collection.trade_rank(this.find_move_picture(event, 'down'), 'down');
this.render();
},
find_move_picture: function (event, direction) {
var classes = $(event.currentTarget).attr('class').split(' ');
var cid = _.find(classes, function (c) { return c != ('rank_' + direction) });
return this.collection.find(function (picture) { return picture.cid == cid });
},
// Show it!
render: function () {
var header = $("table#nature_pictures tr.header").clone();
$("table#nature_pictures > tbody:last").html('').append(header);
this.collection.sort();
this.collection.each(function (picture) {
var pictureView = new NaturePictureView({ model: picture });
$("table#nature_pictures > tbody:last").append(pictureView.render().el);
});
}
});
});