Javascript Composite UIs

Increasingly I find myself building web applications that rarely, if ever, reload the page. Ajax is used to communicate with the server and to update parts of the page as required. After much trial and error I have come upon a technique for organising the javascript on such pages.

Consider an application that has three buttons: red, yellow and green. When one of the buttons is clicked an rectangle is coloured according to the selection.

The UI design will be as follows:

mockup

Here is the demo.

The basic steps in my approach to javascript organisation for such a page are:

  1. Define a namespace for my custom javascript. In this case ‘TrafficLight’.
  2. Define an ‘initialize’ method within the top level namespace and call it from jQuery’s document ready event handler.
  3. Within the initialize method wrap each logical screen component within a javascript object. In this case I will have ‘buttons’ for the buttons and ‘rectangle’ for the rectangle.
  4. Use a ‘screen activator’ to configure a generic event aggregator so that the screen components do not have to be tightly coupled.

This might seem like overkill for such a simple application but I am trying to demonstrate a technique that considerably reduces complexity for more complicated UIs.

Here is the html for the page. Note the document ready event handler and the call to TrafficLight.initialise().

<html>
  <head>
    <link rel="Stylesheet" type="text/css" 
    href="traffic_light.css">
  </head>
  <body>  
    <div id="button_container">
      <input type="button" value="Red" 
        class="colour_button"/><br/>
      <input type="button" value="Yellow" 
        class="colour_button"/><br/>
      <input type="button" value="Green" 
        class="colour_button"/>
    </div>
    <div id="coloured_rectangle">
      
    </div>
    <div id="event_aggregator_element"/>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js">
    </script>
    <script type="text/javascript" src="TrafficLight.js">
    </script>
    <script type="text/javascript">
    
      $(document).ready(function() {
        TrafficLight.initialise(
          $('#button_container'), 
          $('#coloured_rectangle'), 
          $('#event_aggregator_element'));
      });
    
    </script>    
  </body>
</html>

The TrafficLight.js file:


// define the namespace
var TrafficLight = TrafficLight || {};

TrafficLight.initialise = function(
  buttonsWrapperSet, 
  rectangleWrapperSet, 
  aggregatorWrapperSet) {

  // create an event aggregator. 
  // the array lists the valid events for this screen.
  var aggregator = Aggregator.constructor(
    aggregatorWrapperSet, ['ColourSelected']);
  
  // create objects for the major screen components
  var buttons = TrafficLight.buttonsConstructor(
    buttonsWrapperSet, aggregator);
  var rectangle = TrafficLight.rectangleConstructor(
    rectangleWrapperSet, aggregator);

  // create a screen activator to connect the various components
   var screenActivator = TrafficLight.screenActivatorConstructor(
     buttons, rectangle, aggregator);
  screenActivator.activate();

};

TrafficLight.screenActivatorConstructor = function(
  buttons, 
  rectangle, 
  aggregator) {
  
  var that = {};
  that.activate = function() {
    // bind the 'ColourSelected' event to the rectangle object
    aggregator.bindToColourSelected(rectangle.handleColourChange);
  };  
  return that;
};

TrafficLight.buttonsConstructor = function(buttonsWrapperSet, 
  aggregator) {
  var that = {};  
  
  // configure event handlers for the individual buttons
  $('input', buttonsWrapperSet).click(function() {
    var selectedColour = $(this).val();
    // raise the 'ColourSelected' event.
    aggregator.triggerColourSelected([selectedColour]);
  });
  
  return that;
};

TrafficLight.rectangleConstructor = function(rectangleWrapperSet) {
  var that = {};

  that.handleColourChange = function(event, new_colour) {
    rectangleWrapperSet.css('background-color', new_colour);
  };
  
  return that;
};


var Aggregator = {

    constructor: function(wrapperSet, supportedEvents) {
        if (wrapperSet.length > 1) {
            alert("more than one object selected as event aggregator.");
            return;
        }
        var that = {};

        $.each(supportedEvents, function(index, eventName) {
            that['bindTo' + eventName] = function(callback, data) {
                wrapperSet.bind(eventName, data, callback);
                Debug.Log('Callback registered for ' + eventName);
            };
            that['trigger' + eventName] = function(extraParameters) {
                wrapperSet.trigger(eventName, extraParameters);
                Debug.Log('Triggered ' + eventName);
            };
        });
        return that;
    }

};

var Debug = Debug || {};

Debug.Log = function(message) {

    if (window.console && window.console.log) {
        window.console.log(message);
    }
};

jQuery client-side templates with jqote and Asp.Net MVC

Why Use Client-side Javascript Templates?

When building rich internet applications you often need to construct html on the client. I am going to demonstrate how to construct DOM elements using the jqote jQuery plugin (2.0.0).

The naive approach to client-side html generation is to embed html inside javascript like:

var text = 'Some text';
$('body').append($('<div id="content>' + text + '</div>"'));

This approach fails as the complexity of the html increases. It is also a clear separation of concerns violation to mix html (presentation) with script (interaction).

Javascript templates provide a way to dynamically build html on the client while storing the dynamic html with the rest of the presentation markup. Additionally javascript templates provide MVC-like separation of concerns.

Dynamically Building a Table with a Client-side Javascript Template

Suppose you want a web page that allows the user to build a table of people. For each person the user can enter their name and age. First we need a form to collect the values, and we need some jQuery magic to cancel the form post:

<form id="people_input">
        <label for="name">Name: </label><input type="text" name="name" /><br />
        <label for="age">Age: </label><input type="text" name="age" /><br />
        <input type="submit" value="Add" />
    </form>

    <script type="text/javascript">

        $(document).ready(function () {

            $('form#people_input').submit(function (e) {
                e.preventDefault();
            });

        });    
    
    </script>

There needs to be a table to display the people, and each time the form is submitted a new row should be added to the table. jqote templates are defined in the html by wrapping the template in a script tag and a CDATA tag. The script tag is necessary to stop the template from being interpreted as part of the page. The CDATA tag is required so that the page remains syntactically valid. Here is my empty table and a template for a row:

<table id="person_table">
        <tr>
            <th>Name</th><th>Age</th>
        </tr>    
    </table>

    <script type="text/html" id="template">
    <![CDATA[
        <tr>
            <td><$= this.name $></td><td><$= this.age $></td>
        </tr>    
    ]]>
    </script>

 

The default jqote tags use <%= %> syntax which I have replaced with <$= $> to avoid conflict with Asp.Net MVC. Inside of a jqote template ‘this’ refers to the data object used to render the template. Within the jqote tags any javascript is valid since jqote is based on John Resig’s Javascript Micro-Templating.

The final, and most interesting step is to render the template each time the form is submitted and insert the result at the end of the table. Note the second parameter to the jqote() method, which is the character to use for the html nugget syntax.

        $(document).ready(function () {

            $('form#people_input').submit(function (e) {
                var data = { name: $('input[name=name]').val(), age: $('input[name=age]').val() };
                $('table#person_table').append($('#template').jqote(data, '$'));
                e.preventDefault();
            });

        });   

To try out the complete code, grab it from codepaste.net.


Put It On a Shirt

refactoring_happens Sometimes you have a t-shirt idea, but there is no way to try it out – until now. Introducing OnAShirt.net. It is a simple app I coded in a couple of hours today that allows the user to place text over a picture of a t-shirt, or even to conduct t-shirt conversations with themself.

Thanks to jQuery for making this sort of thing so easy.


jQuery UI Dialog: Part 2 – The Modal Dialog

This is part 2 of my series on the jQuery UI Dialog. Part 1 – The Default Dialog covered the most basic usage of the dialog widget. In this second part I will demonstrate a simple modal dialog.

A modal dialog is a dialog that takes focus, and disables the rest of the application until it is closed. They are used to force the user to acknowledge something, or to gather some input. It is worth pointing out that modal dialogs can be annoying for users so you should consider carefully if it is absolutely necessary. User Account Control (UAC) in Windows Vista and Windows 7 is an example of an annoying usage of modal dialogs.

The dialog widget is usually configured by passing the dialog() method an anonymous object containing a set of key value pairs that describe the options required. The anonymous object is created using javascript’s object literal notation. My favourite javascript author, Douglas Crockford, describes the notation:

In the object literal notation, an object description is a set of comma-separated name/value pairs inside curly braces. The names can be identifiers or strings followed by a colon.

A simple code example is:

var myObject = {
    firstProperty: 'value 1',
    secondProperty: 2
};

The options I will use to create a modal dialog are:

height The height of the dialog
modal Boolean indicating if the dialog should be modal
overlay Creates a partially transparent modal overlay layer. Very web 2.0.

View a Demo

And here is the code:

<!-- See part 1 for html preamble -->
<body>  
    <p>Some text on the page.</p>
    
    <div class="make_me_a_dialog">Content of div</div>
    
    <script type="text/javascript">

        $(document).ready(function() {

            $('.make_me_a_dialog').dialog({ bgiframe: true,
                height: 200,
                modal: true,
                overlay: {
                    backgroundColor: '#000',
                    opacity: 0.5
                }                
            });

        });
        
    </script>  
</body>
</html>



jquery ui dialog: Part 1 – The Default Dialog

jQuery UI Dialog This series is going to document increasingly complex usages of the jQuery UI Dialog widget. This first part of the series will demonstrate how to display the default dialog.

Other series members:

jQuery UI Dialog: Part 2 – The Modal Dialog

The jQuery UI Dialog is a powerful client-side dialog control. It is bundled as part of the jQuery UI suite and as such it is available on the Google CDN. Some of its more interesting features are:

  • Modal / non-modal dialogs
  • Support for resizing and dragging
  • Support for buttons
  • Support for Theming
  • Stacking
  • Partially transparent modal overlay layer

The simplest usage of the dialog control is to select a div, and call the dialog() function.

View a Demo

Here is the complete code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <title>Default dialog</title>
    <link href="ui-darkness/jquery-ui-1.7.2.custom.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js"></script>
</head>
<body>  
    <p>Some text on the page.</p>
    
    <div class="make_me_a_dialog">Content of div</div>
    
    <script type="text/javascript">

        $(document).ready(function() {

            $('.make_me_a_dialog').dialog();

        });
        
    </script>  
</body>
</html>

Note that the two javascript files, jquery.min.js and jquery-ui.min.js, are loaded from the google content delivery network (CDN). Line 19 selects the div with the class 'make_me_a_dialog' and applies the jquery dialog plugin to it.

 

kick it on DotNetKicks.com


Simple AJAX with jQuery

jQuery AJAXJQuery includes powerful ajax features for enriching the experience of a web application. This post will describe the simplest case, using ajax to replace part of a page with new content from the server. The server-side technology can be anything, however ASP.NET webforms makes things more difficult.

An example situation where this technique might be useful is in a master-detail scenario. As the user selects a item from a list the details of that item should be displayed somewhere else on the page. Here is my list of items and the container that will hold the details when an item is selected:

<p><a href="#" onclick="AJAX.ajaxLoad(1);">Option 1</a></p>
<p><a href="#" onclick="AJAX.ajaxLoad(2);">Option 2</a></p>
<p><a href="#" onclick="AJAX.ajaxLoad(3);">Option 3</a></p>

<div id="details">Please select an option from the list above.</div>

You can see that when an option is selected a javascript function called AJAX.ajaxLoad() will be invoked. This function will use jQuery to perform an ajax request to the server, and then update the page with the result. By default jQuery will cache all requests in internet explorer. To disable this behaviour use $.ajaxSetup().

var AJAX = {}; // declare a namespace

AJAX.ajaxLoad = function(id) {
    
    $.ajaxSetup ({
        // Disable caching of AJAX responses */
        cache: false
    });

    $('#details').load('/url_to_get_details/' + id);    
}

This method will call /url_to_get_details/id which must return a html fragment which will be placed in the details div, overwriting anything that is already there.


Why You Should be Verifying Your Javascript (JSLint)

LintIn an attempt to improve the user experience modern websites are using javascript more and more. If you are even remotely serious about performance then you need to merge your script files and minify the result. Minification is the process of removing unnecessary characters from a resource to reduce the size of the file.

You need to verify your javascript because javascript tries to tolerate errors. I'm going to go out on a limb and say that this is stupid. It can lead to a situation where invalid javascript works in its full form, but fails when minified.

Here is an example:

        function(responseText) {
            Chapter.ShowNewChapter(isForwards);
            var expr = /<div id="chapter_id" style="display: none;">(\d+)<\/div>/
            var result = expr.exec(responseText);
            if (result && result.length > 1) { Chapter.CurrentChapterId = result[1]; }
            Chapter.FetchMetadata();
        })

The third line contains a regular expression after which I have neglected to add a semicolon to terminate the line. The last line is also missing a semicolon. Unfortunately, this works fine, until the script is minified. During minification the line breaks are removed because they are unnecessary characters and the javascript interpreter can no longer determine the end of each statement.

The good news is that Douglas Crockford has provided a solution. JSLint is a javascript code verifier in the style of the lint tool for C. JSLint comes with a timely disclaimer, "Warning: JSLint will hurt your feelings". It recommends a conservative javascript style so there are typically a lot of recommendations. To use JSLint you can paste your code into a textbox at www.jslint.com and click the JSLint button. It can also be run from the command line and so included into build scripts.

The creator of JSLint, Douglas Crockford, is skilled at leading people towards a safe and efficient use of javascript. If you are working with Javascript I strongly recommend his book 'Javascript: The Good Parts'.


ASP.NET MVC Conditional Rendering

Critics of ASP.NET MVC often point out that view code can end up looking a bit like classic ASP spaghetti code. Two of the major offenders are conditionals and loops in the view. Consider the following view code:

<script type="text/javascript">
        jQuery(document).ready(function() {
<% if (Model.ShouldJumpToSection)
 { %>
            Chapter.JumpToAnchor('<%= Model.Section.Slug %>');
 <%
    } 
%>
        });
</script>

It is difficult to read. A good strategy to clean up views is to try to move conditionals and loops to the controller or to helper methods. Rob Conery has tackled this on his blog. For situations like the above I like to use a helper extension method to move the conditional to a helper. The code is then simplified to:

    <script type="text/javascript">
        jQuery(document).ready(function() {
            <% Html.WriteIf(Model.ShouldJumpToSection, "Chapter.JumpToAnchor('" + Model.Section.Slug + "');"); %>
        });
    </script>

You can see that it is much easier to read. Because this code is not using the <%= %> notation you have to remember to add a ; at the end of the line. An important thing to keep in mind is that the method paramters are evaluated before the method is called, meaning that they are evaluated even if the conditional is false. Here is the code for the helper methods that I use:

public static class HtmlExtensions
{        
    public static void WriteIf(this HtmlHelper helper, bool condition, string truePart, string falsePart)
    {
        helper.ViewContext.HttpContext.Response.Write(condition ? truePart : falsePart);
    }

    public static void WriteIf(this HtmlHelper helper, bool condition, string truePart)
    {
        WriteIf(helper, condition, truePart, string.Empty);
    }
}

Another common pattern that I see in MVC views is:

<% if (ViewData.Model.Count == 0) { %>
         Nothing to display        
<% } else { 
    foreach (var item in ViewData.Model) { %>
        ...render the item here...
<% }
} %>    

It is not too bad but it can be cleaned up a lot by moving the conditional to the controller and placing the body of the loop in an MVC View User Control. In the controller check if the collection is empty and if so render a special empty view. Then the view above can be simplified to:

<% foreach (var item in ViewData.Model) { 
    Html.RenderPartial("_Item", item);
} %>

 No spaghetti here.

kick it on DotNetKicks.com

 


Optimising Javascript and CSS File Inclusion

Some time ago I wrote about optimising javascript and css file inclusion during the build process. This is necessary because our natural tendancy as developers, to neatly split these file into small modules with plenty of whitespace and commenting, result in unacceptable performance. It turns out that loading many small js files in a page has terrible performance characteristics and whitespace and commenting can slow things down considerably. I consider the technique described a success because the output was good from the performance point-of-view. Unfortunately, the developer experience was poor. There were a lot of steps required and it was easy to make a mistake and introduce a difference between the development environment and the production environment, which is high on my not-to-do list.

I am working on a new project and at the point where I need to think about optimising css and javascript again. This time I have gone with a slightly less optimal, but much simpler approach, based on conventions and adding extension methods to the UrlHelper class (this is part of Asp.Net MVC). Here is how it works.

In my web project I have the standard Content folder for storing resources. With Content I have created Scripts for javascript files and CSS for CSS files. Within Scripts and CSS I have created min folders, which will store the minified versions of the resources. The convention is that every js or css resource has a minified equivalent with the same name in the /min directory. The minified versions will be produced automatically during the build process.

Web project file system

During development I don't want to use minified files. I like to use Firefox to inspect js and css and minification makes this impossible. To make the loading of resources (js and css) choose between full and minified versions transparently I have implemented helper methods on the UrlHelper class. The methods are Script(...) and CSS(...).

    public static class UrlExtensions
    {
        /// <summary>Returns the url for a javascript file. In production the files come from the min sub-directory.</summary>
        public static string Script(this UrlHelper url, string filename)
        {
            return ResolveUrlForEnvironment(url, "~/Scripts/", filename);
        }

        public static string CSS(this UrlHelper url, string filename)
        {
            return ResolveUrlForEnvironment(url, "~/Content/CSS/", filename);
        }

        private static string ResolveUrlForEnvironment(UrlHelper url, string path, string filename)
        {
            if (!IsProduction()) return url.Content(path + filename);
            return url.Content(path + "min/" + filename);
        }

        private static bool IsProduction()
        {
            return (HttpContext.Current != null && !HttpContext.Current.IsDebuggingEnabled);
        }
    }

At runtime the application determines if it is in a 'production' environment by checking the IsDebuggingEnabled property. This corresponds to the debug attribute on the compilation element in web.config. If it is production then the helpers return the paths to the minified files, otherwise the path to the full files is returned. These helpers are used like this:

<link href="<%= Url.CSS("Site.css") %>" rel="stylesheet" type="text/css" />
<script src="<%= Url.Script("jquery-1.3.2.js") %>" type="text/javascript"></script>

To make this strategy work the build process has to: set the debug="true" attribute in web.config, and produce the minified js and css files. The minification can be done with packer and js min as described in my previous post. Changing the web.config can be done using NAnt or MSBuild.

To tackle the problem of many http requests to fetch js and css I plan to use the lo-fi approach of limiting the number of files. I will try to group my css and javascript so that there is roughly one file of each type loaded per page loaded in my application. This means that I will have many javascript 'classes' per javascript file. It is not ideal but it is simple and performant.

Overall I am much happier with my new approach. It is an acceptable compromise that gives me a much simpler model to work with, and I think that simplicity is something that we do not value high enough.

kick it on DotNetKicks.com

 


jQuery Datepicker by Example

I have been working almost exclusively with Asp.Net MVC for the last twelve months. Working with MVC has encouraged me to move more towards client side, javascript based controls, like the jQuery datepicker. The jQuery datepicker is part of the jQuery UI library. The jQuery UI library is a collection of widgets, effects, interactions and theming support.

This post will cover, by example, some of the basic datepicker usages. Once you have these covered the jQuery datepicker is a flexible, powerful component. If you download the full source, included at the end of this post, you will see that the examples are formatted with a css file (ui.all.css) and some images. This look and feel was generated using the online jquery themeroller tool.

Always Visible Datepicker Calendar

This example has a datepicker always visible and available for selecting a date.

View the Example

and here is the code:

<html>
<head><title>jQuery Open Calendar</title>
<link rel="stylesheet" href="ui.all.css" type="text/css" media="screen" />

</head>
<body>
<form>
	<input id="date" type="textbox"/>
	<div id="calendar"/>
</form>

	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script> 
	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.5.3/jquery-ui.min.js"></script>
	<script type="text/javascript">
		$(document).ready(function(){
    			$("div#calendar").datepicker({ altField: 'input#date', altFormat: 'yy-mm-dd' });
  		});
	</script>

</body>
</html>

Notice that I am loading the required jQuery javascript files from google. This has some minor performance advantages but you could just as easily keep the files locally. The datepicker is initialized using the jQuery ready function, which runs when the page has loaded. The datepicker is built on an empty div and in this example it simply updates a textbox with the selected date. If you don't want to see the textbox you can use a hidden input element instead.

jQuery datepicker opens on a button click

In this example the datepicker is invisible until a form button is clicked. The datepicker disappears again once a date is selected.

View the Example

and here is the code:

<html>
<head><title>jQuery Open on button</title>
<link rel="stylesheet" href="ui.all.css" type="text/css" media="screen" />

</head>
<body>
<form>
	<input id="date" type="textbox"/>
</form>

	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script> 
	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.5.3/jquery-ui.min.js"></script>
	<script type="text/javascript">
		$(document).ready(function(){
    			$("#date").datepicker({ showOn: 'button', buttonText: "select" });
  		});
	</script>

</body>
</html>

For this example the empty div is not required. The datepicker is constructed on the textbox. Again, a hidden input also works.

jQuery datepicker opens on an image click

This time the datepicker is triggered by clicking on an image. Other than that it is almost identical to the previous example.

View the Example

and here is the code:

<html>
<head><title>jQuery Open on image button</title>
<link rel="stylesheet" href="ui.all.css" type="text/css" media="screen" />

</head>
<body>
<form>
	<input id="date" type="textbox"/>
</form>

	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script> 
	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.5.3/jquery-ui.min.js"></script>
	<script type="text/javascript">
		$(document).ready(function(){
    			$("#date").datepicker({ showOn: 'button', buttonImageOnly: true, buttonImage: 'images/icon_cal.png' });
  		});
	</script>
</body>
</html>

jQuery datepicker selecting a date range

It is common to allow the user to select a range of dates. This last example supports range selection by allowing the user to click once to select the start of the range, and once more to select the end of the range.

View the Example

and here is the code:

<html>
<head><title>jQuery date range selector</title>
<link rel="stylesheet" href="ui.all.css" type="text/css" media="screen" />

</head>
<body>
<form>
	<input id="Range" type="textbox" value="09-04-06"/>
	<div id="fromCalendar"></div>
</form>

	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script> 
	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.5.3/jquery-ui.min.js"></script>
	<script type="text/javascript">
		$(document).ready(function(){
    			$("#fromCalendar").datepicker({ altField: "#Range", altFormat: 'yy-mm-dd', rangeSelect: true });
  		});
	</script>
</body>
</html>

The caveat with this last example is that you will need some sort of post-processing step to separate the start and finish dates of the range. Typically the date will arrive on the server in a format such as "2009-04-10 - 2009-05-27".

To run these examples locally, with the full look and feel, you can download a zip containing everything.

kick it on DotNetKicks.com