Click here to Skip to main content
Click here to Skip to main content

Single Page Application performing database CRUD operations using Backbone and ASP.NET Web API

, 1 Apr 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
Single Page Application development using Backbone and performing database operations using Web API services.

Introduction

This tutorial is about creating a Single Page Application using Backbone and performing database CRUD (Create, Read, Update and Delete) operations using ASP.NET Web API as a RESTful service.

Contents list of this article

  1. Short description of Single Page Application.
  2. Short description of Backbone.
  3. Short description of ASP.NET Web API.
  4. Sample Single Page Application using Backbone and Web API.

Section-1: Short description of Single Page Application.

Single Page Application became more popular now a day. It gives an impression like a Desktop Application. Basically Single Page Application uses AJAX to communicate with the server, so it takes less time to update a part of the web page without refreshing the whole page and gives impression of a Desktop Application.

Section-2: Short description of Backbone.

Backbone is a JavaScript library with APIs to build a Single Page Application. It provides structure to application with built in JavaScript Classes Model, View, Collection, Router and Event.

Section-3: Short description of ASP.NET Web API.

In short ASP.NET Web API is a framework developed by Microsoft and supplied with Visual Studio 2012. It provides all the functionality of Restful web service specially response on HTTP request call using GET, POST, PUT and DELETE and reply JSON serialize data.

Section-4: Sample Single Page Application using Backbone and Web API.

Almost every application performs some database operations to show or create, update or delete data from database. This sample application shows how to perform CRUD (Create, Read, Update and Delete) operations from Single Page Application using Backbone and ASP.NET Web API. This sample application shows a list of Tournaments and can add, edit or delete a Tournament.

Step 1: First create a Web Application project using Web API Template shows in the following solution explorer.

Description: This application contains only one HTML page tournaments.html and every operation is performed in this page. The Controllers folder contains the Controller classes. Here I am using only one controller TournamentController to extract, add, edit and delete a tournament. Other folder contains the images and necessary JavaScript files for Backbone, Underscore and jQuery. Here BackboneDB is the ADO.NET Entity framework used as a Data Access Layer.

Step 2: Next create a database containing a table Tournament. The table structure is shown below.

Step 3: Next create a HTML page tournaments.html.

This page is the only Single Page which contains all the html and JavaScript. Single Page Application using Backbone the entire HTML is generated by Backbone View class. The initial contents of the page body are shown below.

 <body>
    <div id="page">
        <div id="tournamentAddContainer"></div>
        <div id="tournamentlistContainer"></div>
    </div>
    <div class="loading"><img class="loadingImage" src="/Images/loading.gif" alt="Loading" /></div>
</body> 

As we know View object generates pages html. Model contains application data and is bounded with View to show the information. Collection object contains a list of same type of Model object and Router object changes the browser history.

The custom Views are created for this application is shown below.

 var tournamentAddView = Backbone.View.extend({
        events: {
            'click #btnAddTournament': "addtournament"
        },
        addtournament: function () {
            var tournamentName = this.$el.find("#txtName").val();
            var tournament= new tournamentModel({ Name: tournamentName });
            tournament.save({}, {
                success: function () {
                    tableVeiw.collection.add(tournament);
                },
                error: function () { alert('add error'); }
            });
        },
        render: function () {
            var templateTemp = $("#tempTournamentAdd").html();
            this.$el.html(_.template(templateTemp, { Name: this.model.get('Name') }));
            return this;
        }
    }); 

Here tournamentAddView is created by extended the Backbone built in View Class. This View is used to render an Underscore Template which contains the necessary HTML to add a Tournament. The Underscore Template is shown below.

 <script type="text/html" id="tempTournamentAdd"> 
        <table>
            <tr>
                <td> <input type="text" id="txtName" value="<%= Name %>"/> </td> 
                <td> <input type="submit" id="btnAddTournament" value="Add"/> </td>
            </tr>
        </table>
    </script> 

Here "<%= Name %>" syntax shows the Underscore code block and this statement render the value of Name property of the bounded data Model.

The custom View to render a table to the browser is shown below

 var CustomTableView = Backbone.View.extend({
        tagName: 'table',
        attributes: { class: "tables" },
        initialize: function () {
            this.collection.on('add', this.addCollection);
            tableviewref = this;
            this.$el.html('<tr><th>Tournament Name</th><th></th><th></th></tr>');
        },
        render: function () {
            _(this.collection.models).each(function (tour) {
                this.$el.append(new CustomRowView({ model: tour }).render().el);
            }, this);
            return this;
        },
        addCollection: function (model, collection) {
            tableviewref.$el.append(new CustomRowView({ model: model }).render().el);
        }
    }); 

Here tagName property indicates what kind of HTML element this View is rendering. This View returns a table. Following list describes few of its properties.

Property

Description

tagName

The type of HTML element the View will render.

attributes

Takes a JavaScript object to set the attributes of the HTML element.

initialize

This property contains a reference of a function which is executed when a View is instantiated.

render

This function renders the content of this View.

addCollection

It is a callback function and is called when a Model is added in the collection of the View, which means a row is added to the table.

The custom View to render a row into the table is shown below

 var CustomRowView = Backbone.View.extend({
        tagName: 'tr',
        attributes: { class: "rows" },
        initialize: function () {
            this.model.on('change', this.render, this);
        },
        events: {
            'click #btnDeleteBook': "deleteTournament",
            'click #btnEditBook': "editTournament",
            'click #btnSave': "updateTournament",
            'click #btnCancel': "cancelTournament"
        },
        deleteTournament: function () {
            var self = this;
            this.model.destroy({
                success: function () {
                    tableVeiw.collection.remove(self.model);
                    self.remove();
                    self.render();
                },
                error: function () { alert('delete error'); }
            });
        },
        editTournament: function () {
            var templateTemp = $("#tempTournamentEdit").html();
            this.$el.html(_.template(templateTemp, { Name: this.model.get('Name') }));
        },
        updateTournament: function () {
            var tournamentNameEdit = this.$el.find("#txtNameEdit").val();
            if (tournamentNameEdit != "") {
                this.model.save({ Name: tournamentNameEdit }, {
                    success: function () {
                        var templateTemp = $("#tempTournamentView").html();
                        this.$el.html(_.template(templateTemp, { Name: this.model.get('Name') }));
                    },
                    error: function () { alert('update error'); }
                });
            }
        },
        cancelTournament: function () {
            var templateTemp = $("#tempTournamentView").html();
            this.$el.html(_.template(templateTemp, { Name: this.model.get('Name') }));
        },
        render: function () {
            var templateTemp = $("#tempTournamentView").html();
            this.$el.html(_.template(templateTemp, { Name: this.model.get('Name') }));
            return this;
        }
    }); 

Description of some of the properties are shown below

Attributes

Description

tagName

The type of HTML element the View will render.

attributes

Takes a JavaScript object to set the attributes of the HTML element.

events

Define the events and bind event handler with it.

deleteTournament

Execute this function when delete event is fired.

editTournament

Execute this function when edit event is fired.

saveTournament

Execute this function when save event is fired.

cancelTournament

Execute this function when cancel the update.

The Underscore Template to render a row is shown below

 <script type="text/html" id="tempTournamentView"> 
        <td><%=Name></td>
        <td class="tdInput"> <input type="submit" id="btnEditBook" value=""/> </td> 
        <td class="tdInput"> <input type="submit" id="btnDeleteBook" value=""/> </td>
    </script> 

The Underscore Template used to render HTML when edit button is clicked shown below

 <script type="text/html" id="tempTournamentEdit"> 
        <td> <input type="text" id="txtNameEdit" value="<%= Name %>"/> </td>
        <td class="tdInput"> <input type="submit" id="btnSave" value=""/> </td> 
        <td class="tdInput"> <input type="submit" id="btnCancel" value=""/> </td>
    </script> 

The custom Model use to show every row in the list is shown below

 var tournamentModel = Backbone.Model.extend({
        idAttribute: 'Id',
        urlRoot: '/api/Tournament',
        defaults: {
            Name: 'default',
            Address: 'default'
        }
    }); 

Description of some of the properties are shown below

Attributes

Description

idAttribute

This property is use to assign a custom name of Model id.

urlRoot

This is the server URL to add, edit and delete Tournament from database.

defaults

Default value assigned to the new Model object.

The custom Collection type is shown below

 var CustomCollection = Backbone.Collection.extend({
        model: tournamentModel,
        url: '/api/Tournament'
    }); 

Description of some of the properties are shown below

Attributes

Description

model

The type of the Model this Collection is containing.

url

This is the server URL to fetch the Tournament list.

The custom Backbone Router type is shown below

 var CustomRouter = Backbone.Router.extend({
        routes: {
            'tournaments': 'tournaments'
        },
        tournaments: function () {
            $('#tournamentlistContainer').html(tableVeiw.render().el);
        }
    }); 

Description of some of the properties are shown below

Attributes

Description

routes

It contains a list of navigation URL and its triggered function when navigation occurs.

tournaments

This is a callback function and is called when navigation matches the route.

Step 4: When browser request a page for the first time, because of rendering the whole page it may takes few seconds to load the page. Here I am showing a loading animation when the page is loading for the first time. The initial requested URL is http://localhost:5334/tournaments.html and after load the page Backbone convert it to http://localhost:5334/tournaments, because of Backbone Routing .The page loading event is shown below.

The JavaScript code to show and hide the loading effect is shown below

 $(".loading").css({ display: 'inline'});
    tournamentCollection.fetch({
        success: function (bookResponse) {
            $(".loading").css({ display: 'none' });
        }
    }); 

Before fetching start the animation shows and after successful fetching it hides.

Step 5: The Tournament list page is shown below.

The JavaScript code to extract the list of tournament from server is shown below

 var tournamentCollection = new CustomCollection();
    tournamentCollection.fetch({
        success: function (bookResponse) {
            Backbone.history.start({ pushState: true });
            initialrouter.navigate('tournaments', { trigger: true });
        },
        silent: true
    }); 

This JavaScript code first creates a Collection object and then calls the Collection fetch function to get the list of tournaments. The fetch function takes a JavaScript object as a parameter and the object contains a success callback function and silent property to true that means event will not fire.

When fetching the list from server, Backbone sends a HTTP GET request to the URL 'http://servername/api/Tournament’ which is set in the url property of Collection object.

Server side code to reply to Backbone GET request is shown below.

  // GET api/tournaments
        public List<Tournament> Get()
        {
            List<Tournament> tourList;
            using (BackboneDBEntities entity = new BackboneDBEntities())
            {
                tourList = entity.Tournaments.ToList();
                entity.SaveChanges();
            }
            return tourList;
        } 

When server gets a HTTP GET request from client it executes the Controller’s Get function. This function extract tournament list from database using ADO.NET Entity framework and send the list to the client as a JSON serialize data.

Step 6: The Add tournament page is shown below.

When user clicks on the Add button then Backbone saves a new tournament in the server database using AJAX call request and adds the new tournament in the view without refreshing the whole page.

JavaScript code to add a tournament is shown below.

 addtournament: function () {
            var tournamentName = this.$el.find("#txtName").val();
            var tournament= new tournamentModel({ Name: tournamentName });
            tournament.save({}, {
                success: function () {
                    tableVeiw.collection.add(tournament);
                },
                error: function () { alert('add error'); }
            });
        } 

This function first read the tournament name from textbox and then creates a new Model object and then calls the Model’s save function to save the Model in the database. The URL that Backbone use to save the Model is provided in the Model’s urlRoot property and the URL is 'http://servername /api/Tournament'.

Server side code to add a tournament in database is shown below.

 // POST api/tournaments
        public Tournament Post(Tournament tour)
        {
            using (BackboneDBEntities entity = new BackboneDBEntities())
            {
                entity.Tournaments.Add(tour);
                entity.SaveChanges();
            }
            return tour;
        } 

When server gets a HTTP POST request from client it executes the Controller’s Post function. This function receives a Tournament Entity as a parameter and adds the Tournament Entity to the database using ADO.NET Entity framework and return the newly created tournament to the client as a JSON object.

Step 7: The Edit Tournament page is shown below.

After click on edit button of a tournament in the list, the View is replaced with a textbox and a save and a cancel button. Save button click update the tournament and Cancel button click cancel the update.

JavaScript code is executed on edit button click is shown below.

 editTournament: function () {
            var templateTemp = $("#tempTournamentEdit").html();
            this.$el.html(_.template(templateTemp, { Name: this.model.get('Name') }));
        } 

This function replaces the View with a new Underscore Template ‘ tempTournamentEdit’.

JavaScript code is executed on Save button click is shown below.

 updateTournament: function () {
            var tournamentNameEdit = this.$el.find("#txtNameEdit").val();
            if (tournamentNameEdit != "") {
                this.model.save({ Name: tournamentNameEdit }, {
                    success: function () {
                        var templateTemp = $("#tempTournamentView").html();
                        this.$el.html(_.template(templateTemp, { Name: this.model.get('Name') }));
                    },
                    error: function () { alert('update error'); }
                });
            }
        } 

This function read the update value and calls the Model’s save function with updated value as a parameter. The Backbone sends a HTTP PUT request to the url 'http://servername /api/Tournament/5'. Here 5 is the Id of the tournament in the database.

Server side code to update tournament is shown below.

 // PUT api/tournaments/5
        public void Put(int Id, Tournament tourpara)
        {
            using (BackboneDBEntities entity = new BackboneDBEntities())
            {
                Tournament tour= entity.Tournaments.First(t => t.Id == Id);
                tour.Name = tourpara.Name;
                entity.SaveChanges();
            }
        } 

When server gets a HTTP PUT request from client it executes the Controller’s Put function. This function receives an Id number and a Tournament Entity as a parameter and updates the database record using ADO.NET Entity framework.

JavaScript code to cancel the update is shown below.

 cancelTournament: function () {
            var templateTemp = $("#tempTournamentView").html();
            this.$el.html(_.template(templateTemp, { Name: this.model.get('Name') }));
        } 

This function is executed when Cancel button is clicked. After Cancel button click Backbone cancel the update and returns to the list View.

Step 8: The delete tournament page is shown below.

After click on Delete button Backbone send a HTTP DELETE request to the server to delete the tournament record from database and after successful delete, Backbone delete the tournament from list view.

JavaScript code to delete a tournament is shown below.

 deleteTournament: function () {
            var self = this;
            this.model.destroy({
                success: function () {
                    tableVeiw.collection.remove(self.model);
                    self.remove();
                    self.render();
                },
                error: function () { alert('delete error'); }
            });
        } 

This function calls the Model’s destroy function to delete the tournament from the database. Backbone sends a HTTP DELETE request to the url 'http://servername /api/Tournament/93'. Here 93 is the Id of the tournament need to delete from database.

Server side code to delete tournament is shown below.

 // DELETE api/tournaments/93
        public void Delete(int Id)
        {
            using (BackboneDBEntities entity = new BackboneDBEntities())
            {
                Tournament tour = entity.Tournaments.First(t => t.Id == Id);
                entity.Tournaments.Remove(tour);
                entity.SaveChanges();
            }
        } 

When server gets a HTTP DELETE request from client it executes the Controller’s Delete function. This function receives the Id number of the Tournament as a parameter and deletes the tournament from database using ADO.NET Entity framework.

Conclusion

This is all about how to develop a Single Page Application using Backbone and perform database CRUD operation using ASP.NET Web API. For full codes please download the zip file and run it using Visual Studio 2012.

My Published Articles

  1. http://www.codeproject.com/Articles/661878/Implementation-of-MVC-Patterns-in-ASP-NET-Web-form
  2. http://www.codeproject.com/Articles/674959/MVC-Patterns-Active-and-Passive-Model-and-its
  3. http://www.codeproject.com/Articles/691691/Apply-Here-Map-in-Windows-Phone-HTML-Apps
  4. http://www.codeproject.com/Articles/740703/Easy-way-to-learn-the-Asp-Net-Built-in-Membership

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Khademul Basher
Software Developer (Senior) Brain Station-23
Bangladesh Bangladesh
I am Computer Engineer and expert in Windows platform both for Web and Device. I am in Software development for long time. I develop both for Web and device.I like other technology such as Android, SPA.I am a quick learner and like to research and innovate.

Comments and Discussions

 
GeneralMy vote of 5 PinmemberHumayun Kabir Mamun8-May-14 19:59 
GeneralWay To Complicated and Too Much Overhead Pinmemberkjmcsd9-Apr-14 5:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141030.1 | Last Updated 2 Apr 2014
Article Copyright 2014 by Khademul Basher
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid