Click here to Skip to main content
15,881,833 members
Articles / Web Development / HTML

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

Rate me:
Please Sign up or sign in to vote.
4.78/5 (21 votes)
1 Apr 2014CPOL9 min read 33.8K   1.3K   37   2
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.

Image 1

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.

Image 2

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.

XML
 <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.

JavaScript
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.

JavaScript
<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

JavaScript
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<o:p>

Description<o:p>

tagName<o:p>

The type of HTML element the View will render.<o:p>

attributes<o:p>

Takes a JavaScript object to set the attributes of the HTML element.<o:p>

initialize<o:p>

This property contains a reference of a function which is executed when a View is instantiated.<o:p>

render<o:p>

This function renders the content of this View.<o:p>

addCollection<o:p>

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.<o:p>

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

JavaScript
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<o:p>

Description<o:p>

tagName<o:p>

The type of HTML element the View will render.<o:p>

attributes<o:p>

Takes a JavaScript object to set the attributes of the HTML element.<o:p>

events<o:p>

Define the events and bind event handler with it.<o:p>

deleteTournament<o:p>

Execute this function when delete event is fired.<o:p>

editTournament<o:p>

Execute this function when edit event is fired.<o:p>

saveTournament<o:p>

Execute this function when save event is fired.<o:p>

cancelTournament<o:p>

Execute this function when cancel the update.<o:p>

The Underscore Template to render a row is shown below

JavaScript
<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

JavaScript
<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

JavaScript
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<o:p>

Description<o:p>

idAttribute<o:p>

This property is use to assign a custom name of Model id.<o:p>

urlRoot<o:p>

This is the server URL to add, edit and delete Tournament from database.<o:p>

defaults<o:p>

Default value assigned to the new Model object.<o:p>

The custom Collection type is shown below

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

Description of some of the properties are shown below

Attributes<o:p>

Description<o:p>

model<o:p>

The type of the Model this Collection is containing.<o:p>

url<o:p>

This is the server URL to fetch the Tournament list.<o:p>

The custom Backbone Router type is shown below

JavaScript
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<o:p>

Description<o:p>

routes<o:p>

It contains a list of navigation URL and its triggered function when navigation occurs.<o:p>

tournaments<o:p>

This is a callback function and is called when navigation matches the route.<o:p>

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.

Image 3

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

JavaScript
$(".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.

Image 4

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

JavaScript
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.

C#
// 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.

Image 5

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.

JavaScript
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.

C#
// 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.

Image 6

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.

JavaScript
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.

JavaScript
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.

C#
// 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.

JavaScript
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.

Image 7

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.

JavaScript
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.

C#
// 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)


Written By
Founder http://softwarelandmarks.com/
Bangladesh Bangladesh
I am in Software Development for more than 12 years. I am expert on Microsoft Platform for Web Forms, MVC, MVC Core, Web API, Desktop App, PHP etc. I am also expert on jQuery, AngularJS, Bootstrap, Font Awesome, Telerik UI, Kendo UI etc. I know BackboneJS, KnockoutJS also. I am an article writer. I have many articles in CodeProject.

Email: khademulbasher@gmail.com

Comments and Discussions

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

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

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