Thursday, 21 February 2013

Form validation using Angular JS

User input validation is a crucial feature to be implemented in any data driven application. We have a number of libraries that support input validation on client side and all of them address this issue in a very effective way. Since Angular JS is designed to make the process of client side data driven application development easier, it also has a nice support of user input validation.

Angular is capable of validating HTML5 input types like required, url, number and email. It also provides some directives like min, max, minlength, maxlength and required for validation. If any of these built-in features is not able to address the business purpose, we can define our own directive and use it for validation.

To indicate the user about validity of form data, the following CSS classes can be defined. They will be applied to the input fields by Angular JS whenever they are required:


  • ng-valid – Applied if the value satisfies validation rules
  • ng-invalid – Applied if the value doesn’t satisfy validation rules
  • ng-dirty – Applied only when there is change in the value of the field
  • ng-pristine – Applied if the field is untouched

Let’s apply some validations to the shopping cart item form that we have been using in earlier posts. If you didn’t read old posts yet, refer to the jsfiddle sample of the last post. Following are the CSS styles that will be applied on the form elements:

input.ng-invalid.ng-dirty {
 background-color: #FA787E;
}
input.ng-valid.ng-dirty {
 background-color: #78FA89;
}

Let's apply the following validations on the cart item form:

  • All fields are required – can be done using required attribute
  • Item name should contain only alphabets and spaces, quantity should be an integer – can be achieved using pattern directive
  • Price should be a float number with value between 50 and 5000 – can be done using a custom validation (Note: Though it can be achieved using pattern, I am using custom validator for demonstration)
  • Quantity should be an integer with minimum value 1 and maximum value 90 – can be achieved using min and max directives and a regular expression to check for integer

If the browser supports HTML5, browser will also validate the form elements. This behaviour can be supressed using novalidate attribute on the form tag. Following is the mark-up of item form with validation attributes applied:

<form novalidate name="itemForm">
 <table>
  <tr>
   <td>Name: </td>
   <td><input name="name" type="text" ng-model="item.Name" required ng-pattern="name" /></td>
  </tr>
  <tr>
   <td>Price: </td>
   <td><input name="price" type="text" ng-model="item.Price" required  valid-price /></td>
  </tr>
  <tr>
   <td>Quantity: </td>
   <td><input name="quantity" type="number" ng-model="item.Quantity" min="1" max="90" ng-pattern="integerval" required /></td>
  </tr>
  <tr>
   <td colspan="2"><input type="Button" value="Add" ng-click="addItem(item)" ng-disabled="itemForm.$invalid" /> </td>
  </tr>
 </table>
</form>

Notice the ng-disabled directive on the button. It is used to disable the button if any of input elements in the form is not valid.

To match the pattern of name and quantity fields, ng-pattern attribute is applied on them. The corresponding patterns have to be assigned to a field in the controller.

$scope.name=/^[a-zA-Z ]*$/;

$scope.integerval=/^\d*$/;

For the custom validation to validate price, a directive with the name validPrice has to be created. Let’s add this directive to the shopping module we created in last post.
angular.module(‘shopping’,[])
 .value(…)
 .filter(…)
 .directive('validPrice',function(){
  return{
   require: "ngModel",
   link: function(scope, elm, attrs, ctrl){
    var regex=/^\d{2,4}(\.\d{1,2})?$/;
    ctrl.$parsers.unshift(function(viewValue){
     var floatValue = parseFloat(viewValue);
     if( floatValue >= 50 && floatValue <=5000 && regex.test(viewValue)){
      ctrl.$setValidity('validPrice',true);
     }
     else{
     ctrl.$setValidity('validPrice',false);
     }
     return viewValue;
    });
   }
  };
 });


With this, we are done with all validations. But this leaves the form in invalid state whenever the input fields are cleared after adding an item to the cart. To prevent this behaviour, we have to manually set the form’s state as pristine. Following statement does this for us:
$scope.itemForm.$setPristine();

This statement has to be added to the addItem function of the controller. Though the validations are doing a great job by indicating the invalidity of data on input fields, the user won’t get to know about what has to be modified unless a friendly message is displayed. Message can be displayed in any format that you like. To keep it simple, I am displaying the messages in span elements. An invalid message should be displayed when both of the following conditions meet:

  • An input field is modified – can be checked using $dirty
  • Contains an invalid value – can be checked using $invalid

Following is the markup for displaying error message:

<div ng-show="itemForm.name.$dirty && itemForm.name.$invalid">
 <span ng-show="itemForm.name.$error.required">Name cannot be left blank</span>
 <span ng-show="itemForm.name.$error.pattern">Name cannot contain numbers or special characters</span>
</div>
<div ng-show="itemForm.price.$dirty && itemForm.price.$invalid">
 <span ng-show="itemForm.price.$error.required">Price cannot be blank</span>
 <span ng-show="itemForm.price.$error.validPrice">Price should be a number between 50 and 5000 with maximum 2 digits after decimal point</span>
</div>
<div ng-show="itemForm.quantity.$dirty && itemForm.quantity.$invalid">
 <span ng-show="itemForm.quantity.$error.required">Quantity cannot be blank</span>
 <span ng-show="itemForm.quantity.$error.pattern || itemForm.quantity.$error.min || itemForm.quantity.$error.max">Quantity should be an integer between 1 and 90</span>
</div>

Carefully examine the ng-show directives applied on the div and span elements. The pattern of each condition is in every ng-show directive is:

<form-name>.<element-name>.$error.<type-of-validation>

If there are multiple conditions for one error message, they have to be combined using AND(&&) or OR(||) depending upon the need.

The complete sample is available at the following jsfiddle:



Further learning:

Happy coding!

Saturday, 16 February 2013

Modules in Angular JS

Angular JS supports modules, using which we can divide the JavaScript code involved in our application. Creating modules not only helps separating the code into individual concerns but also improves unit-testability. The modules can be easily replaced by some mocks while unit testing Angular controllers.

Following is the syntax of creating and registering a module:

angular.module(‘module-name’,[dependencies]);

Every module should have a name, which is specified in the first parameter. Second parameter to module function is an array, which may contain names of other modules or services. If the module doesn’t depend on anything, the array can be left blank.

To a module, we can add services, filters, directives, constants, configuration blocks and run blocks. In large applications, it is recommended to add each of these to separate modules. A typical module with all of these blocks added looks like the following:

angular.module(‘module-name’,[dependencies])
 .value(‘service-name’,{
  //properties and functions to be added to the service
         }).
         filter(‘filter-name’,{
         //definition of filter
         }).
         directive(‘directive-name’,function(parameters){
         //directive definition
         }).
         constant(‘constant-name’,object).
         config(function(injectables){
         //configurations to be applied
         }).
         run(function(injectables){
         //code to kick-start the application
         });

In last two posts, we created a shopping cart with functionalities to add and remove items, calculate total price, sort and filter data present in the cart array. Since controller should play the role of mediator, let’s separate data of shopping cart and operations into a separate module and call these functions from controller wherever we need the functionality to be executed. Following is the module that holds data and performs required operations on the data:
angular.module('shopping',[])
   .value('shopping_cart_operations',{
    items : [
     {Name: "Soap", Price: "25", Quantity: "10"},
     {Name: "Shaving cream", Price: "50", Quantity: "15"},
     {Name: "Shampoo", Price: "100", Quantity: "5"}
     ],

    addItem: function(item){
     this.items.push(item);
    },

    totalPrice: function(){
     var total = 0;
     for(count=0;count<this.items.length;count++){
      total += this.items[count].Price*this.items[count].Quantity;
     }
     return total;
    },

    removeItem: function(index){
     this.items.splice(index,1);
    } 
   });

As controller requires the functions defined in the service shopping_cart_service, it has to be passed as a dependency to the controller. The dependency will be automatically resolved at the run-time from the module.

Angular makes heavy usage of Dependency Injection. As we have already discussed in first post, $scope is a mandatory parameter to the controller, but we didn’t discuss about from where it gets its behaviour. It is a service defined in the library and gets injected into the controller when we refer to it by its exact name. To refer it using some other name, we have to assign the modified names to $inject property in the same sequence in which they have to be passed into the function.

MyController.$inject = [‘$scope’, ‘any_other_service’];

After this, we can define the controller as follows:
function MyController(myScope,otherService){
 //Controller body
}
Here, myScope and otherService will hold the values of $scope and any_other_service respectively. To learn more on dependency injection on Angular JS, you can refer to the official website of Angular JS.

Let’s modify ShoppingCartCtrl to use the shopping module created above.

function ShoppingCartCtrl($scope,shopping_cart_operations)  {
 $scope.items = shopping_cart_operations.items;
 $scope.item = {};

 $scope.addItem = function(item) {
  shopping_cart_operations.addItem(item);
  $scope.item = {}; //clear out item object
 };
    
 $scope.totalPrice = shopping_cart_operations.totalPrice;
  
 $scope.removeItem = function(index){
  shopping_cart_operations.removeItem(index);
 };
  
 $scope.mySortFunction = function(item) {
  if(isNaN(item[$scope.sortExpression]))
   return item[$scope.sortExpression];
  return parseInt(item[$scope.sortExpression]);
 }
}

To make the application work as it used to earlier, we need to apply a small change to the HTML. Name of the module has to be assigned to the ng-app directive. Modify the ng-app declaration in the div element to:
<div ng-app="shopping">
....
</div>

Let’s create a simple filter to display price in rupee format and add it to the above module. Following is the code of the filter:
angular.module(‘shopping’,[])
 .value(…)
 .filter(‘rupee’, function(){
  return function(item){
   return "Rs. "+item+".00";
  }
 });

Using this filter is similar to using currency filter.
<td>{{item.Price | rupee}}</td>

This sample is available on jsfiddle:

Happy coding!

Friday, 8 February 2013

Filtering and Sorting data using Angular JS

In last post, we saw how Angular JS helps us in two-way data binding. As I mentioned earlier, Angular JS offers much more than just data binding. We will explore the filtering and sorting features offered by Angular JS.

Angular has a set of filters defined to display data to the user in certain format. We can create our own filters if we are not happy with any of the existing filter. Check Angular’s official developer guide to know more about what filters offer. In this post we will see the usage of some of the built-in filters.

I continue with the same data as I used in the last post. Here is the Angular JS controller with data that we will use in this post. We will add some members to the controller later in the post:

function ShoppingCartCtrl($scope)  {
  $scope.items = [
   {Name: "Soap", Price: "25", Quantity: "10"},
   {Name: "Shaving cream", Price: "50", Quantity: "15"},
   {Name: "Shampoo", Price: "100", Quantity: "5"}
  ];
}

Filtering
Data in an array can be filtered using Angular JS in two ways.

In one approach, we can filter data irrespective of the attributes. The filter is applied across the data in an array. Following markup shows it:

Search: <input type="text" ng-model="searchText" />

<table border="1">
 <thead>
  <tr>
   <th>Name</th>
   <th>Price</th>
   <th>Quantity</th>
  </tr>
 </thead>
 <tbody>
  <tr ng-repeat="item in items | filter:searchText">
   <td>{{item.Name}}</td>
   <td>{{item.Price}}</td>
   <td>{{item.Quantity}}</td>
  </tr>
 </tbody>
</table>

 Initially, the table will display all items present in the items array. As we type some text in the text box, data in the array will be filtered based on the entered text and the filtered data will immediately appear on the list.

As you observe, we didn’t ask Angular to filter data based on a property. This is a general filter. It is applied across the properties.

To filter data based on a property, we have to make some changes to the filter specified above. Following markup segment shows how to do it:

Search by any: <input type="text" ng-model="search.$" />

Search by name: <input type="text" ng-model="search.Name" />

<table border="1">
    <thead>
     <tr>
      <th>Name</th>
      <th>Price</th>
      <th>Quantity</th>
     </tr>
    </thead>
    <tbody>
     <tr ng-repeat="item in items | filter:search">
      <td>{{item.Name}}</td>
      <td>{{item.Price}}</td>
      <td>{{item.Quantity}}</td>
     </tr>
    </tbody>
   </table>

Text entered in the first text box will be used to filter data irrespective of property; it behaves just as our previous case. But the text entered in the second text box will be used to filter data by name alone.

Since price is a dollar amount, we can display the value with a dollar symbol using currency filter.

<td>{{item.Price | currency}}</td>


Sorting
Data in an array can be sorted based on values of a property. We can do it using the orderBy filter.

Let’s add a drop down list to the above sample and sort data based on the selected property. Following markup demonstrated this:

<div>Sort by: 
        <select ng-model=&quot;sortExpression&quot;>
  <option value="Name">Name</option>
  <option value="Price">Price</option>
  <option value="Quantity">Quantity</option>
 </select>
</div>
<table border="1">
 <thead>
  <tr>
   <th>Name</th>
   <th>Price</th>
   <th>Quantity</th>
  </tr>
 </thead>
 <tbody>
  <tr ng-repeat="item in items | orderBy:sortExpression | filter:search">
   <td>{{item.Name}}</td>
   <td>{{item.Price | currency}}</td>
   <td>{{item.Quantity}}</td>
  </tr>
 </tbody>
</table>

As soon as a property is selected from drop-down, you will see the data in the table displayed is sorted according to that property. Observe the sorting pattern of numeric columns (Price and Quantity). They are sorted like strings, not like numbers. This is the default behaviour of the orderBy filter, as mentioned in the documentation.

This behaviour can be overridden by defining a function. If we return value in the form of integer from this function, orderBy filter will apply numeric sorting. Following function can be used to sort string and integer type values. It has to be added to controller:

$scope.mySortFunction = function(item) {
 if(isNaN(item[$scope.sortExpression]))
  return item[$scope.sortExpression];
 return parseInt(item[$scope.sortExpression]);
}

Replace sortExpression of orderBy filter with mySortFunction to sort Price and Quantity as numbers.
<tr ng-repeat="item in items | orderBy:mySortFunction | filter:search">

The mySortFunction checks if the value passed is a number. If it is not a number, it returns the value as is. Otherwise, it parses the value as integer and returns the value.

You can play with the sample on jsfiddle:
Happy coding!

Friday, 1 February 2013

Easy two-way data binding in HTML pages with Angular JS

The world is gradually drifting from heavy server logic to heavy client logic for web applications. We see a number of client side libraries being released for different purposes almost every day. These libraries help front-end web developers to make their applications rich.

Most of the times, we spend time in creating data driven applications, such as shopping cart, accounts management, exploring items like books, audio or video. Data binding becomes primary responsibility for a developer working on such applications. To exploit data binding on client side, we have several libraries like Angular, Knockout, Backbone, and Ember to make our work easier. These libraries also help us to write clean JavaScript code using one of MV* patterns.

Lately, I started exploring Angular JS. It is a great library. Though this post explains about data binding, Angular JS is capable of doing a lot more. Following is a list of features supported by Angular JS:

  • Data Binding
  • Data Templates
  • Filtering and Sorting
  • Validation
  • Support for AJAX
  • History
  • Routing
  • Modular components
  • Dependency injection
  • Encourages separation and testability

Because of these features, Angular JS makes client side development very easier.

Structure of an application using Angular JS
An application using Angular JS must have following components:

  • Reference to Angular JS library
  • A JavaScript controller containing data or with logic to fetch data

We have to add the ng-app declaration to a portion of the page that uses features of Angular JS. It can be added to a div inside a page wherein we have to use some expressions of Angular JS. If it is needed for the entire page, we have to add the ng-app declaration to the body tag.
<div ng-app>
 <!-- Your markup goes here -->
</div>

A demo showing some data binding features of Angular JS
Let’s create a shopping cart. We will add the features to calculate total price of the cart, adding items to cart and removing items from cart. We have to add this logic to the controller. An Angular JS controller must follow the following conventions:

  • It should be a JavaScript function accepting an argument named $scope
  • All of the model variables and functions should be added to the $scope object
  • Controllers are usually suffixed with Ctrl, but it is not necessary

Following is the controller with the required functionalities added:
function ShoppingCartCtrl($scope)  {
    $scope.items = [
        {Name: "Soap", Price: "25", Quantity: "10"},
        {Name: "Shaving cream", Price: "50", Quantity: "15"},
        {Name: "Shampoo", Price: "100", Quantity: "5"}
    ];

    $scope.addItem = function(item) {
        $scope.items.push(item);
 $scope.item = {};
    }
    
    $scope.totalPrice = function(){
        var total = 0;
 for(count=0;count<$scope.items.length;count++){
     total += $scope.items[count].Price*$scope.items[count].Quantity;
 }
 return total;
    }
  
    $scope.removeItem = function(index){
        $scope.items.splice(index,1);
    }
}

To bind data using members of the controller, we have to specify the controller using ng-controller directive. Ensure that the element containing ng-controller directive is a child of an element declared as ng-app.
<div ng-app>
 <div ng-controller="ShoppingCartCtrl">
  <!-- Your markup goes here -->
</div>
</div>

Let’s display the items added to items array in a table. Let’s also add a button on each row to remove the item. We have to use the following blocks to achieve this:

  • ng-repeat directive to iterate through items
  • Binding controller’s properties using {{}}
  • ng-click directive to bind button click event
  • $index to use current index in an array

Following is the table displaying items:

<table border="1">
    <thead>
 <tr>
  <td>Name</td>
  <td>Price</td>
  <td>Quantity</td>
                <td>Remove Item</td>
 </tr>
    </thead>
    <tbody>
 <tr ng-repeat="item in items">
  <td>{{item.Name}}</td>
  <td>{{item.Price}}</td>
  <td>{{item.Quantity}}</td>
  <td><input type="button" value="Remove" ng-click="removeItem($index)" /></td>
 </tr>
    </tbody>
</table>

Let’s display the total price of cart below this table. For this, we need to call the totalPrice() function of controller.
<div>Total Price: {{totalPrice()}}</div>

Finally, let’s add a form to accept values from user and add the new item to items array. We have to use ng-model directive to automatically add an input field to a property of the controller. Following is the form:
<table>
 <tr>
  <td>Name: </td>
  <td><input type="text" ng-model="item.Name" /></td>
 </tr>
 <tr>
  <td>Price: </td>
  <td><input type="text" ng-model="item.Price" /></td>
 </tr>
 <tr>
  <td>Quantity: </td>
  <td><input type="text" ng-model="item.Quantity" /></td>
 </tr>
 <tr>
  <td colspan="2"><input type="Button" value="Add" ng-click="addItem(item)" /> </td>
     
 </tr>
</table>

When we enter something in the text boxes, a property named item is automatically added to $scope. This property is used in the addItem function.

You can play with the sample using the following jsfiddle:



Try removing some items from the table and observe that totalPrice is updated immediately. It also happens when an item is added to the array as well.

As we saw, two-way data binding is made very easy using directives and binding syntax of Angular JS. All we need is a controller with some members in it. We don’t need to invoke any special functions to send notification when something changes in the controller. Everything is available for free to us, all we need to do is follow the conventions.

We will explore other features of Angular JS in future posts.

Happy coding!

Sunday, 20 January 2013

Method overloading in TypeScript

TypeScript is observed as an object oriented language. Because of which we expect it to behave just like any other object oriented program out there. One of the key features of any object oriented language is method overloading. The way TypeScript supports this feature is a bit different.

In TypeScript, we cannot create multiple methods with same name in a class. If we attempt to do it, we get an error saying Duplicate identifier <Method name>. It happens even if the methods are defined by following all the rules of method overloading.

The way to achieve method overloading in TypeScript is we have to define a method with highest parameters and declare the other methods. Following sample demonstrates it:

class MyClass
{
 Display(num?: number,name?: string){
  document.write("x is: "+num.toString()+" and y is: "+name);
 }
 Display(num: number);
 Display(name: string);
 Display();
}

As we see, we have defined a Display method with two null able parameters and declared three Display methods with one or no parameters. This code compiles to following JavaScript:
var MyClass = (function () {
    function MyClass() { }
    MyClass.prototype.Display = function (num, name) {
        document.write("x is: " + num.toString() + " and y is: " + name);
    };
    return MyClass;
})();

Yes, there is just one function named Display. Because, a JavaScript function can be called passing all or less number of parameters. This applies to constructor as well.
class MyClass
{
 num: number;
 name: string;
 
 constructor(x?: number,str?: string){
  this.num=x;
  this.name=str;
 }
 constructor(x: number);
 constructor(str: string);
 constructor();
}

This compiles to:
var MyClass = (function () {
    function MyClass(x, str) {
        this.num = x;
        this.name = str;
    }
    return MyClass;
})();

It is important to note that the parameters that have to be omitted in overloads should be marked as nullable in the concrete method. Otherwise, the parameter becomes mandatory and TypeScript compiler reports an error.

Happy coding!

Thursday, 27 December 2012

Friendly URLs in ASP.NET 4.5 Web Forms


In the recent update of ASP.NET, Microsoft released support for Friendly URLs in ASP.NET Web Forms. It is based on the concept of Routing. But, we don’t need to deal with route table to manually add the routes to be mapped. URLs of the site will be automatically made friendly after invoking when the application starts.

To get started using the Friendly URLs, we need to install the NuGet Package Microsoft.AspNet.FriendlyUrls. The package is not stable yet, so we need to search it in pre-release packages.
























This package adds following files to the web application:
  • Microsoft.AspNet.FriendlyUrls assembly – Contains required set of classes and interfaces
  • Site.Mobile.Master – Master page for mobile devices
  • ViewSwitcher.ascx – A user control that can be used to switch views from desktop view to Mobile view and vice versa
Once Visual Studio finishes installing the NuGet package, a read me file will be popped up. This file contains the steps to be followed to enable Friendly URLs on your site. All you have to do is, call the EnableFriendlyUrls extension method of RouteTable in RegisterRoutes method of RouteConfig class. This method is defined in Microsoft.AspNet.FriendlyUrls namespace.
routes.EnableFriendlyUrls();

And make sure that the RegisterRoutes method is called in Application_Start event of Global.asax:
RouteConfig.RegisterRoutes(RouteTable.Routes);

Now run the application and check URL on the address bar of your browser.































And the magic happened! As we see here, the URL doesn’t contain extension of the page.

Note: You don’t have to install NuGet package and apply the above settings if you have installed ASP.NET and Web Tools 2012.2. These changes are built into the ASP.NET web application template in the new template.

If you are using default ASP.NET 4.5 Web application template, you can invoke the Login (which resides in Account folder) page using:

http://mysite/Account/Login

You can link any page that resides in a folder using the same convention.

Hyperlinks to the pages can be replaced with the friendly convention.

<a id="loginLink" runat="server" href="~/Account/Login">Log in</a>

Data can be passed to a page using segments. Href method of FriendlyUrl class can be used for this purpose:
<a href="<%: FriendlyUrl.Href("~/BookDetails","AspNet") %>">ASP.NET</a>

This hyperlink forms the following URL:

http://mysite/BookDetails/AspNet

This data can be displayed on the page in any mark-up element. To display the topic of book sent through the above URL in a span element, we have to get the value from the segment as shown below:

<span><%: Request.GetFriendlyUrlSegments()[0].ToString() %></span>

Also, this value can be passed as a parameter to a method used for Model Binding as shown below:
public IQueryable<Customer> GetBooks([FriendlyUrlSegments]string topic)
{
    var selectedBooks = context.Books.Where(c => c.BookName.Contains(topic));
    return selectedBooks;
}

Remember that, if you are navigating to the page ListBooks.aspx with following URL,

http://mysite/ListBooks/Book/AspNet

then the parameter marked with FriendlyUrlSegments will hold the value Book/AspNet. So, this should be handled with care.

You can also create mobile friendly pages and even pages specific to certain type of device using Friendly URLs. Check Scott Hanselman’s great post on Introducing ASP.NET FriendlyUrls - cleaner URLs, easier Routing, and Mobile Views for ASP.NET Web Forms to learn more
about Friendly URLs and mobile pages.

Happy coding!

Sunday, 23 December 2012

Basics: Routing in ASP.NET Web forms

Many of our friends think that Routing is a feature of ASP.NET MVC and cannot be used with ASP.NET web forms. But the fact is that, Routing is a part of ASP.NET core. It is added to the core in ASP.NET 3.5 SP1. In ASP.NET 4.0, routing is made more developer friendly. So, anything that falls under ASP.NET family can use routing.

Using routing in ASP.NET Web Forms, we can generate URLs that don’t correspond to the physical file. Server will reach the physical file to be rendered using the parameters passed with route URL. Defining pretty URLs makes the pages easily searchable by the search engines.


Using Routing with ASP.NET Web forms

To use routing in an ASP.NET Web Forms application, we have to register the routes when the application starts. This means, the routes have to be registered to System.Web.Routing.RouteTable.Routes collection in the Application_Start event of Global.asax. There are several overloads of MapPageRoute method in RouteCollection, but we usually use the following overload:

public Route MapPageRoute(string routeName, string routeUrl, string physicalFile);

Following is an example of registering a simple route which can be used to hide extension of aspx forms:
routes.MapPageRoute("basic-route", "{page}", "~/{page}.aspx");

Once this route is registered, we can safely replace the URL

http://mysite/Page.aspx

with the following URL:

http://mysite/Page

But, this route doesn’t work if we have some pages in a folder. For example, suppose the web application has a folder named Account and this folder has the forms Login.aspx and Register.aspx, we would expect the page Login.aspx to respond when we hit the URL

http://mysite/Account/Login

But, it doesn’t work as we didn’t define a route for it. We have to add the following route to the route table to make this URL work as we expected:

routes.MapPageRoute("folder-route", "{folder}/{Page}", "~/{folder}/{Page}.aspx");

Now a question arises that, do we need to hard-code the routed URLs in hyperlinks? The answer is no. We can refer to the registered routes by their names and provide values to the route parameters to get the URL generated for us. Following HyperLink generates the URL to Login page we discussed above:
<asp:HyperLink ID="hlLogin" Text="Login" NavigateUrl="<%$ RouteUrl:RouteName=folder-route,folder=Account,page=Login %>" runat="server" />

We can also pass input parameters to a page using route parameters. For example, if we have a page named Book.aspx that lists a set of books on a particular topic and the topic is passed using QueryString to the page as shown below,

http://mysite/Book.aspx?topic=JavaScript

We can avoid usage of QueryString and make the URL prettier as shown below

http://mysite/Book/JavaScript

To achieve this we have to add the following route to the RouteCollection:

routes.MapPageRoute("book", "Book/{BookName}", "~/Book.aspx");

The route value passed to this page can be accessed from both aspx mark-up and from code behind file. Following mark-up demonstrates displaying mark-up value on a label:
<asp:Label ID="lblBookName" Text="<%$ RouteValue:BookName %>" runat="server" />

Following code snippet shows accessing the route value from code behind file:
var bookName = Page.RouteData.Values["BookName"].ToString();

This value can be used to query database or any other type of further processing.

Further learning:
http://msdn.microsoft.com/en-us/magazine/dd347546.aspx 
http://weblogs.asp.net/scottgu/archive/2009/10/13/url-routing-with-asp-net-4-web-forms-vs-2010-and-net-4-0-series.aspx
http://haacked.com/archive/2008/03/11/using-routing-with-webforms.aspx


Happy coding!

Monday, 17 December 2012

A Real-time chart using SignalR and Flot

I have discussed about SignalR in some of my earlier posts. I lately found Flot, a jQuery plugin that makes it very easy to create charts on HTML pages without doing a lot of work. Since both SignalR and Flot are based on jQuery at the client end, they work well together. In this post, we will see how to create a chart showing price of a stock that changes every second.


On Server Side

As we are using SignalR, we need a hub class. To represent a stock value object, we need a class with a couple of properties in it. Following is the StockValue class that we will use to send data to client:
public class StockValue
{
    public int Time { get; set; }
    public double Price { get; set; }
}

For this solution, I have used Visual Studio 2012 and SignalR 1.0 RC. There are a number of changes made to SignalR in this version. Following are the changes that we will be using in this post:

Calling a client function from Server: Clients.All.functionName(data);
Calling a server function from client: proxy.server.functionName(data);
Defining a JavaScript client function: proxy.client.functionName(data);

We need a StockMarket class that does the following tasks:

  • Initializes stock values
  • Updates the stock values after certain period
  • Sends the updated data to all clients
Code of this class is as follows:
public class StockMarket
    {
        public static readonly Lazy<StockMarket> market = new Lazy<StockMarket>(() => new StockMarket());
        static List<StockValue> stockValues;
        Timer _timer;
 
        public static StockMarket Instance
        {
            get
            {
                return market.Value;
            }
        }
 
        public void InitializeStockvalues()
        {
            stockValues = new List<StockValue>()
                {
                    new StockValue(){Time=10,Price=10.4},
                    new StockValue(){Time=20,Price=10.5},
                    new StockValue(){Time=30,Price=10.2},
                    new StockValue(){Time=40,Price=10.5}
                };
            GetClients().All.drawChart(stockValues);
        }
 
        public void GenerateNextStockValue(object state)
        {
            Random randomGenerator = new Random();
            int changeInCost = randomGenerator.Next(100, 110);
 
            var lastStockValue = stockValues[stockValues.Count - 1];
            var nextStockValue = new StockValue();
            nextStockValue.Time = lastStockValue.Time + 10;
            nextStockValue.Price = changeInCost / 10.0;
 
            stockValues.Add(nextStockValue);
 
            GetClients().All.drawChart(stockValues);
        }
 
        public void PublishPrices()
        {
            if (stockValues == null)
            {
                InitializeStockvalues();
            }
            else
            {
                GenerateNextStockValue(null);
            }
            _timer = new Timer(GenerateNextStockValue, null, 1000, 1000);
        }
 
        public IHubConnectionContext GetClients()
        {
            return GlobalHost.ConnectionManager.GetHubContext<StockValuesHub>().Clients;
        }
    }

Finally, we need a Hub class to kick off the process on the server. The hub class is very simple as we have assigned most of the responsibilities to StockMarket class.
public class StockValuesHub : Hub
    {
        public void GetStockValues()
        {
            StockMarket.Instance.PublishPrices();
        }
    }


On Client Side

On the client HTML page, we need to add references to following JavaScript libraries:
  • jQuery library
  • SignalR jQuery library
  • Flot jQuery library
  • Reference to SignalR’s dynamic proxy library

Flot requires a div element to render chart. So, let’s add the following div element to our page:

<div id="canvasChart" style="height: 300px; width: 300px;"></div>

On page load, we need to invoke the GetStockValues() function to start the process.
var hub = $.connection.stockValuesHub;
var dataToChart = [];
 
$.connection.hub.start()
    .done(function () {
        hub.server.getStockValues();
     });

We need to define the drawChart function on client to consume the data sent by server and render the chart. It involves a bit of logic as Flot doesn’t operate on JSON data. We need to convert our data to a form that Flot understands.

Flot accepts values in the form of an array. In the API documentation of Flot, it is specified that, Flot accepts values in the form of an array of a series. Following is an example of the data to be passed into Flot (copied from API documentation):

[ [1, 3], [2, 14.01], [3.5, 3.14] ]

Since SignalR sends JSON data, we need to convert the data to above format before we render the chart. Each object in the collection has to be converted to an array with two elements. Following function does this job for us:

function convertToArray(data) {
    var dataArray = [];
    dataArray.push(data.Time);
    dataArray.push(data.Price);
    return dataArray;
}

Finally, let’s add the drawChart function to client proxy. Implementation of this function is pretty straight forward.
hub.client.drawChart = function (data) {
    if (dataToChart.length == 0) {
        $.each(data, function () {
            dataToChart.push(convertToArray(this));
        });
    }
    else {
        dataToChart.push(convertToArray(data[data.length - 1]));
    }
    $.plot($("#canvasChart"), [dataToChart]);
};


You can download the complete code here.

Happy Coding!

Tuesday, 4 December 2012

Bouncing a ball on HTML5 Canvas

Canvas provides a nice interface to draw anything on it. Canvas doesn’t support animations by default, but as we write JavaScript to do anything on canvas, we can create animations too. Let’s see how we can create a basic animation to bounce a ball inside boundaries of canvas.

Let’s create a ball on the canvas. We can do it by drawing a circle and filling some color inside it. Following code shows how to do it:
function draw(){
    context.beginPath();
    context.fillStyle="green";
    context.arc(10,10,20,0,Math.PI*2,true);
    context.closePath();
    context.fill();
}
Since we have to move the ball on canvas, we may say that we have to draw the ball over and over at different positions. Before drawing the ball at next position, we must clear the ball already drawn. And this logic has to be repeated after certain time.

Let’s modify the draw function defined above to draw the ball at different positions. The logic involves:
  • Clearing the canvas
  • Drawing the ball at a position
  • Calculating next position to draw the ball

Below code implements this logic:
function draw()
{
    context.clearRect(0,0,300,300);
    context.beginPath();
    context.fillStyle="green";
    context.arc(x,y,20,0,Math.PI*2,true);
    context.closePath();
    context.fill();  
    
    if(x+xShift > width || x+xShift < 0)
        xShift=0-xShift;
    if(y+yShift > height || y+yShift < 0)
        yShift=0-yShift;
    
    x+=xShift;
    y+=yShift;
}
On page load, we can use setInterval function to call draw function after certain interval.
setInterval(draw,20);



Happy coding!