backbone.js + WebAPI

I’ll present you how to use backbone.js with WebAPI. If you don’t know anything about backbone.js you can find useful links in this artcile also.

Backbone.js is a JavaScript framework. I think that you aren’t suprised about that fact 🙂 I recommend you read Backbone.js Getting Started if you don’t know anything about this framework. It’s not my intention to write a lot about backbone.js but about integration between backbone.js and ASP.NET WebAPI. Backbone.js gives us very good mechanism to connect with REST.

I’ll create very simple example about managing list of planets. I’ll create WebAPI REST service and frontend in backbone.js.
We start from creating a new ASP.NET project:

Now we can create PlanetsController which provide REST service to manage planets list:

using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using WebApiBackboneJs.Models;

namespace WebApiBackboneJs.Controllers
{
    public class PlanetsController : ApiController
    {
        private static IList planets = new List
        {
            new Planet { Id = 1, Name = "Mercury", Diameter = 4878, Orbit = 88, Day = 58.6m },
            new Planet { Id = 2, Name = "Venus", Diameter = 12104, Orbit = 225, Day = 241m },
            new Planet { Id = 3, Name = "Earth", Diameter = 12760, Orbit = 365.4m, Day = 1m },
            new Planet { Id = 4, Name = "Mars", Diameter = 6787, Orbit = 687, Day = 1.01m },
            new Planet { Id = 5, Name = "Jupiter", Diameter = 139822, Orbit = 11.9m * 365, Day = 9.8m / 24.0m }
        };

        [HttpGet]
        [Route("api/planets")]
        public HttpResponseMessage Get()
        {
            HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, planets);

            return response;
        }

        [HttpGet]
        [Route("api/planets/{id}")]
        public HttpResponseMessage Get(int id)
        {
            HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, planets.FirstOrDefault(x => x.Id == id));

            return response;
        }

        [HttpPost]
        [Route("api/planets")]
        public HttpResponseMessage Post([FromBody]Planet value)
        {
            value.Id = planets.Max(x => x.Id) + 1;
            planets.Add(value);

            return Request.CreateResponse(HttpStatusCode.OK, value);
        }

        [HttpPut]
        [Route("api/planets/{id}")]
        public HttpResponseMessage Put(int id, [FromBody]Planet value)
        {
            Planet planet = planets.FirstOrDefault(x => x.Id == id);
            int index = planets.IndexOf(planet);
            planets[index] = value;

            return Request.CreateResponse(HttpStatusCode.OK);
        }

        [HttpDelete]
        [Route("api/planets/{id}")]
        public HttpResponseMessage Delete(int id)
        {
            Planet planet = planets.FirstOrDefault(x => x.Id == id);
            planets.Remove(planet);


            return Request.CreateResponse(HttpStatusCode.OK);
        }
    }
}

I think that it’s time to install backbone.js. I’ll use bower and gulp to this.So first of all we create file .bowerrc:
{
    "directory": "./lib"
}

And bower.json:

{
  "name": "WebApiBackboneJs",
  "private": true,
  "dependencies": {
    "backbone": "*",
    "jquery": "*",
    "json2": "*"
  }
}

Bower install all necessary JavaScript files in lib folder. So, we need gulp to copy scripts from lib to Scripts. We create gulpfile.js to do that:
var gulp = require('gulp');

gulp.task('copy_backbone', function () {
    gulp.src('./lib/backbone/backbone-min.js')
   .pipe(gulp.dest('./Scripts'));
});

gulp.task('copy_jQuery', function () {
    gulp.src('./lib/jquery/dist/jquery.min.js')
   .pipe(gulp.dest('./Scripts'));
});

gulp.task('copy_json2', function () {
    gulp.src('./lib/json2/*.js')
   .pipe(gulp.dest('./Scripts'));
});

gulp.task('copy_underscore', function () {
    gulp.src('./lib/underscore/underscore-min.js')
   .pipe(gulp.dest('./Scripts'));
});

gulp.task('default', ['copy_backbone', 'copy_jQuery', 'copy_json2', 'copy_underscore']);

Of course you can do that in other way. For example you can download all JavaScript files and add them to project to Scripts folder. It’s up to you. Now we need backbone scripts with our planet’s model and collection. So we add two files: planet-model.js and planet-view.js.
$(function () {
    Planet = Backbone.Model.extend({
        defaults: function () {
            return {
                id: null,
                name: null,
                diameter: 0,
                orbit: 0,
                day: 0
            }        
        },
        idAttribute: "id",
        urlRoot: "/api/Planets/"
    });

    PlanetSet = Backbone.Collection.extend({
        url: "/api/Planets/",
        model: Planet
    });
});

and second:
$(function () {
    PlanetView = Backbone.View.extend({
        model: new Planet(),
        tagName: 'tr',

        initialize: function () {
            this.template = _.template($('.planet-list-template').html());
        },

        events: {
            'click .edit-planet': 'edit',
            'click .update-planet': 'update',
            'click .cancel': 'cancel',
            'click .delete-planet': 'delete'
        },

        edit: function () {
            $('.edit-planet').hide();
            $('.delete-planet').hide();
            this.$('.update-planet').show();
            this.$('.cancel').show();

            var id = this.$('.id').html();
            var name = this.$('.name').html();
            var diameter = this.$('.diameter').html();
            var orbit = this.$('.orbit').html();
            var day = this.$('.day').html();

            this.$('.id').html('<label class="form-control id-update">' + id + '</label>');
            this.$('.name').html('<input class="form-control name-update" type="text" value="' + name + '" />');
            this.$('.diameter').html('<input class="form-control diameter-update" type="text" value="' + diameter + '" />');
            this.$('.orbit').html('<input class="form-control orbit-update" type="text" value="' + orbit + '" />');
            this.$('.day').html('<input class="form-control day-update" type="text" value="' + day + '" />');
        },
        update: function () {
            this.model.set('id', $('.id-update').html());
            this.model.set('name', $('.name-update').val());
            this.model.set('diameter', $('.diameter-update').val());
            this.model.set('orbit', $('.orbit-update').val());
            this.model.set('day', $('.day-update').val());
            this.model.save();
            planetsView.render();
        },
        cancel: function () {
            planetsView.render();
        },
        delete: function () {
            this.model.destroy();
        },

        render: function () {
            this.$el.html(this.template(this.model.toJSON()));
            return this;
        }
    });

    planetsList = new PlanetSet();
    planetsList.fetch({ data: { page: 'no' } });

    PlanetsView = Backbone.View.extend({
        el: $('.planets-list'),
        model: planetsList,
        initialize: function () {
            var self = this;
            this.model.on('add', this.render, this);
            this.model.on('change', function () {
                setTimeout(function () {
                    self.render();
                }, 600);
            }, this);
            this.model.on('remove', this.render, this);
        },
        render: function () {
            var self = this;
            this.$el.html('');
            _.each(this.model.toArray(), function (planet) {
                self.$el.append((new PlanetView({ model: planet })).render().$el);
            });
            return this;
        }
    });

    planetsView = new PlanetsView();
});

Now we can create index.html:

<!DOCTYPE html>
<html>
<head>
    <title></title>
	<meta charset="utf-8" />
    <link rel="stylesheet" type="text/css"  href="site.css" />
    <script src="Scripts/jquery.min.js"></script>
    <script src="Scripts/json2.js"></script>
    <script src="Scripts/underscore-min.js"></script>
    <script src="Scripts/backbone-min.js"></script>
    <script src="Scripts/Model/planet-model.js"></script>
    <script src="Scripts/View/planet-view.js"></script>    
</head>
<body>
    <div id="app">
        <div class="planets">
            <h1>Solar planets:</h1>
            <table id="planetsTable" class="table">
                <tr>
                    <th>Id</th>
                    <th>Name</th>
                    <th>Diameter (km)</th>
                    <th>Orbit (Earth days)</th>
                    <th>Day (Earth days)</th>
                    <th></th>
                </tr>
                <tr>
                    <td></td>
                    <td><input class="form-control name-input"></td>
                    <td><input class="form-control diameter-input"></td>
                    <td><input class="form-control orbit-input"></td>
                    <td><input class="form-control day-input"></td>
                    <td><button class="btn btn-primary add-planet">Add</button></td>
                </tr>
                <tbody class="planets-list">
                </tbody>
             </table>
        </div>
    </div>

    <script type="text/template" class="planet-list-template">
        <td><label class="id"><%= id %></label></td>
        <td><label class="name"><%= name %></label></td>
        <td><label class="diameter"><%= diameter %></label></td>
        <td><label class="orbit"><%= orbit %></label></td>
        <td><label class="day"><%= day %></label></td>
        <td>
            <button class="btn btn-warning edit-planet">Edit</button> 
            <button class="btn btn-danger delete-planet">Delete</button>
            <button class="btn btn-success update-planet" style="display:none">Update</button> 
            <button class="btn btn-danger cancel" style="display:none">Cancel</button>
        </td>

    </script>

    <script>
        $(document).ready(function() {
	        $('.add-planet').on('click', function() {
	            var planet = new Planet({
                    id: null,
                    name: $('.name-input').val(),
                    diameter: $('.diameter-input').val(),
                    orbit: $('.orbit-input').val(),
                    day: $('.day-input').val()
		        });
	            $('.name-input').val('');
	            $('.diameter-input').val('');
	            $('.orbit-input').val('');
	            $('.day-input').val('');
		        console.log(planet.toJSON());
	            planetsList.create(planet);
	        })
        })
    </script>
</body>
</html>

It’s our example:

You can find all source code on GitHub: https://github.com/letyshub/WebApiBackboneJs.

 

Useful links

I use bower and gulp but mabe you have never used it before. So maybe those links will help you:

http://www.hanselman.com/blog/IntroducingGulpGruntBowerAndNpmSupportForVisualStudio.aspx

https://github.com/Microsoft/nodejstools

http://bower.io/

http://gulpjs.com/