Thursday, September 23, 2010

Introducing jQuery Templates 1: First Steps


UPDATE: A joint announcement has just been made by jQuery and Microsoft that the jQuery Templates, Data Link and Globalization plugins are now 'Official jQuery Plugins'. In addition, a full set of documentation for the jQuery Templates and Data Link plugins is now available on the http://api.jquery.com/ site. See my next post: jQuery Templates is now an Official jQuery Plugin for details.
In my last post, I said I planned to start a series of posts introducing jQuery Templates. This is the first of that series. This post also introduces the Sample Viewer, which you can use to try out your own jQuery templates. In a sense jQuery Templates consists of three plugins: .tmpl(), .tmplItem() and .template(), and each one comes in two flavors: instance plugin and static plugin. From a basic scenario point of view, it is like this:
  • .tmpl(): Render the template
  • .tmplItem(): Find the template item
  • .template(): Compile/Store the template
The template itself is any HTML markup, along with any of a set of template tags which enable some very rich scenarios for creating data-driven UI. The current set of tags that are supported in jQuery templates are:
  • ${...}: Evaluate fields or expression
  • {{each ...}}...{{/each}}: Iterate without creating template items
  • {{if ...}}...{{else ...}}...{{/if}}: Conditional sections
  • {{html ...}}: Insert markup from data
  • {{tmpl ...}}: Composition, as template items
  • {{wrap ...}}...{{/wrap}}: Composition, plus incorporation of wrapped HTML
This blog will be the first of a series in which I hope to drill into the role of each of those APIs and tags. For this first blog, we'll start with the simplest possible scenario. We'll use just the .tmpl() API, for rendering a template, and the ${...} template tag, for inserting data values into the rendered output... So here goes:

Rendering a template using local data within the page

Here is some data:
var movies = [
    { Name: "The Red Violin", ReleaseYear: "1998" },
    { Name: "Eyes Wide Shut", ReleaseYear: "1999" },
    { Name: "The Inheritance", ReleaseYear: "1976" }
];
Here is some markup to be used as a template:
<script id="movieTemplate" type="text/x-jquery-tmpl">
    <li>
        <b>${Name}</b> (${ReleaseYear})
    </li>
</script>
and a target element where we are going to render the result of rendering the template against our data:
<ul id="results"></ul>
And here is some code to take the template, render it with the data, and append the resulting HTML as content under our target element:
$( "#movieTemplate" ).tmpl( movies )
    .appendTo( "#results" );
In the above code, we get a jQuery wrapped set containing our template markup, and use the .tmpl() plugin method (to which we pass the data) to render the template. Then we chain with the appendTo method to append the results under our target element:
Demo:
    As you see the template got rendered once for each item in the movies array. Data values are inserted using the template tag ${...}. In fact ${expression} inserts the (HTML-encoded) result of evaluating the expression term, in the context of the current item. The template engine actually exposes the current data item as the variable $data, and also exposes each of the fields of the current data item as individual variables. So the most simplest use-case of ${...} is just with a field name as expression, such as ${ReleaseYear}. This is actually equivalent to ${$data.ReleaseYear} and inserts the value of that field on the current data item. Pretty straightforward. Here is the complete code of our example:
    <script src="http://code.jquery.com/jquery.js" type="text/javascript"></script>
    <script src="jquery.tmpl.js" type="text/javascript"></script>
    
    <script id="movieTemplate" type="text/x-jquery-tmpl">
        <li>
            <b>${Name}</b> (${ReleaseYear})
        </li>
    </script>
    
    <ul id="results"></ul>
    
    <script type="text/javascript">
        var movies = [
            { Name: "The Red Violin", ReleaseYear: "1998" },
            { Name: "Eyes Wide Shut", ReleaseYear: "1999" },
            { Name: "The Inheritance", ReleaseYear: "1976" }
        ];
    
        $( "#movieTemplate" ).tmpl( movies )
            .appendTo( "#results" );
    </script>
    

    Playing with the data and the template: Sample Viewer

    To get the feeling of how it works, here is the same demo again, but this time I have used a special Sample Viewer script which is integrated into my blog, so that if you mouse over the demo, you will see a little '+' button that you can click on. The result will be a tabbed view in which you can see the data and the template, as well as the result:
    Demo with Sample Viewer (Mouse over...)
      Try mousing over the demo above, clicking on the '+' button, and modifying the data or the template under the respective tabs. Go back to the result tab and you will see how it renders. Click on the '-' button, and you will be back with the orginal data and template... By the way, this sample viewer is actually implemented using jQuery templates, and illustrates the kind of dynamic interactive client-side UI that can be built very easily with jQuery templates. Maybe at some point I'll reach the point of blogging about how I went about building the sample viewer. But for now, let's get back to just playing with it. For example, if you want to just change the data, and see how the template rendering works with your changes, here are some examples of changes to the data that you could explore:

      Changing the data

      Mouse over the demo above and expand the Sample Viewer. Now try copying and pasting the data examples below into the Data tab, and then switching back to the Result tab. Change values, number of elements etc.
      [
          { "Name": "The BLUE Violin", "ReleaseYear": "1998" }
      ]
      Conclusion: It actually is data-driven :-) Remove some fields and add others:
      [
          { "Name": "The Red Violin", "ReleaseYear": "1998" },
          { "Name": "Eyes Wide Shut"  },
          { "Name": "The Inheritance", "ReleaseYear": "1976", "Director": "Mauro Bolognini" }
      ]
      Conclusion: It ignores the missing/undefined values without error. If you put the value of those fields to null or to the empty string, the result is the same. And of course the added fields have no effect, unless you want to add ${Director} to the template. (Try it...) Replace the array with a single object:
      { Name: "The Red Violin", ReleaseYear: "1998" }
      Conclusion: The templating engine is smart about arrays. Pass an object and it renders the template once, with the object as data item. Pass it an array and it creates a template item (a rendered template) for each of the data items in the array. Set the data to null:
      null
      Conclusion: If you pass no data at all, the templating engine still renders the template once, but the current data item is null. We will see that there are many scenarios where you are just rendering boiler-plate, or where the template pulls in data from other places than the data item, so passing data to the template is not always appropriate or relevant. It may be a nested template, and use data from the parent item. It may have template tags whose parameters are not simple values, but function calls, and the template is driven by the data returned by that function call. For example it might include {{each myApp.getData(foo)}}, or ${myApp.getData(foo)}. In this blog I am staying with much simpler examples, but we will see in later blogs how passing functions to template tags is extremely common. Include some HTML markup in the data:
      { "Name": "The <strong style="color: Red;">Red</strong> Violin", "ReleaseYear": "1998" }
      Conclusion: This does not change the formatting of the text. Instead, it shows the markup in the rendered UI. This is by design: ${expression} HTML-encodes the value before inserting it into the DOM. If you actually want your markup to get inserted into the DOM, then use the {{html ...}} template tag rather than the ${...} template tag. You can try it now: go to the #movieTemplate tab and replace ${Name} by {{html Name}}. Now the markup will not be escaped, and the data will actually get inserted as HTML. (We'll come back to this lower down in the blog). One detail: the sample viewer is using JSON2 to convert between string expressions and JavaScript objects. So the text you are editing above is actually JSON, not JavaScript literals. That's why the keys are wrapped in quotes. Try removing them, and the sample viewer will tell you that you have a syntax error! But in your script, of course, you have literals, and those quotes can be omitted (as long as you avoid JavaScript keywords!)

      Changing the template

      Let's try changing the template, now, rather than the data. For convenience, here is the sample viewer again. This time I set it to show the tabs from the get-go, so you don't need to mouse over and click the '+' button... Sample Viewer
        So try copying and pasting the template examples below into the #movieTemplate tab, and then switching back to the Result tab. Add some text:
        <li>
            <b>${Name}</b> (Released in the year ${ReleaseYear})
        </li>
        Conclusion: It works as you would expect! Add some markup and some formatting:
        <li>
            <b>${Name}</b> (<span style="color: Blue;">${ReleaseYear}<span>)
        </li>
        Conclusion: It works as you would expect... Add simple JavaScript expressions:
        <li>
            <b>${Name.toUpperCase()}</b> (${parseInt(ReleaseYear) + 100})
        </li>
        Conclusion: This works too. You can put JavaScript expressions as parameters to the tags. But don't go overboard! There is not a complete JavaScript parser in the context of inline expressions in the template. If you have complex code, write a function, and call the function from your template, and pass parameters if you need to: ${myFunction(a,b)}. (More on that in a later blog...) Add another template tag:
        <li>
            <b>${Name}</b> (${ReleaseYear}) - Director: ${Director}
        </li>
        Conclusion: Nothing yet - there is no Director field... Now change the data too:
        [
            { "Name": "The Red Violin", "ReleaseYear": "1998", "Director": "Francois Girard" },
            { "Name": "Eyes Wide Shut", "ReleaseYear": "1999", "Director": "Stanley Kubrick" },
            { "Name": "The Inheritance", "ReleaseYear": "1976", "Director": "Mauro Bolognini" }
        ]
        Conclusion: Yes, it works as expected! Finally let's make the change I mentioned in the previous section, and get a 'teaser' on one of the other template tags to be covered in later blogs: the {{html ...}} tag... First, include HTML markup in the data:
        { "Name": "The <strong style='color: Red;'>Red</strong> Violin", "ReleaseYear": "1998" }
        Now change the template to use the {{html ...}} template tag instead of the ${...} template tag:
        <li>
            <b>{{html Name}}</b> (${ReleaseYear})
        </li>
        Conclusion: Thanks to the {{html ...}} tag, you can insert HTML markup into the DOM, as HTML. Combining some of the changes above to data and template, here is a working example that illustrates what you did, and which you can use for exploring further changes: Sample Viewer
          And here is the complete code of our modified example:
          <script src="http://code.jquery.com/jquery.js" type="text/javascript"></script>
          <script src="jquery.tmpl.js" type="text/javascript"></script>
          
          <script id="movieTemplate" type="text/x-jquery-tmpl">
              <li>
                  <b>{{html Name}}</b> 
                  (<span style="color: Blue"> ${ReleaseYear}</span>) - Director: ${Director}
              </li>
          </script>
          
          <ul id="results"></ul>
          
          <script type="text/javascript">
              var movies = [
                  { Name: "The <strong style='color: red'>Red</strong> Violin", ReleaseYear: "1998", Director: "Francois Girard" },
                  { Name: "Eyes Wide Shut", ReleaseYear: "1999", Director: "Stanley Kubrick" },
                  { Name: "The Inheritance", ReleaseYear: "1976", Director: "Mauro Bolognini" }
              ];
          
              $( "#movieTemplate" ).tmpl( movies )
                  .appendTo( "#results" );
          </script>
          

          What's next?...

          Of course we have only just started scratching the surface here. I hope to provide more blogs soon to continue exploring the possibilities of jQuery templates. In the meantime, you can download the code for jQuery templates from http://github.com/jquery/jquery-tmpl.

          Wednesday, September 22, 2010

          From Microsoft to Open Source

          Since earlier this year, I have been working on jQuery Templates, as well as some other contributions to jQuery. The starting point was an initial prototype by John Resig, sometimes referred to as his micro-templating proposal. I hope to follow this post with a series of posts on jQuery Templates.

          But before beginning those posts I wanted to to give some background:

          Microsoft and jQuery

          At Microsoft, we had a pretty cool client templating implementation which Dave Reed and I created. This was part of the Microsoft AJAX Library. The client templates were integrated with live data-linking, and with a script loader. We also worked on some very interesting integration between all that and jQuery, so that if you were using jQuery you could get jQuery-style APIs for the MS AJAX features, and use selectors, fluent-style APIs etc.

          But after reaching the point of releasing Preview 6, and getting very close to a final release, our management team decided to make a radical change. Client-side AJAX platforms are all about performance and optimization of Web requests, and in a sense we were in a contradictory situation. - We were encouraging our developers to use both the MS AJAX platform and jQuery in their client apps, but inevitably there was some overlap and the inclusion of both platforms in their apps was not completely optimal.

          So the change was that from that point on we would not just provide support for using jQuery alongside our own client-side Microsoft AJAX platform. We would instead begin to offer contributions directly to jQuery.

          In fact while jQuery has some very cool features, there were a number of features in our AJAX platform which were not in jQuery, and indeed were pretty much ahead of the curve as far as AJAX platforms in general are concerned - or at least that is my view :-). Amongst those features - our client templates, our concept of observable JavaScript objects and arrays (which we now refer to as "data-linking"), our globalization support, and our script loader.

          Moving to Open Source

          So we began the process of completely redesigning and re-implementing some of those features as pure jQuery plugins or extensions. The goal was very strongly towards lean and clean JavaScript code; to follow JavaScript best-practice for coding - in the sense of optimal use of the JavaScript language itself; and not to attempt to squeeze it into a strongly-typed or object-orientated (in the C# or Java sense) paradigm - or in general bring to bear coding habits and patterns that come from C# and are not really 'at home' in JavaScript code.

          The work is taking place as a true open source effort, hosted on GitHub, and in touch with the community. I have been having a great time as a developer working in that context, and enjoying every minute of it!

          So far we have three projects on GitHub: jQuery Templates, jQuery Data Linking, and jQuery Globalization. We are also working on bringing our original Script Loader code into a form that might be optimal for jQuery. The globalization plugin was announced here, and is already seeing a lot of use. jQuery Templates has been under very active development recently, and will be the subject of some of my upcoming blogs. And jQuery Data-Linking will probably see some more intensive development in the coming weeks, and is likely to include some very interesting integration with jQuery Templates...

          I am looking forward to sharing more of these Open Source efforts with you over the coming weeks, starting with a series of blogs introducing jQuery Templates...

          Monday, September 20, 2010

          Dancing with Data

          Well, finally, this blog will start. After so long always planning to start a blog, but never actually doing so, now, my current work on jQuery templates is reaching the point where I really can't 'hide' any longer!

          The immediate purpose of this blog, then, will be to share with others what I feel to be the really rich potential of building dynamic Web applications using client-side templates, and in particular, the jQuery Templates I have been working on these past four months or so. But more broadly, I hope to share aspects of my "Dancing with Data" journey that I think may be interesting to others, or on which I would love to get feedback.

          Why "Dancing with Data"?

          I referred to my "Dancing with Data" journey, and in fact my journey through life has so often I feel drawn me into a fascination with apparent opposites. Dance and Data. Order and Chaos, Mathematics and Music, Science and Spirituality.

          I studied mathematics at college, went on to do research studies in theoretical physics (actually twistor theory) under Roger Penrose, then, rather than submit my doctoral thesis, went off in a different direction, getting involved in working in experimental theater and voice work, with the Roy Hart Theatre, and soon after, moving from the UK to France with the theater company, and also playing clarinet and composing music for theater performances.

          Then, some time later, music took me back to mathematics, in a sense: For a music composition I was working on, I got my first music software, sampling keyboard, and so on, and from there started to teach myself programming, and began to develop my own music software tools for composition and real-time improvisation. And basically it was music that took me into the world of software development, and ultimately to becoming a professional developer.

          So from there, it was "data" too that fascinated me. Not so much data itself, but data-driven applications and UI. In a sense, life itself is data-driven, if you think about genomes and DNA sequences, for example. Yet within that 'prescriptive' concept, so much richness and 'innovation', coming, as it were, from the meeting of chaos with order, through mutations and selection, with the interplay between gene expression and environmental factors. I would almost say that life itself, in fact, is a kind of dance with data.

          Right at the beginning of the emergence of XML I created a client-side (in the browser) declarative stylesheet language for transforming XML data fetched from the server, into HTML. This led me to become a member of the XSLT working group on the W3C. - And later, to join Microsoft, where I was a member of the team which created InfoPath before, later, joining the ASP.NET team. And most recently, it led me to be involved in working with the open source community and with jQuery, once again exploring this interplay between data and UI, where the user too is a player, and the result is an interactive responsive application; where the user, too, if you like, is 'dancing with the data'.

          Opposites

          Opposites then, but through that opposing dialectic, the richness of the interplay. I feel as if my contribution is about bringing together these opposites. Facilitating, in some way. Using my own logical analytic capabilities, but following at the same time some kind of intuitive path, a gut feeling, and seeking the innovative richness that can occur when the goal is not just to compete, or to emulate, (or, dare I say it - in some cases at least - to copy), the competition - rather, the goal is to follow what seems right, what seems to make sense, what seems to be suggested by the underlying patterns, what seems to fit the user need.