Posts Tagged 'MVC'

Retrieving Data with a JavaScript MVC Framework

This is part of series of posts on building reliable, testable Ajax-enabled applications using a JavaScript MVC framework. In my first post, I discussed why this was a key technology and set up my initial server-side resources in an ASP.NET MVC application. The second post created the test framework for the application, using QUnit for the client-side code and Visual Studio for the server-side code. My last post started to provide the pay-off for all that work: integrating the client-side ViewModel’s data and methods with HTML.

The point of this application is to have the user select a customer from a dropdown list and display the information for that customer, retrieved from the server. Using Knockout as a framework for implementing the MVVM pattern, I’ve created a client-side Customer ViewModel written in JavaScript that exposes three properties (CustId, CompanyName, and City) and the functions to retrieve a Customer (getCustomer) and delete a Customer (deleteCustomer). I’ve also wired up the properties to controls on the page.

But I’ve left out one important part: integrating the code that actually retrieves the data from the server into events in the page. In this post, I’ll take care of two topics: adding a dropdownlist that displays all the customers in the Northwind database and retrieving the appropriate customer object from my server when the user selects a customer from the list. Unlike my previous posts, however, I’ll defer showing the TDD code that proves the code works to the end of the post.

Creating the DropDown List

My first step is to define the dropdown list. In my client-side ViewModel I need a property that will expose the list of Customer objects that I retrieve. I add that to the list of properties that I defined in my ViewModel again using one of Knockout’s functions. Because I’m working with multiple objects, I use Knockout’s observableArray function:

this.Customers = ko.observableArray();

Technically speaking, I probably don’t need to use observableArray here. The observableArray function gives me two-way databinding: changes to the Customers property will be reflected in the page and changes to the array in the page would be reflected in the property. Right now, I don’t intend to let the user add or remove Customers from this property so using observableArray is probably providing more functionality than I need. However, the syntax for updating “observable” properties is different from updating a standard variable: I’m using observableArray here because it makes my life easier to use Knockout’s observable functions on all of my ViewModel’s properties instead of just some of them.

Also on the client, I need a function that uses jQuery’s getJson method to retrieve the customer objects that will populate the property. I add the following function to my client-side Customer ViewModel to do that. In the function, I use my controller variable to build the URL that retrieves the list of Customer objects from the right controller. Once I’ve retrieved the array, I update my Customers property with it:

this.getCustomers = function () {
         $.getJSON("/" + Controller + "/GetAllCustomers",
				null,
				function (custs) {
                        self.Customers(custs);
                    }
                 );
    };

With the client-side code created, I need the server-side method in my controller that returns the JSON objects that will populate the dropdownlist. Rather than return the whole Customer object, I’ll create an anonymous object that holds just the values the dropdownlist needs—CustomerId and CompanyName:

public ActionResult GetAllCustomers()
{
  using (northwndEntities ne = new northwndEntities())
  {
    var res = from c in ne.Customers
	select new  {cName = c.CompanyName, cId = c.CustomerID};
    return this.Json(res.ToArray(), JsonRequestBehavior.AllowGet);
   };
}

My final step in displaying these customers is to bind a dropdownlist on the page and bind it to the Customers property I’ve created on my ViewModel. That markup looks like this:

<select data-bind="options: Customers, 
                    optionsText: 'cName', 
                    optionsValue: 'cId', 
                    optionsCaption: 'Select a  Customer'">
</select>

I’m using several of Knockout’s bindings here to tie the list to the property:

  • options: this binding is passed the name of the property on my ViewModel that holds the list of objects to be used to populate the dropdown list.
  • optionsText/optionsValue: These bindings specify which property on the object are to be used for the text and value attributes in the list. The text attribute specifies the property to be displayed to the user while the value property specifies the property to be passed to any related function
  • optionsCaption: Specifies the value to be displayed in the list when it’s first displayed

I don’t need the selectedOptions binding that lets you specify the list’s current selected value through a property on the ViewModel.

Retrieving the Customer Object

Now I need a client-side method to retrieve the customer object from the server. I write that method so that it accepts a customer Id and updates the ViewModel’s properties with the retrieved data:

this.getCustomer = function (custId) {
        $.getJSON("/" + Controller + "/CustomerById/" + custId,
		null,
		function (cust) {
                self.CustId(cust.CustomerID);
                self.CompanyName(cust.CompanyName);
                self.City(cust.City);
        }
       );
    };

I can’t however, wire this method up to my dropdown list directly. Here’s the syntax that ties the list to a function called fetchCustomer on my ViewModel that runs as soon as the user selects an item in the list:

<select data-bind="event: {change: fetchCustomer}, 
                   options: Customers, …

I’m using Knockout’s event binding which lets me specify an event (change, in this case) to a method (fetchCustomer). Unfortunately, there’s no provision in this binding to pass a parameter to the fetchCustomer function. However, when a function is called through Knockout’s binding process, the function is passed two parameters. The second paremeter includes information about the event and through that parameter’s target property I can access the element that fired the event. From there it’s just a short step to retrieving the current value on the element that invoked the function through its value property.

This code gets the currently selected value from the dropdownlist that calls the function and passes that value to my getCustomer function:

this.fetchCustomer = function (ignore, event) 
    {
      this.getCustomer(event.target.value);
    };

Which raises the question of why have the fetchCustomer method at all? Why not call the getCustomer function from the dropdownlist binding and just extract the selected value from the second parameter? I don’t know that I have a good answer for that question. I’m could say that I’m trying to create a testable ViewModel and the more functions that I have that are tied to my View, the harder it is to test the ViewModel. However, a test for a method like fetchCustomer isn’t hard to construct—this code would do the trick:

var eventTest = { target: { value: "ALFKI"} };
cust.fetchCustomer(null, eventTest);

Still, I’m happier isolating any code that seems to me is related to the user interface into its own methods so I’ll continue with this design.

As I said at the start of this series, Learning Tree has several excellent courses in this area. In Canada, I teach both Learning Tree’s ASP.NET MVC course (which has a chapter on TDD in ASP.NET MVC) and its Design Patterns and Best Practices course (which goes into TDD in more depth). But Learning Tree also has related courses that I don’t get to teach, including ones on JavaScript and jQuery.

There’s lots more I could do here. With Knockout it’s easy to enable and disable portions of your page by binding them to properties on your ViewModel. I also haven’t tried to create or manage multiple objects on the page. However, I have convinced myself (and, hopefully, you) that there’s at least one MVC/MVVM framework out there that lets you create applications in a testable, reliable way even when your application includes client-side code.

Test Code

And here’s the code that I used to test my code. First, the test for client-side code that returns the list of customers:

test("Get All Customers",
                  function () {
                  stop();
                  cust = new Customer("Test");
                  cust.getCustomers();
                  setTimeout(function () 
                            {
                             equals(cust.Customers().length, 2, 
                                        "All customers not retrieved");
                             start();
                            },
                        3000);
                  }
    );

Now the mock server-side method that I used to with that client-side test code:

public ActionResult GetAllCustomers()
{
  List<Customer> custs = new List<Customer>();
  Customer cust = Customer.CreateCustomer("PHVIS", 
              "PH&V Information Services", null);
  cust.City = "Regina";
  custs.Add(cust);
  cust = Customer.CreateCustomer("Other", "Other one", null);
  cust.City = "Winnipeg";
  custs.Add(cust);
  return this.Json(custs.ToArray(), JsonRequestBehavior.AllowGet);
}

Finally, the test code for the production version of the server-side method:

[TestMethod]
public void GetAllCustomersTest()
{
  HomeController hc = new HomeController();
  System.Web.Mvc.JsonResult jres = 
                (System.Web.Mvc.JsonResult) hc.GetAllCustomers();
  dynamic res = jres.Data;
  Assert.AreEqual(96, res.Length, "Unable to retrieve all customers");
}

Creating a Testable Client-side ViewModel with Knockout

In my previous post, I discussed why I a JavaScript MVC or MVVM framework is essential: It lets you prove, quickly and conveniently, that your code works so that you can assemble applications out of reliable components. In that post I also started on a project to show how one of those frameworks—Knockout—supports the MVVM design pattern. I also created the server-side methods that my application (an ASP.NET View that displays information for a customer selected by the user) would need. However, what I created were mock functions that I could use for testing. In this post, I’ll start to create the client-side resources my application would need while still focussing on testing the code.

Setting Up the Client

My first step on the client (after adding the Knockout library to my Scripts folder, of course) is to add the necessary script references to my layout page to support using Knockout. For testing purposes, I also include a RenderSection that will allow me to selectively add script references on a View-by-View basis. This basic set of references is used by every View:

<head> <meta charset="utf-8" />  
 <title>@ViewBag.Title</title> 
 <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />  
 <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>  
 <script src="@Url.Content("~/Scripts/knockout-2.0.0.js")" type="text/javascript"></script>
 @RenderSection("Header",false) 
</head> 

With those references in place I’m ready to start generating some client-side code. First, I add a Javascript file to my Scripts folder to hold the Customer ViewModel that I’ll developer. Again, to support testing, I add a variable called controller to the file that will let me redirect my server-side requests to my mock methods:

var controller = ""; 

Now I can (finally) start defining my ViewModel, beginning with the properties that hold the data my page will both display and allow users to update. I define those properties using Knockout’s observable function:

var Customer = function (custIdIn) { 
 this.CustId = ko.observable(); 
 this.CompanyName = ko.observable(); 
 this.City = ko.observable(); 

Using the observable function gives me two-way databinding (the ViewModel automatically updates the View’s elements, the View’s elements automatically update the ViewModel). Other Knockout functions support handling arrays and computed values. I don’t have to use the observable function—if I only wanted the data to flow from my Customer ViewModel to the elements on my page, I could skip using the observable function.

I also define a variable to refer to the current value of this (my ViewModel). I’ll need a reference to my ViewModel later and defining self at this point in the ViewModel’s code bypasses any of the ways that this gets redefined:

var self = this; 

My next step is, still in my Customer ViewModel, to define a function that uses jQuery’s getJSON method to retrieve data from my server-side methods. I’m going to call this function getCustomer and have it retrieve the Customer object from my server-side methods. Once the JSON object is retrieved, the code updates my ViewModel’s properties from the JSON object’s properties. This is one of the places that I use the self variable I defined earlier to avoid problems with this being redefined. I also use my controller variable to define the URL used to access the service:

this.getCustomer = function (custId) {
  $.getJSON("/" + controller + "/CustomerById/" + custId, 
 null, 
 function (cust) { 
 self.CustId(cust.CustomerID); 
 self.CompanyName(cust.CompanyName); 
 self.City(cust.City); } ); }; 

Because my CustId, CompanyName, and City properties are really Knockout observable functions, I must use the syntax shown here to update their values. This ensures, for instance, that changes to the CompanyName and City properties will automatically be reflected in any elements in my page that the properties are databound to.

Testing a JavaScript ViewModel

I’ve got enough functionality written at this point to begin testing (too much, actually, for a real TDD approach—I should have started writing my tests before I put any code in my getCustomer function). In my last post, I defined a controller (TestController) and an action method (CustomerViewModelTest) to use for testing. I can now create the View that will be called from that action method (CustomerViewModelTest.cshtml). I use QUnit for testing client-side code, so I need to add the files Qunit needs (a JavaScript file and a CSS file) to my application. However, I’d prefer not to download those files on every page so I don’t add those references my layout View. Instead, in my test View, I add the references to the Header section that my Layout View references. I also add a reference to the JavaScript file holding my Customer ViewModel that I want to test:

@{ ViewBag.Title = "Customer ViewModel Tests"; } 
@section Header { 
 <script src="@Url.Content("~/Scripts/CustomerVieModel.js")" type="text/javascript"></script>  
 <link href="@Url.Content("~/Content/Tests/qunit.css")" rel="stylesheet" type="text/css" />  
 <script src="@Url.Content("~/Scripts/qunit.js")" type="text/javascript"></script>  
} 

In the body of my page, I add in the headers that QUnit needs to execute and display test results:

<form action="/Test/index">
 <h1 id="qunit-header">Customer MVVM Tests</h1>
 <h1 id="qunit-bannder"></h1>
 <div id="qunit-testrunner-toolbar"></div>
 <h2 id="qunit-userAgent"></h2>
 <ol id="qunit-tests"></ol>
</form> 

I can now test my ViewModel using QUnit’s test function. I set my controller variable to direct all my getJson requests to the mock methods on my Test controller. I use jQuery to prevent my tests from running until the page is fully loaded:

controller = "Test"; $(function () { 

That test consists of instantiating my Customer ViewModel, calling its getCustomer method passing a customer Id, and checking to see if the ViewModel’s properties were updated correctly. Since I’m making an asynchronous server-side call, I can’t simply call my getCustomer method and check the property results—my test code might run faster than my server-side call and check the property before the result is returned. To get around that, I use QUnit’s asyncTest and JavaScript’s setTimeout functions to wait for one second before checking the result using QUnit’s equals function:

var cust; test("Get Customer", 
 function () { 
 stop(); 
 cust = new Customer("Test"); 
 cust.getCustomer("ALFKI"); 
 setTimeout( function () { 
 equals(cust.City(), "Regina", "Customer not retrieved"); 
 start(); }, 
 3000); } ); 

I can now run my tests and see the results by calling my CustomerViewModel action method on my TestController (and, of course, my test passes the first time).

At this point I have a testable ViewModel but, of course, that’s not much good unless it supports a real page. That’s what I’m going to look at in my next post. But with this framework in place, I know that I’m building my page with something that works.

If you’re looking for a course with a good introduction to TDD in Visual Studio, Learning Tree’s Design Patterns and Best Practices in .NET course is a good choice. However, Learning Tree’s ASP.NET MVC course devotes a whole chapter to TDD with ASP.NET MVC.

Peter Vogel

Creating Testable Applications with a JavaScript MVC Framework

I love test driven development because, assuming that I’m going to test my code at all, the TDD frameworks make testing much easier and faster—much faster than running the whole application in order to test a few lines of code, for instance. The problem is that my usual JavaScript + jQuery coding practices defeat TDD.

My usual practice is to present users with a page where, for instance, they can select a customer from a dropdown list in order to see the information on that customer. In my JavaScript code, I use the customer Id from the dropdown list to access a service that returns the appropriate JSON object. I then start moving that data to the page using jQuery to select the elements that I want to update with data from the JSON object. And this is where the wheels fall off, at least as far as TDD goes: I can’t claim that I’ve tested my code unless I’ve tested the jQuery code and I can’t test my jQuery code without providing the page with the elements that my jQuery code is updating.

But this is exactly the problem that the Model-View-Controller design pattern is intended to solve: Have all the code/logic in the controller where it can be tested with TDD; have a separate View that is too simple to have much wrong with it and, as a result, doesn’t require testing. What I want, then, is an MVC framework that lets me put all my JavaScript code in a Controller that doesn’t need a View to be tested. Then, in my View, I want to integrate with my controller in a declarative “code-free/logic-free” way that doesn’t require testing. Oh, sure, in my View I can still have what I call “blunders” (e.g. misspelled text; the right data in the wrong place) but I can’t have logic errors that require debugging.

There are several frameworks that will do that. Lately, I’ve been using one of them—Knockout—on a project for one of my clients. Knockout implements the MVVM pattern which includes a ViewModel object that wraps up both the code and the data that drives your View creating, in the ViewModel, a very testable object. Knockout also provides declarative databinding to elements in my page to move data to my elements without code. In addition to Knockout’s basic functionality there’s lots to like about Knockout. For instance, it’s very easy to implement: download the Knockout library from knockoutjs.com, add it to your Scripts folder, and add a script reference to your page. Knockout also relatively agnostic about how you retrieve your data, making it easy to integrate with either WCF or ASP.NET MVC. I’m going to do this in easy stages, starting with this post that sets up my server-side resources.

Setting Up the Server

As an example, I’m going to walk through creating a page with Knockout using ASP.NET MVC. Since, with TDD, I begin with my tests, I first a controller called Test to my application, with an action method to support displaying a View that will let me test my client-side Customer ViewModel:

public class TestController : Controller {
 public ActionResult CustomerViewModel() {
 return View();
} 

My client-side Customer ViewModel is going to need to retrieve Customer objects from my server. Since I’m working in ASP.NET MVC, I’ll add an action method to my controller to support that. However, I’ll just return some mocked up objects for testing purposes. This ensures that, when I’m testing my Customer ViewModel, I really am only testing my Customer ViewModel and not my server-side code or database connection. That mock method looks like this:

public ActionResult CustomerById(string id) {  
 Customer cust = Customer.CreateCustomer(id, "PHVIS", null); 
 cust.City = "Regina";  
 return this.Json(cust, JsonRequestBehavior.AllowGet); 
} 

Learning Tree has several excellent courses in this area. I get to teach both Learning Tree’s ASP.NET MVC course and its Design Patterns and Best Practices course. But Learning Tree also offers courses on JavaScript and jQuery.

Peter Vogel


Learning Tree International

.NET & Visual Studio Courses

Learning Tree offers over 210 IT training and Management courses, including a full curriculum of .NET training courses.

Free White Papers

Questions on current IT or Management topics? Access our Complete Online Resource Library of over 65 White Papers, Articles and Podcasts

Enter your email address to subscribe to this blog and receive notifications of new posts by e-mail.

Join 29 other subscribers
Follow Learning Tree on Twitter

Archives

Do you need a customized .NET training solution delivered at your facility?

Last year Learning Tree held nearly 2,500 on-site training events worldwide. To find out more about hosting one at your location, click here for a free consultation.
Live, online training