Browse Tag: jquery

Create a telephone directory with Bootstrap, KnockoutJS, jQuery, Web API and Entity Framework (Part 2 of 2)

I find that the best way to learn any new technology, or technology that are unfamiliar with, is to sit down and practice.  The purpose of this very simple tutorial is to learn the basics of creating a single page website that can be used to capture peoples names and telephone numbers. 

By following this tutorial you will learn;

  1. How to use Bootstrap to create a simple UI
  2. How to use KnockoutJS for binding to/displaying of your data
  3. How to use jQuery to asynchronously retrieve data from a web service
  4. How to create a simple Web API using C#/ASP .NET
  5. How to persist data using Entity Framework code first

This is part 2 of 2.  You can read the first part here.

Create the UI

Our user interface has several jobs to do;

  • It must look good (Bootstrap to the rescue here)
  • It must allow the user to enter their name and number
  • It must allow the user to submit their details to the server
  • It must allow the user to reset the data
  • It must allow the user to edit and delete existing entries

What we don’t want is we don’t want to see the page refresh.  This is going to be such a simple page that the act of refreshing the entire page will feel clunky (not to mention the additional overhead of contacting the server to retrieve our entities again).  To aid this, we will use KnockoutJS, which provides JavaScript bindings out of the box.

You have already created the basic structure of your web page, add the following code to the body to create the basic design;

<div class="container-narrow">
    <div class="row">
        <h1>Telephone Directory</h1>
    </div>
    <div class="row shaded padded">
        <div class="col-sm-3">
            <label for="firstName">First Name</label>
            <input id="firstName" name="firstName" type="text" class="form-control" required="required" />
        </div>
        <div class="col-sm-3">
            <label for="lastName">Last Name</label>
            <input id="lastName" name="lastName" type="text" class="form-control" required="required" />
        </div>
        <div class="col-sm-3">
            <label for="phoneNumber">Phone Number</label>
            <input id="phoneNumber" name="phoneNumber" type="text" class="form-control" required="required" />
        </div>
        <div class="col-sm-12">
            <button id="add" name="add" type="submit">Add</button>
            <button id="reset" name="reset" type="reset">Reset</button>
        </div>
    </div>
</div>
<div class="container-narrow">
    <div class="row">
        <table class="table table-striped">
            <thead>
                <tr>
                    <th>First Name</th>
                    <th>Last Name</th>
                    <th>Phone Number</th>
                    <th>&nbsp;</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td><span></span></td>
                    <td><span></span></td>
                    <td><span></span></td>
                    <td>
                        <a href="#">Edit</a>&nbsp;<a href="#">Delete</a>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</div>

Also, you should update your site.css file to include a few styles, as follows;

.shaded {
    background-color: #f9f9f9;
    border-radius: 15px;
}

.padded {
    padding: 10px;
}

.container-narrow {
    margin: 25px auto 0 auto;
    max-width: 700px;
}

    .container-narrow > .row > h1 {
        margin-bottom: 20px;
    }

    .container-narrow > .row > .col-sm-12 {
        margin-top: 15px;
        margin-bottom: 5px;
    }

Note that discussion about Bootstrap is generally out of scope of this tutorial, but basically we have used Bootstrap to create a container (a narrow one) with a couple of rows and a few columns to get the layout we desire.  We have also included a little custom CSS to add some shading, and margins.  We also have a couple of empty spans, which are currently working as placeholders, which will be used to display data about each of our entities.

Create a view model using KnockoutJS

With our UI (view) now in place, we now need a view model.  The purpose of the view model will be to send requests to/receive requests from our Web API, and relay the information to the user.

Open index.js and add the following code;

/// <reference path="jquery-1.9.0.intellisense.js" />
/// <reference path="knockout-3.1.0.debug.js" />

function TelephoneEntry(data) {
}

function TelephoneViewModel() {
    var self = this;
   
    self.add = function () {
    };
    self.edit = function (telephoneEntry) {
    };
    self.delete = function (telephoneEntry) {
    };
    self.reset = function () {
    };
    self.load = function () {
    };

    self.post = function (telephoneEntry) {
    };
}
ko.applyBindings(new TelephoneViewModel());

Note that the references at the top of the file are cues to Visual Studio IntelliSense, and aren’t strictly required (although they do make life a lot easier).

We have some functions here for performing certain actions (which are hopefully self explanatory).  The view model gets bound to the view at at the end, and using some funky syntax (which we will see later) we can access the properties/methods on our view model very simply.

Observable properties

An observable property in KnockoutJS is similar to that in WPF.  Basically when the value of an observable property changes, a change notification is raised, which causes the value of the property on the view to be refreshed.  Add the following observable properties to the view model (under var self = this;).  (this defines each property, and sets a default value)

self.id = ko.observable(0);
self.firstName = ko.observable('');
self.lastName = ko.observable('');
self.number = ko.observable('');

And at the very end of the view model, under all the methods we have defined, add the following;

self.telephoneEntries = ko.observableArray([]);
self.load();

An observable array raises change notifications when items are added to it/removed from it.  It does not raise change notifications where the entities themselves are changed (a common misunderstanding).

Add a new telephone entry

We want to capture the details entered by the user on the form, and display them in a list so they can easily be read back (and persist the data back to the database, more on this later).  Update the TelephoneEntry class to store the basic properties of each entity (you may notice this class is identical to that you created for Entity Framework earlier);

function TelephoneEntry(data) {
    var self = this;
    self.id = data.id;
    self.firstName = data.firstName;
    self.lastName = data.lastName;
    self.number = data.number;
}

Now update the add method to add the new entity, as follows;

self.add = function () {
    var entry = new TelephoneEntry({
        id: self.id(),
        firstName: self.firstName(),
        lastName: self.lastName(),
        number: self.number()
    });

    self.telephoneEntries.push(entry);
};

Add bindings to the view

Switch back to the view.  We can now use Knockout bindings to bind the properties we just created on our view model to our text fields, and our placeholder spans that we created earlier.  To specify a binding, we simply use the data-bind attribute on whatever elements we desire.

Locate the firstName input field and add the data-bind attribute, as shown;

<input id="firstName" name="firstName" type="text" class="form-control" data-bind="value: firstName" required="required" />

We have used a value binding here with the property firstName.  This means that we want to bind the value property of the input field to the firstName property on our view model.  Go ahead and update the other input fields, as shown;

<input id="lastName" name="lastName" type="text" class="form-control" data-bind="value: lastName" required="required" />

<input id="phoneNumber" name="phoneNumber" type="text" class="form-control" data-bind="value: number" required="required" />

Next, we want to bind the click event of our Add button to the add method on our view model.  Can you guess how this might work?  See the code below to see if you were correct!

<button id="add" name="add" type="submit" data-bind="click: add">Add</button>

KnockoutJS is very powerful, flexible and pretty easy to use, wouldn’t you agree?

We’re almost there, but first we need to update our table to show a row for each entity in our telephoneEntries observable array that we created earlier.  For this we need a new binding, the foreach binding.  Update the tbody element, as shown below;

 <tbody data-bind="foreach: telephoneEntries">

Basically what is going to happen here is that for each entity in our telephoneEntries observable array, a tr is going to be output.  Each tr will be bound to its corresponding entity in the array.  Use the text binding to see the text property for each span placeholder, as shown below;

<tbody data-bind="foreach: telephoneEntries">
    <tr>
        <td>
            <span data-bind="text: firstName"></span>
        </td>
        <td>
            <span data-bind="text: lastName"></span>
        </td>
        <td>
            <span data-bind="text: number"></span>
        </td>
        <td>
            <a href="#" data-bind="click: $parent.edit">Edit</a>&nbsp;<a href="#" data-bind="click: $parent.delete">Delete</a>
        </td>
    </tr>
</tbody>

I’ve also added a link for editing and deleting entities, which we’ll flesh out later.  To access properties/methods on the view model (rather than whatever is in the current context) we use the $parent object.

If you run the application now, you should be able to enter a first name, last name and number, click the Add button and see a new row added to the table underneath.  Lets now wire up the rest of the functionality.

Add some new properties to you view model, as follows;

self.addText = ko.observable('Add');
self.resetText = ko.observable('Reset');
self.selectedIndex = -1;

These will be used for the add/update methods to determine which is which.  Now update the add method so that it can determine weather it should perform an add, or an update, as shown;

self.add = function () {
        var entry = new TelephoneEntry({
            id: self.id(),
            firstName: self.firstName(),
            lastName: self.lastName(),
            number: self.number()
        });
        if (self.addText() == 'Add') {
            self.telephoneEntries.push(entry);
        }
        else {
            var oldTelephoneEntry = self.telephoneEntries()[self.selectedIndex];
            self.telephoneEntries.replace(oldTelephoneEntry, entry);
        }

        self.post(entry);
        self.reset();
    };

Next, update the edit method to allow editing of each entry.  The method simple reads out the given entity (provided by the context aware aspect of KnockoutJS) and populates the publicly bound properties with those values;

self.edit = function (telephoneEntry) {
    self.id(telephoneEntry.id),
    self.firstName(telephoneEntry.firstName);
    self.lastName(telephoneEntry.lastName);
    self.number(telephoneEntry.number);
    self.addText('Update');
    self.resetText('Cancel');
    self.selectedIndex = self.telephoneEntries.indexOf(telephoneEntry);
};

The delete method is quite simple, all we have to do is remove the entity (again given to us by KnockoutJS from the telephoneEntries observable array);

self.delete = function (telephoneEntry) {
    self.telephoneEntries.destroy(telephoneEntry);
};

Update the reset method, which will allow the user to clear down the form (and we will call this too when performing certain operations);

self.reset = function () {
    self.id(0);
    self.firstName('');
    self.lastName('');
    self.number('');
    self.addText('Add');
    self.resetText('Reset');
    self.selectedIndex = -1;
};

You will need to update the Add/Reset buttons on your view to include the addText and resetText properties, so that we can perform the appropriate actions when editing/adding;

<button id="add" name="add" type="submit" data-bind="click: add, text: addText">Add</button>

<button id="reset" name="reset" type="reset" data-bind="click: reset, text: resetText">Reset</button>

Communication with the Web API using jQuery

The application should now be completely usable (just a reminder, the full source code in on GitHub if you are struggling).  You may notice, however, that if you refresh the page all your data that you have meticulously typed out has been lost.  We need to make use of that Web API that we created earlier to store our data across page loads.  The quickest and easiest way to do this is with jQuery.

To achieve what we require here, we need to make use of the jQuery getJSON, Post and AJAX methods.

Update the load method as follows;

self.load = function () {
    $.getJSON('http://localhost:62129/api/Data/', function (data) {
        $.each(data, function (index, item) {
            self.telephoneEntries.push(new TelephoneEntry({
                id: item.id,
                firstName: item.firstName,
                lastName: item.lastName,
                number: item.number
            }));
        });
    });
};

We call the Web API using the getJSON method.  This passes a ContentType of application/JSON header under the hood to ensure that the server responds in that format.  When the process is complete, it calls our callback function, passing the retrieved data in as the data parameter.  Its then a simple case of iterating over the resulting array and adding each entity to our telephoneEntries observable array.  And because its an observable array, the view (our table) is updated automatically for us.

If you refresh your view, after a second or two (this will take longer the first time) your seed data that you created earlier should appear!

To post a new entity to the Web API, update the post method as follows;

self.post = function (telephoneEntry) {
 $.post('http://localhost:62129/api/Data/', telephoneEntry, function (id) {
        telephoneEntry.id = id;
    });
};

The HTTP POST verb will be sent along with the request.  Note that the callback for this request might not be what you are expecting.  In order to make future edits and deletes, we need the ID value for the new entity we just created.  Note that when you create a new entity on the client, its ID is unknown, so by default the ID is always 0.  When we wrote up the Post method on our API earlier, after the new entity is saved, its new entity ID is returned back to us.  Again thanks to the observable property provided by KnockoutJS, everything just updates magically for us.

The delete operation is slightly different.  Take the following code;

self.delete = function (telephoneEntry) {
    self.telephoneEntries.destroy(telephoneEntry);
    $.ajax({
        url: 'http://localhost:54946/api/Data/' + telephoneEntry.id,
        type: 'DELETE',
        contentType: "application/json;charset=UTF-8",
        data: JSON.stringify({ id: telephoneEntry.id }),
        dataType: "json"
    });};

We have to explicitly send the  DELETE HTTP verb, the Content-Type and a stringified version of the JSON (and the actual data type) along with the request.  The reason why is unclear, but failing to do so results in a 500 Internal Server Error.  Interestingly, however, the operation still completes in its entirety.  If anybody can explain this to me I’m more than happy to listen.

Create a telephone directory with Bootstrap, KnockoutJS, jQuery, Web API and Entity Framework (Part 1 of 2)

I find that the best way to learn any new technology, or technology that are unfamiliar with, is to sit down and practice.  The purpose of this very simple tutorial is to learn the basics of creating a single page website that can be used to capture peoples names and telephone numbers. 

By following this tutorial you will learn;

  1. How to use Bootstrap to create a simple UI
  2. How to use KnockoutJS for binding to/displaying of your data
  3. How to use jQuery to asynchronously retrieve data from a web service
  4. How to create a simple Web API using C#/ASP .NET
  5. How to persist data using Entity Framework code first

This is part 1 of 2.  The second part will be available soon.

A screenshot of the end result;

FinalProduct

Prerequisites/Set Up

We will not be using the standard ASP .NET template, for the sake of keeping the code simple and light.

Regardless of whether you are using Visual Studio 2012 or 2013, start by creating a new ASP .NET Empty Web Application.  Call the project TelephoneDirectory.

NewProject

We’re using this template to avoid a lot of the bulk that comes with the other default templates.  The empty project is truely empty, apart from a web.config file and a couple of references.

Third party dependencies

Next, use the Package Manager Console to add our third party dependencies;

  • Bootstrap (Install-Package bootstrap (this will also bring down jQuery, which is a dependency)) >> Used to give us a super pretty user interface.
  • Entity Framework (Install-Package entityframework) >> Used for data persistence
  • KnockoutJS (install-package knockoutjs (which surprisingly, has no dependencies itself)) >> Used for model binding our form/displaying our data
  • WebAPI (Install-Package Microsoft.AspNet.WebApi) >> Used as the back end data service
  • Newtonsoft.Json (install-package Newtonsoft.Json) >> Used to JSON-ify our data servers responses

Other files

Add the following files in their respective folders;

  • Scriptsindex.js
  • Contentsite.css
  • index.html
  • Global.asax (Add New Item > Global Application Class)

Open up index.html and update the markup as follows; (be sure to substitute the version numbers for the current version number)

  • Add bootstrap.min.css and site.css to the header
  • Add jquery-1.9.0.min.js, bootstrap.min.js, knockout-3.1.0.js and index.js to the body (just above the closing body tag)

Remember that order matters.  You markup should look as follows;

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <link href="Content/bootstrap.min.css" rel="stylesheet" />
    <link href="Content/site.css" rel="stylesheet" />
</head>
<body>
    <script src="Scripts/jquery-1.9.0.min.js"></script>
    <script src="Scripts/knockout-3.1.0.js"></script>
    <script src="Scripts/index.js"></script>
</body>
</html>

Implement your model

Its always a bit tricky with where to start on these tutorials.  Normally you might spec out a simple UI first and experiment with feeding data to it and evolve the design over a little time, but as this is a guided tutorial, I already know what the end result will be.  So stick with me.

We are using the Entity Framework code first approach for simplicity, so we can create our entities straight in code. 

We will need a property to store the ID of the telephone entry (more on this as we go along), the first name, the last name and the number.  Add a new folder called Models and add a new class called TelephoneEntry, as follows;

public class TelephoneEntry
{
    public string FirstName { get; set; }
    public int Id { get; set; }
    public string LastName { get; set; }
    public string Number { get; set; }
}

Now we need a database context, which we can use to query our database.  Create a DbContext class, called DataContext as follows (you can add this class to the Models folder for simplicity, ideally all your data access code should be split out into its own project, but that is out of the scope of this post);

public class DataContext : DbContext
{
    public DbSet<TelephoneEntry> TelephoneEntries { get; set; }
}

To help aid our testing further down the line, it will be helpful to have some seed data.  Create a custom initializer, called Initializer, which inherits from the  DropCreateDatabaseAlways database initializer.  This will ensure that we start with a fresh database every time our application starts (you would want to change this in a production environment, but its super handy for debugging purposes);

public class Initializer : DropCreateDatabaseAlways<DataContext>
{
    protected override void Seed(DataContext context)
    {
        context.TelephoneEntries.Add(new TelephoneEntry { FirstName = "Jon", LastName = "Preece", Number = "4444" });
    }
}

Override the seed data and add in a new entry (or several if you like), as shown above.

For the final step, we need to initialize our database.  You can do this in Global.asax.cs, inside the Application_Start method;

protected void Application_Start()
{
     Database.SetInitializer(new Initializer());
}

From the database creation perspective, we’re done.  We will query the database a little later on when creating our Web API.

Set up your Web API

Web API is very easy to work with out of the box.  At a high level, it pretty much “just works”, which is fantastic.  One could write a whole book on the ins-and-outs of Web API, but we only need to make use of its basic functionality at this time.

Create a new folder called App_Start and add a new class called WebApiConfig.cs.  This class will contain routing instructions so that our API Controller (coming next) can be accessed as a Restful service.

Add the following static method;

public static void Register(HttpConfiguration config)
{
    config.MapHttpAttributeRoutes();
    config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional });

   JsonMediaTypeFormatter jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
    jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}

You may now be wondering what is the purpose of this JsonMediaTypeFormatter? Well, when a client attempts to access the Web API, it can specify what type of content it accepts in response (by passing an appropriate Content-Type header).

Out of the box, Web API and respond in two formats; XML and JSON.  XML is supported because it is widely used and has been around a long time (although its scarily bulky).  JSON is a very lean duck typed language that can be very efficiently transferred and interpreted.  Unfortunately Web API, when replying with data to the client, responds in Pascal Case (ThisIsPascalCase), whereas JavaScript is typically written in Camel Case (thisIsCamelCase). 

The JsonMediaTypeFormatter ensures that our JSON is sent to the client in camel case, so that it can be properly consumed by the client.

You should call the Register method from the Global.asax.cs Application_Start method, as shown;

protected void Application_Start()
{
    GlobalConfiguration.Configure(WebApiConfig.Register);
    Database.SetInitializer(new Initializer());
}

Design your Web API

Lets take a step back a minute to discuss what Web API is.  Perfectly summed up by Wikipedia;

A server-side web API is a programmatic interface to a defined request-response message system, typically expressed in JSON or XML, which is exposed via the web—most commonly by means of an HTTP-based web server.

Web API is a publically accessible interface for accessing data via HTTP.  Web API uses conventions (or you can actually use routing attributes, but that’s another discussion) to map your methods to the associated HTTP verbs.

Get

So, if you want to respond to a HTTP GET request, you add a Get method to your controller. If you want to respond to a HTTP DELETE request, you add a Delete method to your controller … and so on.

For this tutorial, we will add methods to respond to Get (with overloads), Delete and Post requests.   Create a new folder called Controllers, and add a new class called DataController.  Make sure the class inherits from ApiController (rather than the standard Controller base class) and add the following method;

public class DataController : ApiController
{
     public async Task<IEnumerable<TelephoneEntry>> Get()
     {
        using (DataContext context = new DataContext())
        {
            return await context.TelephoneEntries.ToListAsync();
        }
    }
 }

In the interest of maximum scalability (its important to think ahead) you can make your method asynchronous (by using the async and await keywords) and use the Async versions of methods where possible, although you should know that this is not required (but a good habit to get into).

Interestingly, you can now open up a web browser (by pressing F5) and query this method.  Your browser will send a Get request by default; (note that your port number will vary to mine)

GetData

Well done, your API is now working.

The method you have added will return all the telephone entries by default.  Now, add the following method;

public async Task<TelephoneEntry> Get(int id)
{
    using (DataContext context = new DataContext())
    {
        return await context.TelephoneEntries.FirstOrDefaultAsync(t => t.Id == id);
    }
}

Change the URL to pass in an ID as follows; http://localhost:62129/api/Data/1 or http://localhost:62129/api/Data?id=1.

A little challenge for you, can you add a couple more methods to query the data based on a search query and a first/last name? I’ll wait here whilst you try.

All done? See how yours compares to mine;

public async Task<List<TelephoneEntry>> Get(string query)
{
    using (DataContext context = new DataContext())
    {
        return await context.TelephoneEntries.Where(t => string.Equals(t.FirstName, query) || string.Equals(t.LastName, query)).ToListAsync();
    }
}

public async Task<List<TelephoneEntry>> Get(string firstName, string lastName)
{
    using (DataContext context = new DataContext())
    {
        return await context.TelephoneEntries.Where(t => string.Equals(t.FirstName, firstName) && string.Equals(t.LastName, lastName)).ToListAsync();
    }
}

Delete

If you want the client to be able to delete data (and we do), you will want to add a delete method.  To call the delete method, a DELETE HTTP verb will need to be sent with the request (we will see this in action later).  An identifier for the entity to delete will also need to be sent (in this case, the ID.  Again we will see this later).

Add the following delete method;

public void Delete(int id)
{
    using (DataContext context = new DataContext())
    {
        TelephoneEntry entity = context.TelephoneEntries.FirstOrDefault(t => t.Id == id);
        if (entity != null)
        {
            context.Entry(entity).State = EntityState.Deleted;
        }

        context.SaveChanges();
    }
}

Post

A post request is slightly different to the other methods already discussed.  In this case, we need to pass a more complex object from the client than just a simple ID or a string.  We want to pass the actual TelephoneEntry entity that we want to create.  For completeness, we need to add the FromBody attribute to our parameter, which tells Web API to use the model binder (media type binder to be precise) to extract values from the HTTP message (rather than the URI), and create the object for us without us having to worry about it.

Add your post method as follows;

public async Task<int> Post([FromBody] TelephoneEntry telephoneEntry)
{
    using (DataContext context = new DataContext())
    {
        if (telephoneEntry.Id == 0)
        {
            context.Entry(telephoneEntry).State = EntityState.Added;
        }
        else
        {
            context.Entry(telephoneEntry).State = EntityState.Modified;
        }

        await context.SaveChangesAsync();
        return telephoneEntry.Id;
    }
}

There you go.  You data is now ready to be accessed and consumed by the outside world!

Summary

So far we have explored the basic structure for our project, we have installed all our dependent packages, we have created a database using Entity Framework code first, and we have created a publicly available Web API. In the second part of this post, we will flesh out our view, add KnockoutJS to make our page interactive, and use jQuery to tie everything together.

The entire source code can be found on GitHub