Getting Started with AngularJS – The Application Module

As with all applications there has to be a starting point. Where does the application start? In AngularJS that starting point is the module.

And because a module is, well, modular, you can plug modules into each other to build the application, share components and so on.

Actually, I suppose in Angular it actually starts with a directive, that points to the module to start with, because, if you have more than one, which one do you start with?

<html ng-app="angularCatalogue">
  
</html>

The ng-app directive bootstraps the application by telling AngularJS which module contains the root of the application.

A module is defined like this:

angular.module("angularCatalogue",[])

The name of the above module is "angularCatalogue", the name of the application, which is what is placed in the ng-app directive in the html element previously.

You can also add as a second parameter to the module an array of other modules to inject. The modules don’t necessarily have to be loaded in any particular, so it is okay to refer to a module that may not exist at that point.

The module function returns a Module object, which you can then set up as you need it. Typically an application will have some sort of configuration, controllers, directives, services and so on.

Wiring up the view

In the html you will need to indicate where the view is to be placed.

You can do this via the ng-view directive, which can look like this:

<ng-view></ng-view>

or

<div ng-view></div>

Everything inside the element will be replaced with the contents of the view.

The application then needs to be told where the view is. You can configure the application module with that information, like this:

angular.module("angularCatalogue") 
    .config(["$routeProvider", function($routeProvider){
        $routeProvider.when("/",
            {
                templateUrl:"/ngapp/templates/search.html",
                controller: "productSearchController"
            });
    }]);

The config call on the module allows the module to be configured. It takes an array that consisted of the names of objects to be injected into the configuration and the function that performs the configuration.

The function has a $routeProvider injected into it. This allows routing to be set up. In the example above a route is set up from the home page of the application ("/") that inserts the given template into the element (ng-view) that designated the view and it uses the given controller.

I’ll move onto controllers in an upcoming post.

A note on the dependency injection

If you never minify you javaScript you can get away with something like this:

angular.module('myApplication')
    .config(function($routeProvider){
        ...
     });

You’ll notice that there is no array, it is just taking a function. Angular can work out from the parameter names what needs to be injected. However, if the code is minified most minifiers will alter the parameter names to save space in which case angular’s built in dependency injection framework fails because it no longer knows what to resolve things to. Minifiers do not, however, minify string literals. If the string literals exist then it will use them as to determine what gets resolved into which parameter position. The strings must match the position of their counterpart in the function parameters.

Therefore the minifier friendly version of the previous snippet becomes:

angular.module('myApplication')
    .config(['$routeProvider', function($routeProvider){
        ...
     }]);

A note on naming conventions

You can name things what you like but AngularJS has some conventions reserved for itself.

  • Its own services are prefixed with a $ (dollar). Never name your services with a dollar prefix as your code may become incompatible with future versions of angular.
  • Its own directives are prefixed with ng. Similarly to the previous convention, don’t name any of your directives with an ng prefix as it may clash with what’s in future versions of angular.
  • In javaScript everything is camel cased (the first word is all lower cased, subsequent words have the first letter capitalised), in the HTML dashes separate the words. So if you create a directive called myPersonalDirective when that directive is placed in HTML it becomes my-personal-directive.

Automatically replacing an image on an HTML page when it is not found.

The project I’m working on has just moved the image hosting to Amazon S3. Previously what happened was that we had a big folder full of images that had been uploaded from our users and that if the site needed to render an image it would check the directory for the image it needed, if it didn’t have it, it would look for the original and then resize and render that (storing the resized version in the folder so it can be found the next time). If the original couldn’t be found either it displayed a replacement image in place that was basically an image that said “There is no image available.”

That worked well enough with a small number of users but it really didn’t scale well.

Now that we’ve moved the hosting to Amazon S3 we create all the image sizes needed at the time they are initially uploaded. If we need a new size we have a tool that will go and create all the resized versions for us. The only issue that remains is that some images don’t exist for various reasons. Much of the legacy data came from systems that were installed on people’s desktops and the image data simply never got sync’ed to the central server properly.

But there is a way around this on the browser. The img tag can have an onerror attribute applied, which can then call a function which replaces the image src with a dummy image that contains the message for when there is no image.

For example:

<div>
  <img src="error.jpg" onerror="replaceImage(this, 'replacement.jpg');" title="This image is replaced on an error"/>
</div>

<script type="text/javascript">
  function replaceImage(image, replacementUrl){
    image.removeAttribute("onerror");
    image.src=replacementUrl;
  }
</script>

Although this looks a little ugly (putting in lots of onerror attributes on images) there is a lot less code to be written. When trying to achieve the same results in jQuery I eventually gave up. That’s not to say that it can’t be done, just that for pragmatic reasons I didn’t pursue it as I was spending too much time trying to get it to work.

The function does two things, first it removes the onerror because if the replacementUrl is also broken it will just recurse the call to the error handler and the browser will just slow right down. Second, it performs the actual replacement.

To see it in action there is an example page to demonstrate it.

I also tried to create a jQuery based solution to fit in with everything else. However, there were a couple of problems with a jQuery solution that were less than ideal.

  • You can’t attach an error event to the images because by the time you have done so the error event will be long past. You have to loop around all the images initially to find out which didn’t load before jQuery got a chance to get going.
  • For images that are added to the page by jQuery itself the .on does not work because delegated events, which allow you to create event handlers on elements before they are created, need the events to bubble up to a parent that did exist at the point the event handler was attached. The error event, among a small set of other events, does not bubble up. And if you attach it directly to the newly created element on the page then it will likely be too late, especially on a fast connection, as it will have already fired off the error event. You could do the same as before and check manually to see if the image loaded or not – but then the code is getting rather unwieldy and unmanageable.

In the end I found that the small bit of code that is called from the onerror attribute on each img element that needed it was more compact and didn’t require lots of extra lines of code to ensure that all the errors were corrected in the case that jQuery just didn’t get there in time.

Finally, if anyone has a solution in jQuery that does not require cluttering up the HTML, I’d like to see it

Quick guide to Geolocation in Javascript

In some modern browsers, such as Chrome and Firefox you can access the geolocation of the device. That is, where the device is physically located.

The main function for achieving this is getCurrentPosition, which doesn’t return a position as you might expect. Rather, it takes a callback (and optionally a second if you want to handle error conditions).

I’ve put together a small example page showing this, which I’ll now walk through.

In the example, when the user clicks on the button on the page it will attempt to get the physical location of the device. This may or may not work for several reasons. If it doesn’t work then the browser may not support it, or the user may refuse to give permission to the site, or the geolocation service may not be working.

This first bit of code checks to see if the browser supports the geolocation API and if it does calls the function to get the location passing in the callbacks for success and error handling.

if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(successCallback, errorCallback);
} else {
    displayErrorMessage("The browser does not support the Geolocation API.");
}

In this small example, the successCallback simply fills various spans with the results in the position and creates a URL that links to google maps to display a pin at the coordinates.

function successCallback(position) {
    $("#latitude").html(position.coords.latitude);
    $("#longitude").html(position.coords.longitude);
    $("#accuracy").html(position.coords.accuracy);
    $("#displayMap").attr("href", "http://maps.google.com/?q=" + position.coords.latitude + "," + position.coords.longitude);
    $("#displayMap").removeClass("disabled");
}

The position has a timestamp and a set of coordinates. Since the geolocation may be cached the timestamp will give you an indication of how old the geolocation is.

The coords gives you various bits of information about the geolocation. The three values that will always be available are latitude, longitude and accuracy. The other values (such as altitude, heading and speed) may be nullable. The accuracy is in meters and can be used to gauge how good the lat/long is. The Lat/Long is in WGS84 decimal degrees.

In the event of an error, the errorCallback will receive some indication about what went wrong. The most common may be that the permission was denied, but other potential errors exist.

function errorCallback(error) {
    switch (error.code) {
        case error.PERMISSION_DENIED:
            displayErrorMessage("The request was denied. If a message seeking persmission was not displayed then check your browser settings.");
            break;
        case error.POSITION_UNAVAILABLE:
            displayErrorMessage("The position of the device could not be determined. For instance, one or more of the location providers used in the location acquisition process reported an internal error that caused the process to fail entirely.");
            break;
        case error.TIMEOUT:
            displayErrorMessage("The request to get user location timed out before the operation could complete.");
            break;
        case error.UNKNOWN_ERROR:
            displayErrorMessage("Something unexpected happened.");
            break;
    }
}

 

How your browser reacts to requests for geolocation

Your browser may give you some form of alert to indicate that the site is requesting the geolocation. Chrome, for example, displays a bar just under the omnibox

Chome asks if it is okay to use geolocation

If a site has permission to get the geolocation then the icon above will be displayed in the omnibox to the right of the URL. If not, the icon will have a red cross over it. You can click this icon to change the settings at any time.

 

Finally, if you want to read the spec in full, it is available here: http://www.w3.org/TR/geolocation-API/

Pomodoro

I keep hearing about friends using The Pomodoro Technique and I’ve decided I really need to just try it out for myself. I’m not yet sure if it will work for me, but I’ve been hearing positive things about it.

To that end I set myself the task of a small project using it, that is to create a web page with a pomodoro timer with a visible indicator of time left and that makes a noise when the timer expires. The final pomodoro is to write up this blog post.

This task has a mix of things I already know about (putting together a web page with HTML, CSS, JavaScript and jQuery) and things I would have to look up (like how to get a web page to emit a sound at a given point, have it respond to events at timed intervals, and deploy it to the web via Amazon’s AWS).

What I found was that 25 minutes actually goes past very quickly. Secondly, and this is more because it is the Christmas holidays, I still need to discipline myself not to jump to Facebook or Twitter each time my phone beeps or chirrups a notification at me. Similarly, in work I would probably have to discipline myself not to jump to Outlook or Skype when they pop up notifications.

On the whole, it looks like it could be fairly advantageous and I’ll continue to see if it helps productivity.

For the moment, if you do want to have a look at the very simple pomodoro timer that I created, then you can access it here: http://pomodoro.colinmackay.co.uk – I’m also happy to take suggestions on improvements if you think it could be made better.

Developer Tools in IE Hides Bug

The other day I put some code on our UAT (User Acceptance Testing) server so that some new code could be tested and I started received a very alarming bug that one of the pages simply didn’t work at all. The page was in an administration section of the website and relied heavily on JavaScript even just to display the initial content (which was retrieved via an AJAX request)

As a quick initial smoke test I loaded the page up on my machine and it was working using my developer build. Then I looked at the page on the UAT server in case it was some quirk of the build and it was also working. I then noticed that the person doing the tests was running IE, so I though it might be a browser issue, so I loaded the page from the UAT server up again, this time using IE and it was still working on my machine.

Since it was lucky enough that the particular section was an admin section (which would be used only in-house) the people testing it were not actual customers of ours so I could walk over to their desk and ask for a demonstration in case there was some quirky step that had to be undertaken. When the page was loaded up I immediately saw that it didn’t work.

Being a developer my first instinct was to open up the Developer Tools in IE and have a look at what was happening. So I hit F12 and the reloaded the page…. and it started to work!  It worked with the Developer tools turned on!

I couldn’t fathom that out. What was so different about Internet Explorer when the Developer Tools were turned off so I started going through the various things that IE was showing me in the developer tools, stepping through code and watching the AJAX request go out then come back with data and start to process that data…. And then I noticed it. There was a line that said:

console.log("blah… blah…. blah…");

On a regular user’s machine the Developer Tools are never running, so it never has a console, so the JavaScript just broke.

Demonstrating the bug

How you you try this out? I’ve written a small demo to show what I mean. Obviously, you need to open it in Internet Explorer. I’ve tried it in IE 8.

If you have already opened the Developer Tools previously then you may find that they open automatically, which makes any testing impossible. Shutting them down and restarting IE doesn’t help. You have to go in to the registry and manually disable the developer tools.

To disable the Developer Tools in Internet Explorer you need to edit the system registry. Open up regedit and navigate to HKCU\Software\Microsoft\Internet Explorer\IEDevTools then create a DWORD called Disabled and give it the value of 1.

Once you have disabled the Developer Tools you’ll see that the page displays the text:

This paragraph has been update by javascript.

This paragraph is not yet updated by javascript, and if the Developer Tools are not present, it won’t update.

And a small warning triangle appears in the status bar of IE. Double clicking on the warning triangle brings up a dialog with some error information that looks like this:

To re-enable the Developer Tools simply delete that setting and restart Internet Explorer, press F12 to bring up the developer tools then open the demonstration page again.

Now the text displayed on the page reads:

This paragraph has been update by javascript.

This paragraph has also been updated by javascript, indicating the developer tools are present

Preventing this bug

Obviously running functions on the console object is not all that desirable in a production system so the idea is to remove all those calls so that IE won’t crash. If you find that is impractical you could put in some JavaScript before other JavaScript is run such as the following:

if (window.console === undefined) {
  console = {};
  console.log = function(){};
}

This will ensure that if a console object does not exist then one is created and a dummy function is attached to it. If you use other functions on the console object then you should add them also in a similar way.

The above demonstration has been updated to show this console “protection” in action.

 

Kendo UI: parse – preprocessing data

When retrieving data, it may not be formatted as you would need it. Most obviously, dates are the most likely candidates as the grid can work with them much more easily if they are javaScript Date objects rather than any text or numeric representation. It should be noted however, that if by simply telling the dataSource configuration that the schema of the a specific field is a date then it may be able to work out the format for itself and you don’t need a parse function to help. However, for this example, assume you must convert the type of the value.

dataSource : schema : parse

The dataSource configuration allows you to specify a function that is called when the data needs to be preprocessed in some way.

The parse function takes a parameter where by it passes the object containing the data. The function must return the processed data. In my example I’ve simply replaced the values in the existing structure with the processed version.

function preprocessData(data) {
  // iterate over all the data elements replacing the Date with a version
  // that Kendo can work with.
    $.each(data, function(index, item){
      item.Date = kendo.parseDate(item.Date, "yyyy-MM-dd");
    });
    return data;
}

The JSON structure contains a date in a string with a specific format containing a 4 digit year, followed by a two digit month, followed by a two digit day, separated by dashes. However, the grid can work with dates more easily if they are Date objects, which is what the kendo.parseDate() function returns.

Dealing with percentages

In a previous post I mentioned that you can format a number as a percentage by using a specific format in the kendo.toString() function call. Unfortunately, that may not be the best solution in all cases. If your data is not going to be filtered and it is in range of 0 to 1 representing 0% to 100% then that solution is fine. However, if you want to filter on the data then you probably don’t want to do that, as you’d have to enter set up the filter in the same way as the source data – and it is not intuative for the user to have to type “”0.5″ when they need “50%”.

What you can do instead is ensure that the data is in the form that 100.0 is 100%, and so forth. You can use the parse function to coerce the data if you need to do that. Once you have this the filters become more intuative from the user’s perspective. Also, instead of using the built in format for parsing percentages you will need to use your own, such as “0.0″, which ensures that the value has one digit after decimal point. For example:

template:"#= kendo.toString(Rpi, \"0.0\") #%"

Filtering on a percentage column

The grid configuration

$(function(){
  var data = getData(); // From the economic-data.js file
  $('#MyGrid').kendoGrid({
    dataSource: {
      data: data,
      pageSize: 10,
      schema: {
           parse: function(data){
             return preprocessData(data);
           },
          model: {
          fields: {
            Date: {type: "date" },
            Rpi: {type: "number" },
            Cpi: {type: "number" },
            BoeRate: {type: "number" }
          }
        }
      }
    },
    filterable: true,
    columnMenu: false,
    sortable: true,
    pageable: true,
    scrollable: false,
    columns: [ 
      { field: "Date", template: "#= kendo.toString(Date, \"MMM yyyy\") #" }, 
      { field: "Rpi", title: "Inflation (RPI)", template:"#= kendo.toString(Rpi, \"0.0\") #%" }, 
      { field: "Cpi", title: "Inflation (CPI)", template:"#= (Cpi !== null ? kendo.toString(Cpi, \"0.0\")+\"%\" : \"-\") #" },
      { field: "BoeRate", title: "Base Rate", template:"#= kendo.toString(BoeRate, \"0.0\") #%" }
    ]
  });
});

More information

For this post the data is a mash up of UK Inflation data since 1948 and Bank of England Base Rates since 1694. I’ve only used the intersecting dates of both datasets.

The economic-data.js file is available as a github gist.

There is also a working example of this code.

Kendo UI: Paging and accessing the filtered results in javaScript

Moving on slightly from my last post on the Kendo UI Grid we’re going to take a wee look at paging and accessing the results of the filter in javaScript.

pageable : true

By default paging is turned off. This means that when the grid is rendered you get all the data displayed in one go. If the amount of data is small then this
may be fine. However, if the amount of data runs into the hundreds of rows (or more) then you’ll probably want to turn paging on in order to make the display of the data more manageable for the user and potentially to reduce the amount of data send to the browser (but that part is for another day – in this example I’ll be using the same data set as previously which is loaded all at once).

To enable paging add to the configuration pageable : true and also remember to add in to the dataSource part of the configuration the
pageSize that you want.

If you forget to put the pageSize in then the grid will display with all the elements, but the paging navigation bar will display a message such as “NaN – NaN of 150 items”

scrollable : false

By default the grid is scrollable. This is useful if you have something to scroll, such as the virtualised scrolling feature. But for the paging in this example, the scroll bar is simply displayed but not enabled.

To turn off the scrollbar, in the configuration set scrollable : false and the scroll bar will be removed.

Getting the filtered results in JavaScript

It is possible to get the results of the filter out of the grid. It isn’t actually a direct feature of the grid (or the dataSource) but it is possible in a round about sort of way.

Essentially, what needs to happen is that filter object in the grid is used to query the data all over again to produce a second result set that can be used directly in JavaScript.

In the example below, I’ve got the results of the filter being rendered into a unordered list block.

It works but first getting hold of the grid’s data source, getting the filter and the data, creating a new query with the data and applying the filter to it. While this does result in getting the results of the filter it does have the distinct disadvantage of processing the filter operation twice.

function displayFilterResults() {
  // Gets the data source from the grid.
  var dataSource = $("#MyGrid").data("kendoGrid").dataSource;

  // Gets the filter from the dataSource
  var filters = dataSource.filter();

  // Gets the full set of data from the data source
  var allData = dataSource.data();

  // Applies the filter to the data
  var query = new kendo.data.Query(allData);
  var filteredData = query.filter(filters).data;

  // Output the results
  $('#FilterCount').html(filteredData.length);
  $('#TotalCount').html(allData.length);
  $('#FilterResults').html('');
  $.each(filteredData, function(index, item){
    $('#FilterResults').append('<li>'+item.Site+' : '+item.Visitors+'</li>')
  });
}

The results look like this:

The filter results in 12 of 150 rows returned.

National Galleries of Scotland (Edinburgh sites) : 1281465
Edinburgh Castle (Historic Scotland) : 1210248
Kelvingrove Art Gallery & Museum (Glasgow) : 1070521
Royal Botanic Garden Edinburgh : 707244
Gallery of Modern Art (Glasgow Museums) : 490872
People's Palace (Glasgow Museums) : 245770
Burrell Collection (Glasgow Museums) : 187756
Museum of Transport (Glasgow Museums) : 160571
St Mungo Museum of Religious Art (Glasgow Museums) : 143017
Provand's Lordship (Glasgow Museums) : 107044
Scotland Street School Museum (Glasgow Museums) : 49346
Glasgow Museums Resource Centre : 9059

Full grid configuration

Here is the full configuration of the grid for this example:

$(function(){
  var data = getData(); // From the bva-data.js file
  $('#MyGrid').kendoGrid({
    dataSource: {
      data: data,
      pageSize: 10,
      schema: {
        model: {
          fields: {
            Site: {type: "string" },
            Visitors: {type: "number" },
            FreeCharge: {type: "string" },
            Change: {type: "number" }
          }
        }
      }
    },
    filterable: true,
    columnMenu: false,
    sortable: true,
    pageable: true,
    scrollable: false,
    columns: [ 
      { field: "Site" }, 
      { field: "Visitors" }, 
      { field: "FreeCharge" },
      { field: "Change", template: "#= kendo.toString(Change, \"p\") #" }
    ],
    dataBound: function(e) {
      displayFilterResults();
    }
  });
});

The getData() method can be found here: https://gist.github.com/3159627

Example: paging demo.

Updates

  • 24/7/2012: Added a link to a demo

Telerik’s Kendo UI Grid

I’ve recently started to use Telerik’s Kendo UI framework for web applications and I have to say I’m very impressed. Although it does come with a bunch of server side extensions for ASP.NET MVC I’ve found that the javascript configuration to be just as easy.

Sample Data

For these posts I’ll be using various sample data. In this post, the data is visitor numbers to UK tourist attractions which I got from The Guardian.If you want to take the data and play with this sample, you can find the bva-data.js file as a gist on github.

I pulled the data into a .NET application and converted it to JSON. First I took the spreadsheet I downloaded and then saved it as CSV file. I brought it into my .NET application using a .NET CSV Reader I found on Code Project.

Grid configuration

$(function(){
  var data = getData(); // From the bva-data.js file
  $('#MyGrid').kendoGrid({
    dataSource: {
      data: data,
      schema: {
        model: {
          fields: {
            Site: {type: "string" },
            Visitors: {type: "number" },
            FreeCharge: {type: "string" },
            Change: {type: "number" }
          }
        }
      }
    },
    filterable: true,
    columnMenu: false,
    sortable: true,
    columns: [ 
      { field: "Site" }, 
      { field: "Visitors" }, 
      { field: "FreeCharge" }, ]
      { field: "Change", template: "#= kendo.toString(Change, \"p\") #" }
    ]
  });
});

First off, getData() is a simply loads the data so it is available in one array to start with. I didn’t want to complicate this with having lots of calls to other services.

The schema defines how the data is to be interpreted.

filterable defines if the grid columns can be filtered or not. How that filter is represented to user depends on whether columnMenu is true or false.

filterable : true

When filterable is set to true then an icon will appear in the right of the column header to indicate that you can apply a filter.

The filter allows you to specify one or two criteria for filtering the column.

Kendo UI Filterable Grid

Example: filterable demo.

schema

I’m not going to go too much into the schema at the moment. Suffice to say that it allows to to define how the grid interprets the data that has been sent to it.

In this example, I’m using the schema to define the type of each field in the data. That way the filtering options can interpret the data correctly. For example, the Visitors column is a number, so it would be better to give filter options such as “greater than” or “less than” instead of the default string filter options of “contains” or “starts with”. Like this:

Numeric filter on a Kendo UI Grid

Other data types that the schema.model can interpret are string (the default), boolean, and date.

columnMenu : true

By default, if you don’t specifiy a columnMenu, it will be false. and you won’t get the menu. If, however, you set columnMenu to true then there will be a small down-arrow displayed which when clicked displays the menu.

Without any other settings, the menu will just allow you to turn on and off columns. If you set sortable to true then you also get the “Sort Ascending” and “Sort Descending” options. And if you set filterable to true then you get a menu item for filtering the data as the menu item replaces the icon for filtering the data in the column header.

The image below shows the columnMenu with the sortable and filterable options turned on.

Kendo UI Grid Column Menu

Example: columnMenu demo.

template

In the definition of the Change column is a template parameter. This defines how the column should be displayed if it should not be simply displayed as is.

In this example, all that is happening is that the number is being represented as a percentage. The data contains the information as a floating point number so that a value of 0.05 is displayed as 5%.

Templated values are set between two # markers. After the opening marker you can put an equal sign or colon depending on how you want the value rendered. The = indicates the value is rendered as is, the : indicates that the value is to be HTML encoded before being rendered.

There is a toString function that allows you to format data in various ways. In this example, I’m taking a number and formatting it as a percentage. Like this:

#= kendo.toString(Change, "p") #

Just remember that if you have quotation marks inside your template to escape them if needs be for the code that the template is defined within.

Updates

  • 24/7/2012: Added links to demos.

JsRender looping, nested objects, and conditional statements.

So far, I’ve posted a couple of very basic introductory posts on JsRender. In this post, I’ll get a little bit more into the meat of the templating language and show looping, conditional statements, and some other bits and pieces.

In the example, I’ve put together a supermarket receipt. It shows the items bought, their quantities and any savings from offers. Here’s the data:

var theReceipt =
  {
    items:
      [
        {
          description:"800g Wholemeal Bread",
          quantity:2,
          price:1.05,
          offer: {qty_needed:2, price:1.90}
        },
        {
          description:"Kellog's Fruit & Nut",
          quantity:1,
          price:2.69
        },
        {
          description:"2 litres Semi-skimmed Milk",
          quantity: 3,
          price:1.18,
          offer: {qty_needed:3, price:3.00}
        },
        {
          description:"1 litre Pineapple Juice",
          quantity:2,
          price:1.10
        }
      ],
      total: 9.79,
      saving: 0.74
  };

The data contains an array of items, each of which contains the the description, quantity, and price of each item. On some items there is also details of any offer. There is also the precomputed total and the saving that the customer has made.

Looping

In the previous post I showed what happens when the object you pass JsRender is an array. But what if the data contains an array as some sub-element? In that case you can use the for tag followed by the name of the array to indicate the start of the loop (and which array to loop over). At the end of the loop repeat the tag but with a slash in front of it (rather like HTML). For the data above, it would look like this:

{{for items}}
  Put repeating template here
{{/for}}

The tags inside the for block will be for current element. So, for the items above, I could use tags such as description, quantity, and so on.

Conditional statements

You can render parts of a template conditionally if you like. You can use the if tag to do that. Again at the end of the block, you put the slash in front of the tag to indicate its end.

{{if some_condition}}
  Put template to render if true here.
{{else some_other_condition}}
  Put template to render here if the second condition is true.
{{else}}
  Put template to render here if previous conditions are false.
{{/if}}

In the example, the test is whether the offer object exists or not. However, it acts just like an if conditional statement works in javascript. So if offer evalates to false, zero, etc. then it will be regarded as false, other values are regarded as true.

{{if offer}}
  <tr>
    <td></td>
    <td><em>{{:offer.qty_needed}} for £{{:offer.price}}</em></td>
    <td><em>save:</em></td>
    <td><em>£{{:offer.price - (quantity * price)}}</em></td>
  </tr>
{{/if}}

Nested object

In the looping section you can access the elements of each item being iterated over. The looping mechanism takes care of that for you, so when you are in the loop each tag is an element of the current item.

You can, as you can see in the conditional statements section above, also see that you can use the standard dot-notation to access nested elements. In this case the elements in the offer object.

Calculations

In the conditional statements section you can see some basic calculations.

{{:offer.price - (quantity * price)}}

The result of the calculation will be rendered to the page.

Rendering options

You will have noticed that templating statements are all in two braces. Where something is rendered the initial opening braces are followed by a colon. This simply outputs the results directly on to the page. This is great if the output is safe (or it is HTML), however if you want to ensure that the output is correctly encoded for a web page you can use a right-cheveron.

  {{:some_html_to_be_rendered}}
  {{>some_text_to_be_escaped}}

The example

The example for this post can be found here. You are encouraged to view the source of the example.

JsRender and arrays

Previously, I showed how to very quickly get up and running with JsRender witha very simple hello world demonstation. In this post I’ll be extending things a little further showing you how simple arrays of data are handled.

For this demo I have an array of data representing photos from my flickr account. This is what the data looks like:

var thePhotos =
  [
    {
      "title":"Forth Road Bridge",
      "thumbnail":"http://farm1.staticflickr.com/1/2843652_f542c664ed_q.jpg",
      "url":"http://www.flickr.com/photos/colinangusmackay/2843652/in/photostream"
    }, {
      "title":"Forth Bridge",
      "thumbnail":"http://farm1.staticflickr.com/1/2843680_58c5c8003b_q.jpg",
      "url":"http://www.flickr.com/photos/colinangusmackay/2843680/in/photostream"
    }, {
      "title":"Helmsdale",
      "thumbnail":"http://farm1.staticflickr.com/4/5441773_2929a2ebdf_q.jpg",
      "url":"http://www.flickr.com/photos/colinangusmackay/5441773/in/photostream"
    }, {
      "title":"Scottish Parliament",
      "thumbnail":"http://farm1.staticflickr.com/3/6340272_0e7ad78251_q.jpg",
      "url":"http://www.flickr.com/photos/colinangusmackay/6340272/in/photostream"
    }, {
      "title":"Space Needle",
      "thumbnail":"http://farm3.staticflickr.com/2013/2410201132_356ff1a147_q.jpg",
      "url":"http://www.flickr.com/photos/colinangusmackay/2410201132/in/photostream"
    }
  ];

The template defines how to render a single element in the array. There is also a special token available {{:#index}} which allows you to get the index value into the template. In the example below, I’m adding one to it in order to put a sensible number next to the photo.

As you can also see, you can place template placeholders in many places, includeing inside attributes in HTML elements.

The template looks like this:

<script id="photosTemplate" type="text/x-jsrender">
  <div class="photoFrame">
    <span class="index">{{:#index+1}}</span>
    <a class="photoLink" href="{{:url}}">
      <span class="photoTitle">{{:title}}</span>
      <img class="photo" src="{{:thumbnail}}" alt="{{:title}}"/>
    </a>
  </div>
</script>

The code to render the template and add it to the page is pretty much the same as last time.

I’ve also put together a full example to look at, feel free to look at the source of this page.

Follow

Get every new post delivered to your Inbox.