jQuery Slides & Demo from my Remix Australia Talk

On the 1st of June I had the pleasure of giving a talk at the Remix conference in Melbourne, Australia on the Microsoft/jQuery contribution story and the new Templating engine that were announced at Mix10 in Las Vegas earlier this year. This conference punctuated the Web Camps world tour that I’ve been on and was a welcome break to enjoy someone else running a big event :-)  I loved the widescreen, colorful slide template they gave me to use and the “love the web” theme for the conference was definitely running high through the attendees.  I overheard someone say that half the attendees were non-microsoft developers which was great to see as many of the talks were on open source, geo-location, HTML5 and other topics that were useful for all developers. 

image

One of the things I try to stress in my talk is the contribution model that Microsoft are using when making contributions to jQuery.  It’s the same as everyone else.  We are behaving as any other member of the jQuery community does – i.e. propose a new feature, spec it out and then build a prototype – all out in the open on jQuery’s forums and Github.  The community have been brilliant to work with. There is no shortage of enthusiasm, feedback, suggestions, code branches and more – it’s been great to see.  Here is the slide that I use to describe the contribution model, where examples of cool stuff are templating, data-linking and Cool Stuff ++ are features that the core team library deem essential enough to include in the jQuery core library – in the future.

Below are the slides for the talk and you’ll see the code from the demo in my next post.  They will also be releasing the video of the talk soon – I’ll let you know when that’s out too. Cheers and enjoy!

Tags:

The secret anti-spam checkbox in BlogEngine.net?

I’ve been under a bit of a spam deluge recently here on my blog.  I have to hand it to those spammers, their comments are getting more human-like everyday, with their text relating directly to the post in question.

Before today I’ve tried some options in BlogEngine.net to get rid of spam like enabling the AkismetFilter settings.  Much to my disappointment it didn’t seem to have any effect on the amount of spam I was getting – it just kept piling up! 

image

I drew to the conclusion that I was just going to have to put up with it, deleting comments manually.  Then this weekend after I upgraded to the shiny new BlogEngine.NET 1.6 I was playing around with the comment admin panel and strolled into the Configuration tab.

image

At first glance nothing special in there but then the “Moderate Comments” checkbox caught my eye.  I never normally moderate comments before they are posted but with today’s spam count reaching fever pitch I thought I would succumb to an anti-free speech approach to keeping my comments clean and relevant. 

I clicked the checkbox and much to my surprise I found a whole host of functionality I would never have associated with “Moderation”.  I had always associated moderation with something manual that I must do – I had never checked this box before.  My friends, I must tell you that this was like discovering the buried treasure on Treasure Island – it was a pure moment of enlightenment.  There, below were rules for capturing spam and filtering it out automatically.

image

Now, I don’t have any evidence that this was the flaw in my anti-spam campaign, but time will tell – i will be sure to keep you updated if it makes a difference. 

What did I learn from this discovery?  There’s a lesson in there for everyone about user experience and the subtleness of convention based approaches.  The convention in this case would for BlogEngine.NET not to put the spam settings under “moderation” (hiding them by default doesn’t help either) but under “Comment Spam”.

Also, it pays to click everything and also read the instruction manual :-)  Anyway, for those of you that come across this post and find it to provide the same kind of enlightenment that it did for me, happy (spam free) blogging!

Tags:

My Visual Studio 2010 Setup

image

When I install Visual Studio 2010, I only install the stuff I really need.  It’s easy to just do the “default” install but in my experience I find that not only does it take up additional hard drive space but the installation time is significantly reduced if I am selective about what components I use. 

Altogether, my install is 3.7GB compared to 5.5GB with Visual Studio 2010 fully loaded and takes around 35 minutes to install from scratch.

What’s your experience and what configuration do you prefer?

Tags:

Microsoft <3 jQuery

 

photo

Today at Mix10 we announced our increased support and involvement in the jQuery Library and how we are working closely with the community and the jQuery Team to accelerate the development of this already powerful front-end library.

In recent weeks leading up to Mix we have been working with John Resig and the rest of the team on a proposal, specification and prototype of a new jQuery templating engine, designed to make it easier than ever before to create rich, data-driven web applications. 

What we showed in the keynote today represented an early prototype of the jQuery Templating engine based off the community-driven specification.  Right now the feature is available as a jQuery plugin but we hope to include it in the core library in the future.

This is an exciting step for Microsoft as it increases its involvement in open source – in the spirit of the community – and will help make the web a better place for everyone, regardless of server-side technology.

What can you do today?

In the spirit of the jQuery community-driven development model we encourage you to get involved by reviewing the specification and and provide feedback on the jQuery forums.

There are a couple of prototypes out there on Github right now, an original version and a more recent version with more functionality.  I recommend trying out both and seeing which you like best – then let us know of course!

Come along to a jQuery Conference

Next month in April, jQuery will be holding its conference at the Microsoft Silicon Valley Campus in Mountain View – come along to learn more about the jQuery Templating Engine and jQuery from the team.

(Picture – Discussing the Day 2 Keynote backstage, Left to right, Rey Bango, John Resig, Scott Hanselman, Scott Guthrie, James Senior)

Tags:

Building Twitter Search using the ASP.NET Ajax Library Beta – Part II

In the first installment of this two-part series we explored how you can consume JSONP data sources using hardly any code thanks to the ASP.NET Ajax Library and the powerful networking stack that lies within.  This time around we’ll take a look at doing something useful with the data and render it using client templates, again, using the ASP.NET Ajax Library.

In the next few paragraphs, this is what we will build:

image

At this stage we have received data from the Twitter endpoint and now we want to do something useful with the JSON.  As a reminder, here is the code required to get to this point:

  1. <script src="http://ajax.microsoft.com/ajax/beta/0911/start.debug.js" type="text/javascript"></script>
  2.      
  3.     <script type="text/javascript">
  4.  
  5.         Sys.require([Sys.scripts.WebServices], function callback() {
  6.             Sys.Net.WebServiceProxy.invoke(
  7.                 "http://search.twitter.com/search.json?q=jsenior",
  8.                 null,
  9.                 true,
  10.                 null,
  11.                 function (result) { alert(result.results[0].text) });
  12.         });
  13.  
  14.         // Workaround for a bug in ASP.NET Ajax Beta, you don't need this in the final version
  15.         function createElement(tag) { return document.createElement(tag); }
  16.   
  17.     </script>

Let’s first construct how our template will look.  I want to display some basic information from a twitter search, like twitter handle, the contents of the tweet, when it was posted, and links to Twitter.com so the user can see the original tweet and the profile of the user.  Here’s what that looks like based on the documentation provided by Twitter on how their API returns data.

  1. <div id="TweetList">
  2.     <ul id="resultsView" class="sys-template">
  3.         <li>                
  4.             <a sys:href="{{ 'http://twitter.com/' + from_user }}">
  5.                 <img sys:src="{{ profile_image_url }}"  />                 
  6.                 <b>@{{ from_user }}</b></a>                     
  7.             says:                                 
  8.             <span class="tweet_created_at">
  9.                 (<a sys:href="{{ 'http://twitter.com/' + from_user + '/statuses/' + id }}">
  10.                 {{ new Date(created_at).format('dd MMMM yyyy HH:mm:ss') }}</a>)
  11.             </span>                
  12.             <br />
  13.                 {{ text }}
  14.             <br />   
  15.         </li>
  16.     </ul>
  17. </div>

As you can see, the template is fairly straightforward and the HTML is quite clean.  If you run the code in it’s current form you get the template output to the browser including all the curly braces.  This is to be expected because we haven’t attached the DataView control to the tempate – that’s the next step.

First we use the Script Loader to bring in the things like DataView, WebServices, Globalization (for the date formatting), and Watermark that we need for this app.  We’ll use the Watermark later on when we add an input box for specifying a search query.  Remember that the Script Loader takes care of loading all these components so you don’t need to know their dependencies – which is very handy with complex scripts.

  1. Sys.require([Sys.components.dataView, Sys.scripts.WebServices, Sys.scripts.Globalization, Sys.components.watermark], function () {
  2.  
  3.             var myDV = Sys.create.dataView("#resultsView");

Now that we have told the Script Loader to bring in the DataView control, we can assign it to our template, thus:

  1. var myDV = Sys.create.dataView("#resultsView");

Notice how we use the Sys namespace to do this (Sys is the ASP.NET Ajax Library namespace) and select the div using its ID, “resultsView”.  We are effectively telling the library that we want whatever is in the div to be data aware so when we bind the DataView it will repeat its contents for each row of JSON data – in this example we are repeating the LI element.

At this point let’s stop and add an input box and button to our page so we can specify the query to make to Twitter’s search API.  Use this code just before your template DIV.

  1. <div id="queryarea">
  2.         <input id="query" />   
  3.         <button id="btnQuery">Submit</button>
  4.     </div>
  5. <div id="TweetList">
  6.     <ul id="resultsView" class="sys-template">
  7.         <li>

Nice and easy, huh?  Throughout the rest of the sample we are going to refer to the input, “query”, exactly twice, so for performance reasons I am going to select it once and then store that reference in a var so I don’t need to select it any more than is absolutely necessary (this takes extra cycles for libraries like ASP.NET Ajax Library and jQuery).  Here’s the code you need to add under your existing JavaScript.

  1. var queryBox = Sys.get("#query");

Remember, when we brought in the Watermark control (part of the 35 free client-side controls in ASP.NET Ajax Library)?  We’re ready to use it!  We are going to apply the Watermark control to the input box using the var we have created above.  Here we go:

Sys.create.watermark(queryBox, "Search Twitter...", "watermark");

The first two parameters for the above method are fairly straightforward and the third one applies a style to the input box and its watermark so you can make it look how you want.

So now we have that sorted, it’s time to wire up our button to do the search when the user clicks the button.  We use the addHandler method for this purpose:

  1. Sys.addHandler("#btnQuery", "click", function () {
  2.  
  3. Sys.Net.WebServiceProxy.invoke("http://search.twitter.com/search.json?q=" + (encodeURIComponent(queryBox.value)), null, true, null, function (result) {
  4.     myDV.set_data(result.results);
  5. });
  6.  
  7. });

This method’s first parameter takes the selection of an element, in this case “btnQuery” and then applies an HTML event, “click” to it.  It then has a callback function that will fire when the user clicks the button; here we are just using an anonymous function which should be familiar to you.  Yes, it’s the WebServiceProxy.invoke method, which calls the Twitter Search API and passes it the search string.  We pass the results of the query into the function and then bind the dataset to the DataView using myDV.set_data.

Twitter nests its search results in a JSON array so that’s why we must use result.results to get to the data.

We are pretty much set. If we run the code then we’ll have the ability to search twitter and have the results displayed in the template we’ve setup.  However, those among you who have been paying attention will notice that we still have our ugly templates displayed with all the curly braces etc prior to searching.  Let’s apply a style to hide that and and the same time make our UI a bit more appealing – right now it looks like a dog’s dinner (Englishism for looking a “mess”).

Adding our styles to the page with all the JavaScript code we get the following.  The key part for hiding the template is .sys-template. Below is the full HTML page and you can just copy and paste this and you will be good to go.

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml" >
  3. <head>
  4.     <title>Untitled Page</title>
  5.     <style type="text/css">
  6.     
  7.         .sys-template {
  8.             display: none;
  9.         }
  10.         
  11.         #queryarea
  12.         {
  13.             width: 500px;
  14.             border: 3px solid #1958b7;   
  15.             padding: 10px;
  16.         }
  17.         
  18.         input {
  19.             height: 30px;
  20.             width: 280px;
  21.             font-size: 14pt;
  22.             border: 2px dotted #2586d7;
  23.             padding: 5px;           
  24.         }
  25.         
  26.         button
  27.         {
  28.             height: 45px;
  29.             width: 110px;
  30.             border: 2px solid #1958b7;
  31.             background-color: #FFFFFF;
  32.             font-size: 14pt;
  33.             color: #1958b7;
  34.         }        
  35.         
  36.         .watermark
  37.         {
  38.             font-style: italic;
  39.             color: Gray;
  40.         }
  41.         
  42.         
  43.         .tweet_created_at {
  44.             font-size: 8pt;
  45.             text-align: right;
  46.         }
  47.         
  48.         img {
  49.             height: 50px;
  50.             width: 50px;
  51.             float: left;
  52.             padding: 5px;
  53.             margin: 5px;
  54.             vertical-align: top;
  55.             margin-bottom: 15px;
  56.             border: 2px solid white;
  57.         }        
  58.         
  59.         #TweetList {
  60.             width: 490px;
  61.             padding: 0 0 1em 0;
  62.             margin-bottom: 1em;
  63.             font-family: 'Trebuchet MS', 'Lucida Grande',
  64.               Verdana, Lucida, Geneva, Helvetica,
  65.               Arial, sans-serif;
  66.             font-size: 10pt;            
  67.             color: #333;
  68.         }
  69.         
  70.         #TweetList ul {
  71.             list-style: none;
  72.             margin: 0;
  73.             padding: 0;
  74.             border: none;
  75.         }
  76.         
  77.         #TweetList li {
  78.             border-bottom: 1px solid #90bade;
  79.             margin: 0;
  80.             display: block;
  81.             padding: 5px 0px 5px 0.5em;
  82.             border-left: 10px solid #1958b7;
  83.             border-right: 10px solid #508fc4;
  84.             background-color: #2175bc;
  85.             color: #fff;
  86.             text-decoration: none;
  87.             width: 100%;
  88.             
  89.             height: 85px;
  90.         }
  91.  
  92.         html>body #TweetList li a {
  93.             width: auto;
  94.             color: White;
  95.         }
  96.  
  97.         #TweetList li a:hover {
  98.             color: Blue;
  99.         }
  100.  
  101.  
  102.     </style>
  103.  
  104.     <!-- Get the script loader from the CDN -->
  105.     <script src="http://ajax.microsoft.com/ajax/beta/0911/start.debug.js" type="text/javascript"></script>
  106.     <script src="http://ajax.microsoft.com/ajax/beta/0911/Extended/ExtendedControls.debug.js" type="text/javascript"></script>
  107.     
  108.     <script type="text/javascript">
  109.     
  110.         // We need dataView for templating, Web Services for JSONP call, Globalization for formatting the date, watermark for the input box
  111.         Sys.require([Sys.components.dataView, Sys.scripts.WebServices, Sys.scripts.Globalization, Sys.components.watermark], function () {
  112.  
  113.             var myDV = Sys.create.dataView("#resultsView");
  114.             var queryBox = Sys.get("#query");
  115.  
  116.  
  117.             Sys.create.watermark(queryBox, "Search Twitter...", "watermark");
  118.             
  119.  
  120.             Sys.addHandler("#btnQuery", "click", function () {
  121.  
  122.                 Sys.Net.WebServiceProxy.invoke("http://search.twitter.com/search.json?q=" + (encodeURIComponent(queryBox.value)), null, true, null, function (result) {
  123.                     myDV.set_data(result.results);
  124.                 });
  125.  
  126.             });
  127.  
  128.         });
  129.                
  130.     </script>
  131.     
  132.     <script type="text/javascript">
  133.  
  134.         // Workaround for a bug in ASP.NET Ajax Beta, you don't need this in the final version
  135.         function createElement(tag) { return document.createElement(tag); }
  136.         
  137.     </script>
  138.  
  139. </head>
  140. <body>
  141.     <div id="queryarea">
  142.         <input id="query" />   
  143.         <button id="btnQuery">Submit</button>
  144.     </div>
  145. <div id="TweetList">
  146.     <ul id="resultsView" class="sys-template">
  147.         <li>                
  148.             <a sys:href="{{ 'http://twitter.com/' + from_user }}">
  149.                 <img sys:src="{{ profile_image_url }}"  />                 
  150.                 <b>@{{ from_user }}</b></a>                     
  151.             says:                                 
  152.             <span class="tweet_created_at">
  153.                 (<a sys:href="{{ 'http://twitter.com/' + from_user + '/statuses/' + id }}">
  154.                 {{ new Date(created_at).format('dd MMMM yyyy HH:mm:ss') }}</a>)
  155.             </span>                
  156.             <br />
  157.                 {{ text }}
  158.             <br />   
  159.         </li>
  160.     </ul>
  161. </div>
  162. </body>
  163. </html>

This brings to close this 2-part series showing how to create a Twitter search in pure client-side code thanks to the ASP.NET Ajax Library.  We’ve covered the following important topics:

  • Getting the library from the Microsoft Ajax CDN
  • Using the Script Loader to load and execute all the required scripts and components
  • Applying the DataView Control to the Page
  • Creating a watermark
  • Adding an onClick handler to the button
  • Calling the Twitter Search API using JSONP
  • Setting up our client template

Tags:

Building Twitter Search using the ASP.NET Ajax Library Beta – Part 1

Last week we launched the ASP.NET Ajax Library Beta during PDC, oh and we donated it to the CodePlex Foundation under new BSD license (FTW).  As the email volume has been fading away running up to Thanksgiving in the US and everyone at work is recovering from conferences, I took this golden opportunity to sit down and build a small sample with the new library now that we are in Beta.

Since the ASP.NET Ajax Library takes care of JSONP requests for me (which enables cross-domain service requests) it is really easy to hit a service like the Twitter Search API which in turn provides me with a JSON result and a callback to trigger functionality which does something with the result.

This allows us to build a Twitter Search application that is running completely on the client-side depending on no servers apart from those at Twitter HQ (we kind of need them for the search results, remember).  In Part 1 of this 2-part series I will look at how to call the Twitter Search service using the WebServiceProxy.invoke method and then in subsequent posts I will look at using the data once in a DataView and how we can use client-side template to render the results.

First we start by exploring the WebServiceProxy.Invoke method – which is how we call the Twitter APIs.

  1. Sys.Net.WebServiceProxy.invoke("http://search.twitter.com/search.json?q=@jsenior", null, true, null, doSomething(result));

The above code will make the required call to the Twitter Search API and takes a few parameters including an onSuccess callback function (doSomething) so we can then do something with the result set.  We can also specify things like the methodName (for webservice requests), query parameters, timeout etc – for the full set of params check out the MicrosoftAjaxWebServices.debug.js file.  Behind the scenes, the invoke method figures out if you are making a request cross-domain in which case we require the call to be JSONP so we can receive the callback on our end.

To get access to WebServiceProxy.invoke we need have referenced a number of scripts from the ASP.NET Ajax Library including MicrosoftAjaxWebServices.js.  The most sensible way to do this is to use the new Script Loader which takes care of loading not only this particular script but also any others from the library on which it is dependant.  It does this in a really efficient way both in parallel and asynchronously allowing scripts to be loaded but not executed according to a dependency tree.  Furthermore, you don’t even need to reference the Script Loader from a local folder or web server, you can grab it direct from the Microsoft Ajax CDN:

  1. <script src="http://ajax.microsoft.com/ajax/beta/0911/start.debug.js" type="text/javascript"></script>

You’ll notice that we do versioning based on year and month so that your apps won’t break when we bring out new versions.

Once you’ve got the Script Loader referenced from the CDN, you can start bringing in the components you need and in this sample, so far, we need Sys.scripts.WebServices.  We use Sys.require to tell the Script Loader that’s what we need and also can provide a callback function for it to call once everything has been loaded and we are good to start using the script.

  1. Sys.require([Sys.scripts.WebServices], callback);

If we put all this code together and push one of the result tweets into a simple alert to show that it works, we get the following code:

  1. <script src="http://ajax.microsoft.com/ajax/beta/0911/start.debug.js" type="text/javascript"></script>
  2.     
  3.     <script type="text/javascript">
  4.  
  5.         Sys.require([Sys.scripts.WebServices], function callback() {
  6.             Sys.Net.WebServiceProxy.invoke(
  7.                 "http://search.twitter.com/search.json?q=jsenior",
  8.                 null,
  9.                 true,
  10.                 null,
  11.                 function (result) { alert(result.results[0].text) });
  12.         });
  13.  
  14.     </script>

Try it yourself by copy and pasting it into a blank HTML document, it’s that easy.

In the next post, I’ll show you how to do something useful with the result set by using the DataView component and client-templates.  Stay tuned.

For more information about the ASP.NET Ajax Library including samples, downloads and docs check out the wiki here: http://www.asp.net/ajaxlibrary

*UPDATE*

There is a bug in the beta where you need to include the following method to get the sample working.  Sorry to those who’ve been having trouble getting it working.  Add this to your javascript code and all will be right in the world.

// Workaround for a bug in ASP.NET Ajax Beta, you don't need this in the final version
        function createElement(tag) { return document.createElement(tag); }


Tags:

Building High Performance Web Applications

At the PDC (our dev conference) we release the Beta version of the ASP.NET Ajax Library and also donated it to the CodePlex Foundation as their first project.  For this version of the library we’ve focused on four areas of functionality:

Power for developers

Performance

Interoperability

Extensibility

Getting detailed about Performance

Dan Wahlin and I put together the following whitepaper that talks about how you can use the features in ASP.NET Ajax Library to speed up the performance of your web applications.  You can download the PDF here or read it below:

Building High Performance Web Applications

Tags:

News on the ASP.NET Ajax Library Beta

The ASP.NET Ajax Library Beta was released today! The five big things I’m going to talk about in this post are:

  1. The ASP.NET Ajax Library is now in Beta
  2. Contributing the ASP.NET Ajax Library to the CodePlex Foundation
  3. Merging the Ajax Control Toolkit with the ASP.NET Ajax Library
  4. Plans to provide support for the ASP.NET Ajax Library
  5. ASP.NET Ajax Library features that provide:
    • Powerful developer libraries and tooling support
    • Performance – build high performance websites
    • Interoperability – use it with any server platform and alongside jQuery
    • Extensible – build on top of the library and inherit from controls like DataView

Since July last year the team has been cranking out new features in 6 previews, each with exciting innovations including powerful productivity benefits for developers, performance enhancements to make your website faster and making the library interoperable with multiple server platforms and other JavaScript libraries like jQuery.

 

Contributing the ASP.NET Ajax Library to the CodePlex Foundation

clip_image002

When it comes to the web, open source and licensing is important – see yesterday’s Open Web Foundation (OWF) announcement about Microsoft’s contributions in the Open Web. The ASP.NET Ajax Library is the first project to be contributed to the CodePlex Foundation and we are incredibly excited because it allows the project to take other contributions by the community and be driven by your feedback. The ASP.NET Ajax Library will be distributed under the New BSD license.

Merging the Ajax Control Toolkit with the ASP.NET Ajax Library

Before today, the Ajax Control Toolkit (ACT) was an impressively popular download from CodePlex.com with 25,000 downloads per week. ACT provides, and will continue to provide, loads of rich controls for ASP.NET Web Forms developers to add Ajax experiences to their web applications without the need to write client-side code. In ASP.NET Ajax Beta, we have converted 34 controls to pure client script, so now developers who write client-side code (including ASP.NET MVC, PHP and Ruby on Rail developers etc.) can use them in their web applications too. As a bonus we’ve also made it possible to instantiate the ACT controls as jQuery Plugins – part of the interoperability efforts we have been making. (More on that later.)

Here’s an example of instantiating a Watermark ACT control using the new syntax:

  1. <script src="../scripts/start.debug.js" type="text/javascript"></script>
  2. <script src="../scripts/extended/ExtendedControls.debug.js" type="text/javascript"></script>
  3.  
  4. <script type="text/javascript">
  5.  
  6.     Sys.require(Sys.components.watermark, function () {
  7.         Sys.create.watermark("#input1", "Enter something...");
  8.     });
  9.     
  10. </script>


Plans to provide support for the ASP.NET Ajax Library

Knowing that there is someone on the end of the phone to talk to about an issue is important to our developers. When the full version of the ASP.NET Ajax Library is released Microsoft will provide full product support. We already provide full support for jQuery and we will continue this going forward.

ASP.NET Ajax Library features

Power for developers

Performance

Interoperability

Extensibility


Useful Links

Here are some links that you will find useful:

Tags:

Let me know your questions for Scott Guthrie and the ASP.NET Team @devconnections

I’m going to be at DevConnections this year to deliver a session on Microsoft Ajax with Jim Wang and also chair a panel with Scott Guthrie and members of the ASP.NET Team.  First of all here are details on the invitation:

Join us for a technical question and answer session with Scott Guthrie and members of the ASP.NET team on November 10th 2009 from 6:15 PM - 8:15PM at the ASP.NET Connections conference in Las Vegas. This is your chance to meet face to face with the people working on ASP.NET, give feedback and receive guidance. Attendance is limited so be there early and ask for details at the registration desk. We will have pizza and beverages.

I’ll be taking questions from the audience but if you can’t make it to Las Vegas and want to pose a question to Scott and the team feel free to leave me a comment on this post or hit me on twitter @jsenior!

See you there!



Tags:

How the Script Loader in the Microsoft Ajax Library will make your life wonderful

Everyone in the Microsoft Ajax team has a favorite feature, the CDN, jQuery Integration, and mine happens to be the Script Loader. I’m fond of it because it has some really cool features that aid the performance of my web application and take away much of the headache associated with organizing and loading any scripts that I use either from Microsoft, my own application or indeed a third party library like jQuery. The headache I’m referring to can be best characterized in the example below where I am loading scripts needed to use controls from the Ajax Control Toolkit (ACT) and the various components of the Microsoft Ajax Library. There are multiple scripts required and prior to the Script Loader I would be bringing them in all manually and having to worry myself with loading them in the right order. Not fun.

 

  1. // Microsoft Ajax Library scripts
  2.     <script type="text/javascript" src="../Scripts/MicrosoftAjax/MicrosoftAjaxCore.js"></script>
  3.     <script type="text/javascript" src="../Scripts/MicrosoftAjax/MicrosoftAjaxComponentModel.js"></script>
  4.     <script type="text/javascript" src="../Scripts/MicrosoftAjax/MicrosoftAjaxSerialization.js"></script>
  5.     <script type="text/javascript" src="../Scripts/MicrosoftAjax/MicrosoftAjaxGlobalization.js"></script>
  6.     <script type="text/javascript" src="../Scripts/MicrosoftAjax/MicrosoftAjaxTemplates.js"></script>
  7.  
  8.     // ACT Controls
  9.     <script src="../Scripts/ACT/ACTRegisterExtended.js" type="text/javascript"></script>
  10.     <script src="../Scripts/ACT/ACTWatermark.js" type="text/javascript"></script>
  11.     <script src="../Scripts/ACT/ACTExtenderBase.js" type="text/javascript"></script>
  12.     <script src="../Scripts/ACT/ACTCommon.js" type="text/javascript"></script>

This can all be made better – let’s find out how by starting at the beginning with start.js.

Getting started with the script loader

Start.js is your friend. It contains the Script Loader which is super small and knows about all the scripts of the Microsoft Ajax Library, some of which are listed in the above sample. You include it just as you would any other script like so:

  1. <script type="text/javascript" src="../scripts/start.js"></script>

It’s also available via our brand spanking new, smoking fast Microsoft Ajax CDN so your customers will get blisteringly fast script downloads wherever they are in the world. ScottGu’s got more info on the CDN here.

<script type="text/javascript" src="http://ajax.microsoft.com/ajax/beta/0910/Start.js"></script>

Now that you’ve got the Script Loader bootstrapped it’s time to “harness the power of the atom” (Scott Hanselman’s favorite saying at the moment) and start loading scripts into your application. The Script Loader allows you to load libraries and scripts into your application without having to worry about where the code file is. Now this is where it gets sexy (yes JavaScript can be sexy). In the following example I want to use the dataView control and the ApplicationServices script (both included in Microsoft Ajax Library) so I tell the Script Loader to get them ready for me using “Sys.require”:

  1. <script src="../Scripts/MicrosoftAjax/start.js" type="text/javascript"></script>
  2. <script type="text/javascript">
  3.  
  4.     // Load required scripts for DataView client control, using script Loader
  5.     Sys.require([Sys.components.dataView, Sys.scripts.ApplicationServices], function () {
  6.  
  7.         // do some stuff with dataView and Application Services
  8.  
  9.     });
  10.  
  11. </script>

Once the Script Loader fetches them (in parallel) and executes them it checks if the DOM is ready and then calls the function I’ve specified in the second parameter of Sys.require. On a side note, we can also bring in jQuery by adding Sys.scripts.jQuery to the array.

Let’s take it further by considering a common scenario where I have created a custom script for my application. The script is only needed when a user clicks a certain button though, so we’re going to register it with the Script Loader but only execute it on-demand when (this is an example of what we call “lazy loading”):

  1. <script src="../Scripts/MicrosoftAjax/start.js" type="text/javascript"></script>
  2. <script src="../Scripts/RegisterMyAppScript.js" type="text/javascript"></script>
  3.  
  4. <script type="text/javascript">
  5.  
  6.     function useMyCustomScript() {
  7.  
  8.         Sys.require(Sys.scripts.myAppScript, function () {
  9.             // Use my custom script
  10.         });
  11.  
  12.     }
  13.             
  14. </script>
  15.  
  16. <input type="button" onclick="useMyCustomScript()" value="Click me"/>

“But wait”, I can hear you say, “what is that extra script we reference – “RegisterMyAppScript.js”? Good question – that’s where we define our script and any other scripts that it depends on.

Let’s be definitive

Within RegisterMyAppScript.js we use the Script Loader’s “defineScripts” method to make it aware of the location of our script and any dependencies that it may have on other scripts:

  1. Sys.loader.defineScripts({
  2.         releaseUrl: "%/../CustomScripts/{0}.js",
  3.         debugUrl: "%/../CustomScripts/{0}.js"
  4.     },
  5.         [
  6.             { name: "myAppScript",
  7.                 executionDependencies: ["ApplicationServices"],
  8.                 isLoaded: !!(window.My && My.Scripts && My.Scripts.TheScript)
  9.             }
  10.         ]
  11.     );

First we specify a release and debug URL and depending on how we’ve setup the loader it will use a minified version or a version with comments and intellisense (we’ll get into that later). Then we pass a parameter to defineScripts that provides the information about the different scripts we want to register – in our case “myAppScript”. For each script we specify the name (filename without the file extension) its execution dependencies and an isLoaded test that we use to check if the script has already been loaded (we don’t want to load it again!)

If this were a custom control we were loading then we could also tell the Script Loader under which namespace our behaviors are loaded.

Now we can let the Script Loader worry about the fact that my custom script requires ApplicationServices from the Microsoft Ajax library and it will load all the required scripts in parallel, maximizing performance whilst only executing them when they are ready.

Next we’ll look at what the actual custom script looks like.

Parallel Power with dependency management built in

In the past, loading scripts in sequence made sense when you had complex dependencies that tied the scripts together however this is not recommended practice if performance is important. Let us assume that both having modular code (dependencies) and good performance is important to you. Whilst browsers have been able to load two scripts in parallel for some time, modern browsers let you load many at once but this in itself can raise a couple of problems. Firstly, we have a “race condition” where Script A is racing against Script B to be loaded and executed. When there are dependencies between A and B and the dependent script loads first (for whatever reason) your code will break because it is expecting a symbol to be present that has yet to be loaded and executed by the browser. Secondly, only modern browsers allow us to load more than two scripts in parallel (there are some hacks you can do but let’s assume we’re not using them), so if we have a large collection of scripts with dependencies we will still be waiting an undesirable length of time.

The Script Loader allows us to download multiple scripts in parallel whilst managing all their dependencies and making sure that we only execute the scripts once a dependency is satisfied.

There’s one more question that needs answering though. How do we load the scripts, like RegisterMyAppScript.js, without executing them automatically? We solve this problem by wrapping the script in an execute function and then check to see if the Script Loader is ready (loaded). If it’s ready to rock then we then call registerScript, passing in the name of the component and the execute callback function. Now the loader knows that this is the script that must be called when all its dependencies are in place – and that execute is the function to make this happen.

  1. (function() {
  2.         function execute() {
  3.             // .. script content ..
  4.         }
  5.      
  6.         if (window.Sys && Sys.loader) {
  7.             Sys.loader.registerScript(“myAppScript”, null, execute);
  8.         }
  9.         else {
  10.             execute();
  11.         }
  12.     })();

You’ll notice that if the Script Loader is not there (for whatever reason) then we just go ahead and execute the script anyway – with this we are preserving the original functionality of the script.

Power to the developer

A lot of developers are scared by JavaScript development. However, more recently with the introduction of libraries like Microsoft Ajax Library and jQuery as well as better intellisense support and browser debugging there is no longer much of a reason to hide behind the cushions. Remember earlier on where we specified a release and debug version of the scripts? The Script Loader has a property we can set to enable a debug mode which when we are running our scripts and stepping through them using our favorite browser plugins is really useful. When set to true the loader uses the version which is not minified and has comments so we can figure out where our script is going wrong.

  1. Sys.debug = true;


Summary

That’s it for now but there is a bunch more features in the Script Loader that I will cover off in future blog posts, including:

  • Lazy Loading
  • Intellisense in Visual Studio
  • How the loader does the ordering of scripts
  • Handling DOM ready events etc

In this blog post we’ve seen how script loading and management of execution is made easier using the Script Loader from the Microsoft Ajax Library as well as covering off how we handle dependencies between different scripts and debugging.

To find out more about what’s in the Microsoft Ajax Preview 6 release check out the following resources and be sure to come to Microsoft PDC where we’ll be doing sessions on the new stuff!

Tags: