Wednesday, September 12, 2012

Dealing with JSON format date

When working with web application and dealing with JSON formatted data, we may come across date types that are represented as /Date(1347490800000)/. The value between the parenthesis i.e. 1347490800000 indicates the number of milliseconds elapsed since 1st Jan 1970.

In order to show the date in human understandable format, we will have to construct the date object using these millisecond values. In JavaScript, this can be done as follows:

var myJSONDate = "/Date(1347490800000)/"; //For demonstration purpose but in realtime we will get from Ajax call returning data in JSON format
var value = new Date(parseInt(myJSONDate.replace(/\/Date\((.*?)\)\//gi, "$1")));

In the above method, we have used native JavaScript’s regular expression technique to get hold of the millisecond value stripping the /, Date and parenthesis characters. In JavaScript, the new date object by default starts from 1st Jan 1970.

Similarly, we will can construct the DateTime object in .NET from JSON date as follows:

var jsonDate = "/Date(1347490800000)/";
jsonDate = System.Text.RegularExpressions.Regex.Replace(jsonDate, @"/Date\((.*?)\)\/", "$1");
var date = new DateTime(1970, 1, 1, 0, 0, 0, 0).AddMilliseconds(long.Parse(jsonDate));

Hope this helps…

Wednesday, September 05, 2012

Knockout Model and Validating "inner" Models

More and more technologies, projects and products are basing their foundation on MVC and MVVM principles. The reason is that it makes the project or product to be maintained easily without much headache. The latest trend in client based web development is also shifting towards MVVM model and the tool that is getting most widely used is the Knockout javascript library. It’s a great tool that eases binding making even the complex javascript tasks to be designed pretty easily like for example dynamically rendering design for multiple contacts and collecting details, etc..,

Basic Knockout Model Validation

Validating a basic knockout model is a straight forward task. We just have to use the extend method on the observable attributes and set the necessary parameters. Consider the following model:

function ClientModel (id, firstName, lastName, email) {
        var self = this;
        self.Id = ko.observable(id);
        self.FirstName = ko.observable(firstName).extend({ required: true, maxLength: 50 });
        self.LastName = ko.observable(lastName).extend({ required: true, maxLength: 50 });
        self.Email = ko.observable(email).extend({ maxLength: 50, email: true });

        self.save = function () {
            if (self.errors().length != 0) { //verifying the errors attribute using the count of errors
                self.errors.showAllMessages(); //displaying the corresponding error messages
                return; //returning the control providing user a chance to correct the issues
            }

            $.ajax({
                type: "POST",
                url: "Save",
                data: ko.toJSON(self),
                contentType: 'application/json',
                success: function (mydata) {
                    alert("Success");
                },
                error: function (xhr, ajaxOptions, thrownError) {
                    alert("save method error status: " + xhr.status);
                    alert("save method error thrown: " + thrownError);
                }
            });
        };
};

$(document).ready(function () {
var clientModel = new ClientModel(1, "Hello", "World", "hell0@world.com");
clientModel.errors = ko.validation.group(clientModel); //setting up the errors attribute to the model to capture the validation error message
ko.applyBindings(clientModel);
});

The above is a basic model with validations added for the attributes using the extend method (More validation can be found here). The validation error messages are shown when the save method of the model is executed.

Deep Knockout Model Validation

Often we face situation where we will have a requirement for a complex model than the basic one. For example: our client may request us to design a solution to allow multiple contact numbers for a customer to be collected. In this case, the underlying model is changed as follows.

function Contact(id, phoneType, phone) {
        var self = this;
        self.ClientId = ko.observable(id);
        self.PhoneType = ko.observable(phoneType).extend({ required: true });
        self.Phone = ko.observable(phone).extend({ required: true });
};

function ClientModel (id, firstName, lastName, email, contacts) {
       var self = this;
       self.Id = ko.observable(id);
       self.FirstName = ko.observable(firstName).extend({ required: true, maxLength: 50 });
       self.LastName = ko.observable(lastName).extend({ required: true, maxLength: 50 });
       self.Email = ko.observable(email).extend({ maxLength: 50, email: true });

self.Contacts = ko.observableArray(ko.utils.arrayMap(contacts, function (aContact) { return aContact; }));

       self.save = function () {
            if (self.errors().length != 0) { //verifying the errors attribute using the count of errors
                self.errors.showAllMessages(); //displaying the corresponding error messages
                return; //returning the control providing user a chance to correct the issues
            }

            $.ajax({
                type: "POST",
                url: "Save",
                data: ko.toJSON(self),
                contentType: 'application/json',
                success: function (mydata) {
                    alert("Success");
                },
                error: function (xhr, ajaxOptions, thrownError) {
                    alert("save method error status: " + xhr.status);
                    alert("save method error thrown: " + thrownError);
                }
            });
       };
};

$(document).ready(function () {
       var contacts = { new Contact(1, "Home", "1234567890"), new Contact(1, "Work", "9876543210") };
var clientModel = new ClientModel(1, "Hello", "World", "hell0@world.com", contacts);
clientModel.errors = ko.validation.group(clientModel); //setting up the errors attribute to the model to capture the validation error message
ko.applyBindings(clientModel);
});

The above is a also a model with validations added for the attributes using the extend method. The validation error messages excepts the contacts will be displayed when the save method of the model is executed. The reason is that we have not made the validation “deep” so the inner validations are not executed. In order to achieve this, we will have to include the following Knockout initialization block:

ko.validation.init({grouping: { deep: true }, messagesOnModified: false });

Adding the above line of code should make the inner validations work in most cases. But if it still doesn’t work, then we will have to add the errors attribute to the Contact model just like we have added for the ClientModel. The below listing shows the updated Contact model with errors attribute added:

function Contact(id, phoneType, phone) {
        var self = this;
        self.ClientId = ko.observable(id);
        self.PhoneType = ko.observable(phoneType).extend({ required: true });
        self.Phone = ko.observable(phone).extend({ required: true });

self.errors = ko.validation.group(self); //setting up the errors attribute to the Contact model to capture the validation error message
};

Having added the errors attribute to the Contact model, we also need to update the save method of the ClientModel to verify the errors collection attribute and return if in case there are errors. The updated save method is listed below:

self.save = function () {
       var errorExists = false;

if (self.Contacts().errors().length != 0) { //verifying the errors attribute from the Contact model
              self.Contacts().errors.showAllMessages(); //displaying the corresponding error messages
              errorExists = true; //set error flag to stop further processing
       }

if (self.errors().length != 0) { //verifying the errors attribute using the count of errors
              self.errors.showAllMessages(); //displaying the corresponding error messages
              errorExists = true; //set error flag to stop further processing
       }

if (errorExists) {
              return; //returning the control providing user a chance to correct the issues
       }

      
       $.ajax({
              type: "POST",
              url: "Save",
              data: ko.toJSON(self),
              contentType: 'application/json',
              success: function (mydata) {
                     alert("Success");
              },
              error: function (xhr, ajaxOptions, thrownError) {
                     alert("save method error status: " + xhr.status);
                    alert("save method error thrown: " + thrownError);
              }
            });
};

From the above updated save method, all the errors corresponding to the main model (ClientModel) and the child model (Contact) will be displayed.
Hope this helps!!!