OdeToCode IC Logo

Thoughts on AJAX Preview 4 and JSINQ

Saturday, February 7, 2009

ASP.NET AJAX 4.0 is adding client-side templates. You can bind data in the browser using declarative markup, imperative JavaScript code, or mix and match both approaches. The purely declarative approach looks like the following:

<body xmlns:sys="java script:Sys"
xmlns:dataview="java script:Sys.UI.DataView"
sys:activate="*">
    <ul id="departmentManagerList" 
            class="sys-template"
            sys:attach="dataview"
            dataview:serviceuri="DepartmentService.svc"
            dataview:query="GetAllDepartments">
        <li>{{ Manager.Name }}</li>
    </ul>

That code is everything you need to invoke an AJAX-enabled WCF service (specifically the GetAllDepartments method of DepartmentService.svc), and bind the results to a list. Some of the binding markup looks foreign inside the HTML, and when I read it a little voice in my head says: “JavaScript should be unobtrusive”. I reply and say “that is not JavaScript”, and the voice says “but it’s still ugly”. I have to agree, but there is an alternative we’ll look at in just a moment.

Anyone who has used XAML binding extensions for Silverlight or WPF will notice a number of similarities in the AJAX 4 bits. For example, both use curly braces inside the item template to denote the path to the source property for binding (in the above code we’re drilling into a department object and pulling out a manager’s name property). The AJAX libraries will take care of replicating the data inside of <li> tags. Also, there are similar binding modes (one way, two way, and one time), and the concept of an IValueConverter for each binding (ConvertFrom and ConvertBack functions can inject custom logic at bind time).

The AJAX 4 libraries support hierarchical data binding (for master detail scenarios) and can update a binding when the underlying data changes. However, this is one place where AJAX and XAML land differ. In XAML land we use INotify* interfaces to raise change events, whereas AJAX provides a Sys.Observable class that can “mixin” functions on a target object that allow you to ultimtaely catch property change notifications, but you must use Sys.Observable.setValue to see the notifications. Infinities Loop has the scoop on this behavior.

Imperative Code and JSINQ

Instead of purely declarative code, one can instantiate a DataView and write some JavaScript code to grab and process data. Since there doesn’t appear to be any pre or post request events we can hook from the DataView (which would be nice), this also gives us a chance to manipulate data from a web service before binding. The HTML will look cleaner:

<body>
    …    
    <ul id="departmentManagerList" class="sys-template">
        <li>{{ Manager.Name }}</li>
    </ul>

And we need to write a bit of code during load:

var view = $create(Sys.UI.DataView, {}, {}, {},
                  $get("departmentManagerList"));

var service = new DepartmentService();
service.GetAllDepartments(function(result) {
    view.set_data(filterAndSortDepartments(result));
});

What is filterAndSortDepartments? It’s a function that uses JSINQ – LINQ to objects for JavaScript.This isn't part of ASP.NET AJAX 4.0, but a CodePlex hosted project.

function filterAndSortDepartments(departments) {
    
    return new jsinq.Enumerable(departments)
                       .where(function(department) {
                         return department.Employees.length > 1;
                     }).orderBy(function(department) {
                         return department.Name;
                     }).toArray();
}

JSINQ has complete coverage of all the standard LINQ query operators, including join, group, groupJoin, any, all, and aggregate. The above code was written with the “extension method” syntax style, and rather makes me wish that JavaScript could take the lead from C# 3.0 lambda syntax and allow function definitions without keywords. JSINQ also offers comprehension query syntax:

function filterAndSortDepartments(departments) {
    var query = new jsinq.Query('\
                        from department in $0 \
                        where department.Employees.length > 1 \
                        orderby department.Name \
                        select department \
                    ');
    query.setValue(0, new jsinq.Enumerable(departments));
    return query.execute().toArray();
}

In this case the declarative code is easier on the eyes, but like most declarative code it’s impossible to debug if something goes wrong. There are lot’s of possibilities when using the combination of these two libraries. Give JSINQ a try in the JSINQ playground