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: