Filtering .NET 3.5 returned JSON with jQuery

In .NET 3.5, when a Web service class is decorated with “ScriptService” attribute, the web service returns data in JSON format [MSDN]. I have demonstrated this with a simple example in the article, Passing JSON objects in .NET 3.5.

Let us consider that our “person” class has several properties, of which only few are useful on the client side for data binding. We can filter this object in two ways:

1. On the server side:- Create a dictionary object [System.Collections.Generic.Dictionary(Of TKey, TValue)], add the desired properties to dictionary object and return it.

2. On the client side:- In cases where a quick filter has to be done without touching server side code, we can use jQuery’s each function to create a custom JSON object.

Suppose you want to filter only “country” and “code” out of the below JSON data,

var players = 
[{ "country": "India", "code": "Ind", "name": "Sachin" },
{ "country": "Sri Lanka", "code": "SL", "name": "Murali" },
{ "country": "Australia", "code": "Aus", "name": "Shane" },
{ "country": "West Indies", "code": "WI", "name": "Lara"}];

you can simply write the below jQuery code:

var newObject = {}; //Creating a new object
$.each(players, function() { //Looping through our players array using jQuery's each function
    newObject[this.country] = this.code; //Creating our custom "name/value" pair
});

So, our newObject will contain new data(having only “country” and “code”). If you want to access country code, you can simply say “newObject.India”, which gives “Ind”.

This tip is particularly useful in cases like filling dropdown lists with JSON data. By default, the server’s JSON data contains several properties which are not required. In such cases, this client side filter comes as a handy tip :)

Customizing jQuery plugins for "d parameter" in .NET 3.5 JSON response.

I was trying to use jqGrid, an excellent jQuery based grid, for building a zero postback page. It's configuration is very simple, similar to flexigrid, but has many additional features like inline editing, subgrids etc.

What jqGrid expects is a JSON response having few objects and arrays, which are mapped to columns in the grid inside the grid.base.js file, like this.

Though the grid's AJAX call is successful, data is not being bound to thegrid. The reason is, .NET 3.5 returns JSON object which is prefixed with a "d" parameter like this.

So, to map the JSON data to the grid, we have to manually parse the AJAX response and separate the "d" parameter in AJAX success callback. This applies not only to jqGrid, but also to all jQuery plugins which expect JSON response.

I was about to write more on why .Net 3.5 prefixes "d" to JSON response, how it enhances security and how to parse it easily., but incidentally, Dave ward explained the concept excellently in his latest article: http://encosia.com/2009/06/29/never-worry-about-asp-net-ajaxs-d-again

So no more worrying about .Net's "d" again :)

Passing JSON objects in .NET 3.5

In my previous post, I have explained how to pass complex types using jQuery and JayRock in .NET 2.0 framework. I was digging a bit into Dave’s example (using complex types to make calling services less complex) in .NET 3.5 framework, to find how easier JSON serilaization/deserialization can be made.

When a Web service class is decorated with “ScriptService” attribute, which is in the System.Web.Script.Services namespace in .NET 3.5, the web service returns data in JSON format [MSDN]. Whether the returned value is a string or an object, it will be in JSON format. So no need of writing chunks of code for serializing objects explicitly.

Therefore, all that we need to do is to simply decorate our web service class with “ScriptService” attribute and  return an object from the server. So, to create a JSON object like this:

{"d":{"FirstName":"Krishna","LastName":"Chaitanya","City":"Hyd","State"
:"Andhra","Country":"India"}}

We can simply return a person object like this:

<WebMethod()> _
    Public Function fnFetchDetailsClass() As Person
        Dim objPerson As New Person
        Try
            objPerson.FirstName = "Krishna"
            objPerson.LastName = "Chaitanya"
            objPerson.City = "Hyd"
            objPerson.State = "Andhra"
            objPerson.Country = "India"
        Catch ex As Exception
 
        End Try
        Return objPerson
    End Function

In some situations (like in client side templating), we might need to create custom, complex JSON objects on the fly. In such situations, we can make use of .NET’s “ListDictionary” and “ArrayList” classes.

The above example can be re-written using ListDictionary as:

<WebMethod()> _
Public Function fnFetchDetails() As ListDictionary
    Dim jsonObj As New ListDictionary
    Try
        jsonObj.Item("fname") = "Krishna"
        jsonObj.Item("lname") = "Chaitanya"
        jsonObj.Item("city") = "Hyd"
        jsonObj.Item("state") = "Andhra"
        jsonObj.Item("country") = "India"
        Return jsonObj
    Catch ex As Exception
        jsonObj.Item("Error") = "Error at server"
        Return jsonObj
    End Try
End Function

Thus, using JSON is made easier in .NET 3.5.

Here is a simple demo which makes things clear. (I have used jQuery for making AJAX calls.)

(Note: ListDictionary stores values in Name/Value pairs, which is useful in building JSON Object. Similarly, an ArrayList can be used to build JSON Arrays. Therefore, these two can be used instead of JsonObject and JsonArray classes of Jayrock in my post Converting ASP.NET DataTable to JSON using JayRock.)

Passing complex types to service calls using jQuery & JayRock

Scenario: Consider a web form having several fields, whose values are to be submitted to the server through an AJAX call.

ComplexTypes

This can be easily achieved using jQuery’s $.ajax(), passing all the form elements (like first name, last name, city etc) as parameters to the AJAX call.

However, in reality, most of our web forms contain large number of input fields and hence the $.ajax() method will be overloaded with several parameters both at the client side as well as at the server side. This is cumbersome and is not a good programming practice.

Solution: The best practice in this scenario is to build a Data Transfer Object (DTO) on the client side and pass it to the server. This is what Dave Ward explained in his excellent article - “Using complex types to make calling services less… complex”.

If you are working on NET 3.5 framework, Dave’s article is the solution. In .NET 3.5, the System.Web.Script.Services Namespace can be imported, which makes webservices accessible in JavaScript. Also, it has the ability to accept JSON object from client side code and parse it at the server.

However, in .NET 2.0 framework, JSON object cannot be parsed inherently and hence have to use libraries like JayRock. Here is how you can achieve the same using JayRock. The difference is in the way how you pass your “data” parameter in ajax call.

$('#btnSubmit').click(function() {
 
        //Build JSON object by looping through all text boxes
        var objDetails = {};
        $('input[type=text]').each(function() {
            objDetails[this.name] = this.value;
        });
        
        //Stringify the JSON object using the below method from json2.js
        var jsObj = JSON.stringify(objDetails);
 
        //jQuery ajax call. Note the data parameter, which is different from normal ajax parameter.
        $.ajax({
            type: "POST",
            url: "CTypesHandler.ashx",
            data: "{'id':'1','method':'fnAjaxMethod','params':{'obj':" + jsObj + "}}",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: fnSuccess,
            error: function(xhr, status, errorThrown) {
                alert('Error' + errorThrown);
            }
        });
 
        function fnSuccess(response) {
            var obj = response.result.details;
            $('#divMessage').html(obj.FirstName + ' ' + obj.LastName + ' resides at ' + obj.City + ', ' + obj.State + ', ' + obj.Country);
        }
    });

Here is a simple demo. You can appreciate the demo if you can see how data is being requested and returned, in json format,  using firebug. (Few optimizations are yet to be done.)

Thanks to Praveen (my Technical Architect) for helping me with the concept. Thanks to Dave for replying to several of my queries.

Beware – jQuery unbind() vs removeAttr()

Here is a jQuery bug which suck few hours of my time:

  1. unbind() works only on events attached using jQuery.
  2. removeAttr() does not work on events added using jQuery

Confusing? Here is the scenario which explains better:

I have a server side asp button(btnTest), for which an “onclick” event is attached on page load (in code behind) like this:

btnTest.Attributes.Add("onclick", "fnTestMethod()")

Without changing server side code, I need to change the functionality of button click (reason: deployment issues). So my initial approach was simple -  To unbind the click event from my asp button using jQuery like this:

$('#btnTest').unbind("onclick"); 
But this didn’t work!

I was confused! I didn’t understand how page life cycle was impacting DOM. After wasting a couple of hours, I remembered the removeAttr() and tried it:

$('#btnTest').removeAttr("onclick"); 

and it worked!
On googling, I came to know that this is a bug in jQuery’s tracker and it doesn’t have a fix. You may find a detailed explanation of the bug here.

In short, the explanation says that:
* unbind() works only on events attached using jQuery’s functions like bind(), click() etc. It didn’t work for me as I was binding in my server side code like: btnTest.attributes.add().
* removeAttr() does not work on events added using jQuery.

Hence, if you want to change the click event but not sure if you have added it from code behind or jQuery, write a safer code like this as suggested in the bug tracker:

$("#btnTest").removeAttr("onclick").unbind("click");

Mentioning about the bug here so that readers may not waste their time in similar scenarios. I still love jQuery a lotttt!!! :)

NovoGeek.com!!

Restructured my site www.novogeek.net. Moved my technical blog from kris.novogeek.net to the root. Created a new subdomain - Labs.NovoGeek.Net for my little experiments. Placed only few important demos as of now. Will slowly move all my silly/stupid code snippets there :)

Update(11th May, 2009): Purchased the domain "NovoGeek.com". It was parked by someone till recently and I could get it last night :)
Configured Domain Forwarding to novogeek.net. So all existing URL's to novogeek.net will work the same with novogeek.com :) 

 Update(24th May, 2009): Redirected my .net domain to .com domain. Now my site's actual address is novogeek.com :)

Converting ASP.NET DataTable to JSON using JayRock

Beginners using jQuery plugins and jQuery AJAX with ASP.NET get stuck with one common problem-converting datatable to JSON. This conversion is necessary since JSON can be easily parsed in JavaScript and also most plugins expect data in JSON format, though that can be altered.

On googling, I found that .Net 3.5 has inbuilt support for this, but learnt from my Tech Arch (Mr.Praveen Reddy) that for .NET 2.0, the simplest solution is to use JayRock. The concept is very simple. Just loop through all rows, all columns of your datatable and add them to JSON arrays, objects.

Download JayRock and add Json.dll to your project’s references and go ahead with the below code (C# lovers may use this utility to convert the below code from VB.NET to C#):

'Import Jayrock.Json namespace, which is defined in json.dll
Imports Jayrock.Json 
 
'Write the below code in your specific events/methods
Dim rowIndex As Integer = 0 
Dim jRowArray As New JsonArray
Dim jTable As New JsonObject
 
If ds.Tables(0).Rows.Count > 0 Then
    'Loop through all the rows of datatable.              
    For Each row As DataRow In ds.Tables(0).Rows         
        Dim colIndex As Integer = 0
        'Create a new JSON array using JayRock 
        Dim jColArray As New JsonArray
        'Create a new JSON object               
        Dim jRowObj As New JsonObject               
        'Loop through all the cells of a row               
        For Each col As DataColumn In ds.Tables(0).Columns  
        'Add the value of each cell of a row to a JSON Array (jColArray)           
            jColArray.Add(row.Item(colIndex))               
            colIndex += 1        
        Next        
        'jColArray now contains data from all columns. Add this to a JSON object (jRowObj)       
        jRowObj("datarow") = jColArray                      
        rowIndex += 1        
        'Now add this JSON object to another JSON Array (jRowArray).    
        jRowArray.Add(jRowObj)                              
    Next 
End If 
jRowArray is the final JSON string, which can now be returned to your JavaScript.
The advantage of using JayRock is, you can customize what JSON data you want to return from the server. E.g., you may require to pass additional data to your JavaScript code such as refresh interval which may not be present in your datatable.
Click here to see the SQL data which will be filled in datatable.

Click here to see the JSON output (in Firebug) of the above data, taken from datatable.

Please share your thoughts. Thanks to Praveen for that! Happy Coding:)

Performance improvement in browsers-John Resig

A beautiful presentation given by John Resig, creator of jQuery, at Google. John covers the latest improvements in the modern browsers namely Firefox 3.1, Safari 4.0, Internet Explorer 8.0, Google Chrome and Opera 10. You can find the video presentation here @ Youtube and the pdf format of the presentation here @ Slideshare. A must see presentation for the modern web developer :)

How to use ASP .NET without Javascript?

In ASP.NET, we are used to drag/drop server controls and quickly finish the task, though we do not concentrate much on how they work. The problem arises when JavaScript is disabled in the user's browser, as some of these controls do not work.

Also, if you have rich AJAX features in your site, they will fail miserably if JavaScript is disabled in the browser. Ideally, your client expects the site to work even when JS is disabled in the browser.

Here are some of the ASP.NET server controls which which depend on client script for their functionality:

  • The LinkButton and HtmlButton server controls require JavaScript. (However, the Button Web server control, the HtmlInputButton or HtmlInputImage controls work fine.)

  • Any Web server control whose AutoPostBack property is set to true need client script so that the control will post the page to the server.

  • The Validation controls require client script to support client-side validation. If the client does not support script, validation will run on the server only.

  • Gridview pagination, sorting will not work. Custom pagination has to be used
How to detect if JavaScript is enabled in the browser or not? Check this excellent article at Boutell.com.

So, for the site to still work without JavaScript, use <noscript></noscript> tag, place server side buttons inside the tags and write your server side code in the button click events. These tags will be visible only when JavaScript is disabled. So you will not face any issues when JS is enabled.

An irritating scenario: You need a link button to do a server side task, but it doesn't wont work without javascript.

Work around: Apply styles to server side button and make it look like link button :p
Here is the CSS code you have to write (works fine in all major browsers):

.NewLinkButton
{
background-color:Transparent;
border-style: none;
color:Navy;
cursor: pointer;
display:inline-block;
font-style:normal;
text-align: left;
text-decoration:underline;
}

Please check the MSDN article: ASP.NET Web Server Controls that Use Client Script for more valuable info.

jQuery for absolute beginners.

I have given a KT (Knowledge Transfer) session on jQuery for my colleagues today. Instead of routine power point stuff, I made a jQuery based web page for presenting the content.

My friend and guru @ office, Mr.Praveen Reddy, guided me and shared really good demos, which are apt for beginners.

Here is the presentation.