Create Contact List of People With Add, Edit, Delete Event

Introduction

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.

"click button.delete""deletePerson",

            "click button.edit""editPerson",

            "change select.type""addType",

            "click button.save""saveEdits",

            "click button.cancel""cancelEdit"

Use the following procedure to create the application.

Step 1

  • Start Visual Studio 2013.
  • From the Start window select "New project".
  • Select "Installed" -> "Template" -> "Visual C#" -> "Web" -> "Visual Studio 2012"and select "ASP.NET Web Application".

Add Web Application

  • Click on the "OK" button.

Step 2

Now add an HTML page to the project.

  • In the Solution Explorer.
  • Right-click on the project and select "Add" -> "HTML page".

Add HTML Page

  • Change the name of the page.

Change Name

  • Click on the "OK" button.

Add the following code:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8" />

    <title>Backbone.js Web App</title>

    <link href="style.css" rel="stylesheet" />

</head>

<body>

    <div id="persons">

        <header>

            <div id="filter"><label>Show me:</label></div>

            <a id="showForm" href="#">Add new Person</a>

            <form id="addPerson" action="#">

                <label for="name">Name:</label><input id="name" /><br />

                <label for="type">Type:</label><input id="type" /><br />

                <label for="address">Address:</label><input id="address" /><br />

                <label for="contact">Contact:</label><input id="contact" /><br />

                <label for="email">Email_Id:</label><input id="email" /><br />

                <button id="add">Add</button>

            </form>

        </header>

    </div>

    <script id="personTemplate" type="text/template">

        <img src="<%= photo %>" />

        <h1><%= name %><span><%= type %></span></h1>

        <div><%= address %></div>

        <dl>

            <dt>Contact:</dt>

            <dd><%= contact %></dd>

            <dt>Email:</dt>

            <dd><a href="mailto:<%= email %>"><%= email %></a></dd>

        </dl>

        <button class="delete">Delete</button>

        <button class="edit">Edit</button>

    </script>

   

Now adding the button for existing template, We can also add an new template that can be used as an editable form.

 <script id="personEditTemplate" type="text/template">

        <form action="#">

            <input class="name" value="<%= name %>" />

            <input id="type" type="hidden" value="<%= type %>" />

            <input class="address" value="<%= address %>" />

            <input class="contact" value="<%= contact %>" />

            <input class="email" value="<%= email %>" />

            <button class="save">Save</button>

            <button class="cancel">Cancel</button>

        </form>

    </script>

   

Now we need to add these scripts file.

 <script src="js/jquery-1.7.1.min.js"></script>

    <script src="js/json2.js"></script>

    <script src="js/underscore-min.js"></script>

    <script src="js/backbone-min.js"></script>

    <script src="js/main.js"></script>

</body>

</html>

Step 3

Now we add a JavaScript file as in the following:

  • In the Solution Explorer.
  • Right-click on the project then select "Add" -> "New Item" -> "JavaScript".

Add JavaScript file

  • Click on the "Add" button.

Add the following code:

(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"), falsefunction (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));

Step 4

Now we add a Style Sheet:

  • In the Solution Explorer.
  • Right-click on the project then select "Add" -> "New Item" -> "Style Sheet".

Add StyleSheet

  • Click on the "Add" button.

Add the following code:

#persons {width:1300pxmargin:auto; }

.person-container { width:400pxpadding:10pxborder:1px solid #aaamargin:0 10px 10px 0position:relativefloat:leftfont-family:sans-serifcolor:#333background-color:#eee; }

.person-container h1 { margin:0font-weight:normal; }

.person-container h1 span { float:rightfont-size:14pxline-height:24pxfont-weight:normal; }

.person-container img { border-width:1pxborder-style:solidborder-color:#fffborder-right-color:#aaaborder-bottom-color:#aaamargin-right:10pxfloat:leftheight:50px ;width:50px;}

.person-container div { margin-bottom:24pxfont-size:14px; }

.person-container a { color:#333;}

.person-container dl { margin:0float:leftfont-size:14px; }

.person-container dt.person-container dd { margin:0float:left; }

.person-container dt { width:50pxclear:left; }

.person-container button { margin-top:10pxfloat:right; }

 

header { margin-bottom:10px; }

header:after { content:""display:blockheight:0visibility:hiddenclear:bothfont-size:0line-height:0; }

 

#filter { float:left; }

#showForm { float:right; }

#addPerson { display:nonewidth:466pxfloat:rightclear:bothfont-family:sans-seriffont-size:14px; }

#addPerson label { width:60pxmargin-right:10pxtext-align:rightline-height:25px; }

#addPerson label#addPerson input { display:blockmargin-bottom:10pxfloat:left; }

#address { width:380pxmargin-left:2px; }

#addPerson label[for="name"]#addPerson label[for="address"]#addPerson label[for="contact"] { clear:both; }

#addPerson button { display:blockmargin:10px 10px 0 0float:rightclear:both; }

 

.person-container input.person-container select { display:blockmargin:0float:left; }

.person-container .name.person-container .address { clear:left; }

.person-container input { margin:0 10px 3px 0; }

.person-container .address { width:395pxmargin-right:0; }

.person-container .contact { width:90px; }

.person-container form button { margin:5px 0 0; }

Step 5

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.

Display record

Add new Person

 
Edit Record 

 

Up Next
    Ebook Download
    View all
    Learn
    View all