Examine

In my last post on ASP.NET AJAX 4.0, we took a look at the new DataView ASP.NET AJAX control. We saw that by using a DataView, we could easily bind data with JavaScript or declaratively with a few attributes. In this post, we’ll look at another feature of the ASP.NET 4.0 AJAX Library, the Observer design pattern for plain JavaScript objects. The pattern is implemented in the client side Sys.Observer class. This feature is used internally within the new version of ASP.NET AJAX for live-binding and the DataView control.

Here we will be using Preview 4 of the ASP.NET AJAX Library, which can be downloaded from CodePlex. Remember that these components are still in “preview” mode (meaning no Microsoft support), though they are usable at your own risk. For more information, you can check out the license on CodePlex. I highly recommend downloading the samples available for Preview 4, which are also available at CodePlex. The samples give you a good look at what is coming.

In this post, we’ll take a closer look at the Sys.Observer class, witness the problems it solves, and take a look at a few examples.

A Quick Look at JavaScript Objects

To this day, I still know developers who either don’t understand, don’t want to understand, or flat out loathe JavaScript. I suppose this really has to do with it being totally misunderstood, but in a Web 2.0 world, a web developer should embrace the language. Especially with wonderful frameworks like jQuery and the Microsoft AJAX Library  This section is a quick overview of JavaScript objects in case you aren’t familiar with them.

Objects in JavaScript can be described as hashtables, they are collections of names and values,  for example:

// An empty object
var person = {};
// Another way of defining an object
var person2 = new Object();
// Adding a name/value pair (a local variable)
person["firstName"] = 'Damien';
// You can also use the dot notation instead of subscript notation
person.lastName = 'White';
// And you can define objects using the object literal notation
var person = { firstName:'Damien', lastName:'White' };

This is by no means definitive. If you have JavaScript-phobia, you should start here.

The Object Modification Problem

Let’s say you have a simple object with a couple of properties. Note that JavaScript doesn’t have properties as we know them in .NET, they are just local variables like those defined on the person object in the previous code snippet, however there are conventions for emulating them with functions. Back to our simple object, let’s say that you need to be notified if the object changes. Take the following snippet, note I’m using the jQuery in order to simplify the code (e.g. append, and document ready).

var latestBlogPost = {
    name: 'ASP.NET 4.0 AJAX - Preview 4 - Client Templates',
    url: '/archive/2009/04/28/' +
         'ASP.NET-4-0-AJAX-Preview-4-Client-Templates.aspx'
}

// Displays the object
function displayLatestBlog() {
    var link = '<a href="' + latestBlogPost.url + '">' + latestBlogPost.name + '</a>';
    $('#latestBlog').empty().append(link);
}

// Show the latest blog post on document ready
$(function() {
    displayLatestBlog();}
);

Very simple example, I’m just displaying the link in a span (id = latestBlog) when the page loads. Now, let’s say that the latest latestBlogPost object changes.

After the change, the displayed latest blog post is now out of date. In this simple example it isn’t too big of a deal to handle this. However, there is a bigger question at large here, what if we wanted to know when the object changed? We could implement some logic in our latestBlogPost object in order to raise events when a property changes (such as is done in many of the ASP.NET AJAX Control Toolkit, by the way, have you checked out the latest version?). This works fine for something along the lines of a control, but it doesn’t make sense for just plain JavaScript objects. Imagine having to add get_ and set_ methods that raise an event each time they are changed for each variable in an object that is passed from the server via JSON. That is where the Sys.Observer class comes into play.

Observing Changes with Sys.Observer

The new Sys.Observer class is a solution to the problem that we defined in the last section. Let’s start by seeing how we would handle notification of object changes. I’ll be appending this code to the previous snippet.

// Make the object observable
Sys.Observer.makeObservable(latestBlogPost);
Sys.Observer.addPropertyChanged(latestBlogPost, displayLatestBlog);

// Change the Latest Blog Post using the Sys.Observer
function changeLatestBlogPost() {
    // Use beginUpdate to prevent changes from being reported until we are done.
    latestBlogPost.beginUpdate();

    // Set the properties in an observable way
    latestBlogPost.setValue('name', 'ASP.NET 4.0 AJAX - Preview 4 - JavaScript Observer Pattern');
    latestBlogPost.setValue('url', '/archive/2009/05/21/' +
        'ASP.NET-4-0-AJAX-Preview 4-JavaScript-Observer-Pattern.aspx');

    // Finish, now the listeners will get the update
    latestBlogPost.endUpdate();
}

I realize this is an extremely simple example, but it shows the basics behind how the Sys.Observer class works.

The first thing being done is making the object “observable.”  The makeObservable method adds the observable methods to it. You don’t need to call the  makeObservable method if you don’t want, but then you would need to call the fully qualified methods of the Sys.Observer class, for example (looking at the beginUpdate method call from the above snippet):

// We can call beginUpdate like this thanks to makeObservable
latestBlogPost.beginUpdate();

// Otherwise we would have to call it like this:
Sys.Observer.beginUpdate(latestBlogPost);

Personally, I think the makeObservable call makes the method calls a little cleaner, but the disadvantage is no IntelliSense on the “observable” object.

Back to the code snippet. In the second line, we are adding an event handler for the propertyChanged event using the addPropertyChanged method. This is all we need to do in order to register as a listener, our method (displayLatestBlog from the earlier code snippet) will be called each time a property on the object changes. Now every property change may be a bit overkill, thankfully we can control when the listener receives notification. In the first step in the changeLatestBlogPost() method, I’m doing just that, calling the beginUpdate Sys.Observer method delays notifications from being fired until we are done with our editing. In the next two lines, I’m using setValue in order to let the Sys.Observer know that this is a change that should be observed. Finally, a call to endUpdate will tell the Sys.Observer that it should now notify listeners of the changes to our object. Without the beginUpdate and endUpdate call, the Sys.Observer class would have sent notifications each time we called the setValue method.

Sys.Observer, JavaScript Arrays, and the DataView

Let’s look at something a little more exciting. Back in my post on the DataView, we looked at setting the DataView using a simple JavaScript array. Let’s revisit the example using the Sys.Observer class. Like the previous examples, I’ll be using just a standard HTML page, no ASP.NET server-side code. Being able to use the ASP.NET AJAX Library OUTSIDE of ASP.NET is often a point that developers seem to miss, so hopefully all of these HTML examples will drive the point home.

I will be building upon the declarative binding example from my earlier post, so you can reference the full explanation of the DataView code if you need to. I’ll just focus on the JavaScript code for the sake of this example, but you can find the full source in the download (available at the end of this post). To refresh your memory a bit, we had a simple array in the DataView example:

var nfcEast = [
    { Team: "New York Giants", Homepage: "http://www.giants.com/" },
    { Team: "Philadelphia Eagles", Homepage: "http://www.philadelphiaeagles.com/" },
    { Team: "Dallas Cowboys", Homepage: "http://www.dallascowboys.com/" },
    { Team: "Washington Redskins", Homepage: "http://www.redskins.com/" }
]

We then used declarative binding to bind the list to the DataView, which in our case was a simple unordered list:

<ul id="nflList" class="sys-template"
     sys:attach="dataview"
     dataview:data="{{ nfcEast }}">
    <li>
        <a href="{{ Homepage }}">{{ Team }}</a>
    </li>
</ul>

Now, let’s make our array “observable,” where again I’ll use the makeObservable method. One thing to note on this example, I’m not setting a handler to capture the changes. The reasoning behind this is due to the functionality built in to the DataView control. Normally to capture changes of a JavaScript array, you would wire up an event handler for the Collection Changed event by calling the method addCollectionChanged on Sys.Observer. The DataView however automatically listens for changes to an underlying “observable” collection.   All we need to do now is change our collection using the Sys.Observer methods for a collection. The Sys.Observer has quite a few methods for doing just this. They are add, addRange, clear, insert, remove, and removeAt. For this example, we’ll just look at a couple of the methods.

Sys.Observer.makeObservable(nfcEast);

function removeTeam() {
    if (nfcEast.length > 0) {
        nfcEast.removeAt(0);
    }
}

function moveTopTeamToBottom() {
    if (nfcEast.length > 1) {
        nfcEast.beginUpdate();
        var topTeam = nfcEast[0];
        nfcEast.removeAt(0);
        nfcEast.insert(nfcEast.length + 1, topTeam);
        nfcEast.endUpdate();
    }
}

This is all to code that is needed in order to update our array and thereby update our DataView unordered list. These are two pretty simple methods, removeTeam and moveTopTeamToBottom. The first simply removes the top team from the list, while the second does a “batch change” moving the top team in the list to bottom using beginUpdate and endUpdate like you saw earlier. Now for the “magic”, notice we’re not handling the changes at all. When you fire up the example, and click on the buttons to call the appropriate functions, you’ll notice that the DataView automatically rebinds after each of these calls. You can see an example of the functionality in the clip below (Figure 1).

Figure 01

Figure 1 – The DataView and Sys.Observer Example

Conclusion

It’s very handy to be able to get notifications for plain JavaScript objects like this. Having the Sys.Observer class at our disposal can empower us to remove custom get/set logic in our client-side classes, and use a standard pattern for this problem. By doing this, other controls (e.g. Sys.UI.DataView) can then subscribe as listeners in a common way for changes to our object without having to know about custom events that we have created.

Looking to try the code in the post out for yourself? [Download the Samples – 84K][3]

For more information on Sys.Observer and ASP.NET AJAX 4.0, here are a few other posts on the topic:

[3]https://images.visoftinc.com/2009-05-21/ObserverSamples.zip