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.