In this article we will create a Contact List with edit, delete and add event features in backbone.js. Here will create the four events "button.edit" , "button.Save", "button.cancle" in the contact View.
Use the following procedure to create the application.
Now add an HTML page to the project.
Now adding the button for existing template, We can also add an new template that can be used as an editable form.
Now we need to add these scripts file.
(function ($) {
//demo data
var persons = [
{ name: "Person 1", address: "Address 1", contact: "0123456789", email: "[email protected]", type: "family" },
{ name: "Person 2", address: "Address 2", contact: "4536782947", email: "[email protected]", type: "family" },
{ name: "Person 3", address: "Address 3", contact: "5647839244", email: "[email protected]", type: "Friend" },
{ name: "Person 4", address: "Address 4", contact: "43890128743", email: "[email protected]", type: "Relative" },
{ name: "Person 5", address: "Address 5", contact: "3456789012", email: "[email protected]", type: "Relative" },
];
//define model
var Person = Backbone.Model.extend({
defaults: {
photo: '/img/winter.jpg',
name: "",
address: "",
contact: "",
email: "",
type: ""
}
});
//define directory collection
var Directory = Backbone.Collection.extend({
model: Person
});
//define person view
var PersonView = Backbone.View.extend({
tagName: "article",
className: "person-container",
template: _.template($("#personTemplate").html()),
editTemplate: _.template($("#personEditTemplate").html()),
render: function () {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
events: {
"click button.delete": "deletePerson",
"click button.edit": "editPerson",
"change select.type": "addType",
"click button.save": "saveEdits",
"click button.cancel": "cancelEdit"
},
//delete a contact
deletePerson: function () {
var removedType = this.model.get("type").toLowerCase();
//remove model
this.model.destroy();
//remove view from page
this.remove();
//re-render select if no more of deleted type
if (_.indexOf(directory.getTypes(), removedType) === -1) {
directory.$el.find("#filter select").children("[value='" + removedType + "']").remove();
}
},
//switch person edit mode
editPerson: function () {
this.$el.html(this.editTemplate(this.model.toJSON()));
//add select to set type
var newOpt = $("<option/>", {
html: "<em>Add new...</em>",
value: "addType"
});
this.select = directory.createSelect().addClass("type").val(this.$el.find("#type").val()).append(newOpt).insertAfter(this.$el.find(".name"));
this.$el.find("input[type='hidden']").remove();
},
addType: function () {
if (this.select.val() === "addType") {
this.select.remove();
$("<input />", {
"class": "type"
}).insertAfter(this.$el.find(".name")).focus();
}
},
saveEdits: function (e) {
e.preventDefault();
var formData = {},
prev = this.model.previousAttributes();
//get form data
$(e.target).closest("form").find(":input").not("button").each(function () {
var el = $(this);
formData[el.attr("class")] = el.val();
});
//use default photo if none supplied
if (formData.photo === "") {
delete formData.photo;
}
//update model
this.model.set(formData);
//render view
this.render();
//if model acquired default photo property, remove it
if (prev.photo === "/img/placeholder.png") {
delete prev.photo;
}
//update persons
_.each(persons, function (person) {
if (_.isEqual(person, prev)) {
persons.splice(_.indexOf(persons, person), 1, formData);
}
});
},
cancelEdit: function () {
this.render();
}
});
//define master view
var DirectoryView = Backbone.View.extend({
el: $("#persons"),
initialize: function () {
this.collection = new Directory(persons);
this.render();
this.$el.find("#filter").append(this.createSelect());
this.on("change:filterType", this.filterByType, this);
this.collection.on("reset", this.render, this);
this.collection.on("add", this.renderPerson, this);
this.collection.on("remove", this.removePerson, this);
},
render: function () {
this.$el.find("article").remove();
_.each(this.collection.models, function (item) {
this.renderPerson(item);
}, this);
},
renderPerson: function (item) {
var personView = new PersonView({
model: item
});
this.$el.append(personView.render().el);
},
getTypes: function () {
return _.uniq(this.collection.pluck("type"), false, function (type) {
return type.toLowerCase();
});
},
createSelect: function () {
var filter = this.$el.find("#filter"),
select = $("<select/>", {
html: "<option value='all'>All</option>"
});
_.each(this.getTypes(), function (item) {
var option = $("<option/>", {
value: item.toLowerCase(),
text: item.toLowerCase()
}).appendTo(select);
});
return select;
},
//add ui events
events: {
"change #filter select": "setFilter",
"click #add": "addPerson",
"click #showForm": "showForm"
},
//Set filter property and fire change event
setFilter: function (e) {
this.filterType = e.currentTarget.value;
this.trigger("change:filterType");
},
//filter the view
filterByType: function () {
if (this.filterType === "all") {
this.collection.reset(persons);
personsRouter.navigate("filter/all");
} else {
this.collection.reset(persons, { silent: true });
var filterType = this.filterType,
filtered = _.filter(this.collection.models, function (item) {
return item.get("type").toLowerCase() === filterType;
});
this.collection.reset(filtered);
personsRouter.navigate("filter/" + filterType);
}
},
//add a new person
addPerson: function (e) {
e.preventDefault();
var formData = {};
$("#addPerson").children("input").each(function (i, el) {
if ($(el).val() !== "") {
formData[el.id] = $(el).val();
}
});
//update data store
persons.push(formData);
//re-render select if new type is unknown
if (_.indexOf(this.getTypes(), formData.type) === -1) {
this.collection.add(new Person(formData));
this.$el.find("#filter").find("select").remove().end().append(this.createSelect());
} else {
this.collection.add(new Person(formData));
}
},
removePerson: function (removedModel) {
var removed = removedModel.attributes;
//if model acquired default photo property, remove it
if (removed.photo === "/img/placeholder.png") {
delete removed.photo;
}
//remove from contacts array
_.each(persons, function (person) {
if (_.isEqual(person, removed)) {
persons.splice(_.indexOf(persons, person), 1);
}
});
},
showForm: function () {
this.$el.find("#addPerson").slideToggle();
}
});
//add routing
var PersonsRouter = Backbone.Router.extend({
routes: {
"filter/:type": "urlFilter"
},
urlFilter: function (type) {
directory.filterType = type;
directory.trigger("change:filterType");
}
});
//create instance of master view
var directory = new DirectoryView();
//create router instance
var personsRouter = new PersonsRouter();
//start history service
Backbone.history.start();
}(jQuery));
Now execute the application.
We can see the output like this. There is a display of the record for the person with edit and save buttons and an Add new Data link is displayed.