How to support JSON-P on the server

Just a quick note for how to modify a standard JSON reply to support requesting data across domains

The answer here is really quite simple …if the &callback=something parameter is provided, then:

    //JSONP opening
    if ( callback != null )
        jsonBuf.append ( callback + "(" );
    
    //Beginning of standard reply
    JSON data
    //End of standard reply
    
    //JSONP closure
    if ( callback != null )
        jsonBuf.append ( ");" );

If you’re like most people, and JSON-P is being considered long after all of your REST end-points have already been created, then coding a method that simply wraps the existing REST replies within the “something( normal rest reply );” construct is a very fast way of supporting cross-browser scripting for rest clients.

  • It appears there’s a performance penalty for using JSON-P instead of straight JSON replies. See http://jsperf.com/ajax-jsonp-vs-ajax-json for more information.
  • Just FYI, Jersey already supports JSON-P with a simple annotation of the REST end-points, and a minor wrapping of the reply as noted above. Further, Jersey recognizes the application/x-javascript mine type to return a JSON-P response without requiring the &callback= query parameter.
  • JSON-P is a mature enough technology that JQuery, Dojo, YUI, MooTools, Windows WCF, Sencha Touch, IBM BPM, and most other relevant web client and server products now support it.
  • Our chosen DataTables also supports JSON-P with the following modification:
    "fnServerData": function( sUrl, aoData, fnCallback, oSettings )
    {
       oSettings.jqXHR = $.ajax(
       {
          "url"       : sUrl,
          "data"      : aoData,
          "dataType"  : "jsonp",
          "cache"     : false,
          "success"   : fnCallback
       } );
    }
    

A New Kind of Stylesheet

Adding Variables to CSS

Goal


Make it MUCH easier for customers to brand Web-based products

Note that the primary goal here is NOT to make it easier for developers to create CSS files. The primary goal is for CUSTOMERS to more easily modify CSS files. In other words, even though we could modify CSS in much more dramatic ways to make it easier for developers to create these files, the goal here is not developers, rather end users. So, the CSS file needs to remain as user friendly and familiar as possible while still making it much easier to brand the CSS.

Problem Statement

  • CSS files usually contain hundreds of color and font codes
  • Color and font codes that should be the same are sometimes slightly different. E.g., dark gray is sometimes #333333; sometimes #313233. Dumb.
  • It’s very difficult for customers to find, understand, and properly change these codes

We need to find a solution that makes it easier for customers to modify our CSS files without having to hunt-and-peck for the relevant colors codes.

Solution 1

  • A wonderful package supporting all of the latest proposed CSS features such as variables, mixins, operations, functions
  • I’d love to use this package. However:
    • it is written in JavaScript and therefore requires Node.js and Rhino
    • that’s 68MB worth of files I need to lay down on customers’ computers
    • over > 5000 files
    • from Java, would have to do an external execution in order to compile our CSS files
    • Even if I automated this work, it’s an awful lot to ask of customers just to have variables in CSS

I can’t use Less because I need to find a solution that consumes very little resources to compile the CSS

Solution 2

  • Like Less, a package supporting all of the latest proposed CSS features including variables, mixins, operations, functions, nested rules, conditional expressions, and more.
  • From a developer’s perspective, this is the package I’d choose (I think it’s slightly better than Less).
  • However I can’t for many of the same reasons as Less:
    • it is written in Ruby (a great language) and therefore requires a Ruby interpreter on customers’ computers
    • For a Windows environment, that’s 30MB worth of files I need to lay down on customers’ computers
    • over > 93,000 files
    • and like Less, I’d still have to do a slow, external execution environment offering little control over the compilation of our CSS files
    • Even if I automated this work, it’s an awful lot to ask of customers just to have variables in CSS

I can’t use Sass because it requires Ruby and lots of resources to compile the CSS. I need something that is light-weight, preferably runs in Java, and allows me to make tweaks should I need to.

What’s Coming in CSS

Looks like whatever solution I find, it’s going to be somewhat temporary since the W3C is already under way to add some of these awesome features into CSS.

The ideal solution would not only be easy to use for customers, but would also easily migrate to the standard solution once that’s fully supported by all browsers in a year or two.

Seeing that the goal is to make it easy for customers to brand our CSS, the ideal solution will look as much like standard css as possible. In other words, it will NOT use all these new Less and Sass CSS features. Bare minimum is best.

Solution 3

  • ZUSS is a pure Java package; that’s good already since that means it can be part of my standard development environment. I can use either the jar directly, or modify the source code as needed.
  • It’s tiny
    • 89K (Wow!! — compare that to Less and Sass above)
    • 73 files in 1 jar (again Wow!)
  • ZUSS supports most of the new CSS features the other packages support:
    • Variables
    • Mixins
    • Nested Rules
    • Functions
    • Includes
    • Conditional Expressions
  • ZUSS provides a small servlet that compiles the CSS files on demand (when requested from the browser)
    • This allows our CSS to be either in a War file (which is how Web products are usually distributed) or in an external directory where customers could copy and edit the files.
    • Caches CSS for future requests
    • Recompiles as CSS files are changed
  • ZUSS is licensed under the GNU Lesser GPL which means it’s very developer and distribution friendly

Fonts

Here’s how a font is defined in my new CSS:

@global-font-family()
{
   font-family: Helvetica, Arial, sans-serif;
}

Notice that it begins with an @ symbol. This designates a variable in the ZUSS language. In other words, global-font-family() becomes a mixin when used.

Notice also that global-font-family() contains a full CSS attribute declaration: font-family: Helvetica, Arial, sans-serif;    We could have included any number of other attribute definitions, for example size, color, margins, line height, font weight and style, etc. Anything placed within the braces is included when used elsewhere in the CSS file.

Here’s the mixin used elsewhere in the CSS:

.welcomeHeader
{
   @global-font-family();
   font-size: 2em;
}

Sweet !!

Colors

Here’s how a color is defined in my new CSS:

@product-color: #8cc63f; /* product name in nav bar, links, quote bin header, active button background, slider value, bread crumb sep */

Any time I want to use that color, I simply:

.headerLogoText
{
   color: @product-color;
}

Functions

If you paid attention to the comment in the color variable defined above, you’ll note we’re using that same color in lots of areas throughout the product. A good 15 places use that color directly, as is. However, buttons have gradients, hovers, and pressed states. Links change colors when hovered or visited.

And we’d like to use a “faint” version of the color when selecting items in rows. Rather than having the customer specify all the variants of a given color, wouldn’t it be cool if we could automatically “derive” the color from the primary color. That way, all the customer has to specify is a single color …and none of its variants.

ZUSS offers two kinds of functions to do this type of task:

  • A simple function defined in CSS permitting basic math functions and color manipulations
    @lighten(@color, @diff: 10%): @color * (1 + @diff);
  • Java-defined functions that can be called directly by our CSS and can provide any range of sophistication
    @lighten(@color, @diff: 10%): @import com.netiq.agility.client.internal.ColorUtils;

We chose to go with the more sophisticated Java-based functions permitting more accurate color calculations.

  • Here’s our ColorUtils.java class in which we created a series of high-fidelity color rendering methods
  • These are based on the HSB (Hue, Saturation, Brightness) color model which is also supported by the basic Java Color class and by Photoshop.
    • It’s much easier to make a color brighter by simply adjusting the “brightness” factor than trying to calculate Red, Green, and Blue values.

Derived Colors

Now that we have color variables and high-fidelity color manipulation routines, let me show you what we did for the single “product color” which I think you’ll agree most Web interfaces have:

/* User-provided Colors */
@product-color:                     #8cc63f;   /* product name in nav bar, links, quote bin header, active button background, slider value, bread crumb sep */

/* Derived Colors - users do NOT need to edit these colors */
@product-color-lighter:             @lighten   ( @product-color, 15% );
@product-color-darker:              @darken    ( @product-color, 15% );

@product-color-hover:               @highlight ( @product-color, "-92%" );
@product-color-hover-lighter:       @lighten   ( @product-color-hover, 3% );
@product-color-hover-darker:        @darken    ( @product-color-hover, 5% );

@product-color-select:              @highlight ( @product-color, "-78%" );
@product-color-select-lighter:      @lighten   ( @product-color-select, 3% );
@product-color-select-darker:       @darken    ( @product-color-select, 5% );

/* hover */
@active-bhover-color:               white;
@active-bhover-background-color:    @lighten   ( @product-color, 10% );
@active-bhover-background-start:    @lighten   ( @active-bhover-background-color, 5%);
@active-bhover-background-end:      @darken    ( @active-bhover-background-color, 12%);
@active-bhover-border:              @darken    ( @active-bhover-background-color, 15%);
@active-bhover-shadow-color:        @shadow    ( @active-bhover-background-end );

/* pressed */
@active-bdown-color:                black;                                          /* invert the hover color */
@active-bdown-background-color:     @darken    ( @product-color, 5% );
@active-bdown-background-start:     @active-bhover-background-end;                  /* invert the hover color */
@active-bdown-background-end:       @active-bhover-background-start;                /* invert the hover color */
@active-bdown-border:               @darken    ( @active-bdown-background-color, 12% );
@active-bdown-shadow-color:         @shadow    ( @active-bdown-background-end );

We’ve created 20 variants on the primary user-provided “Product Color”. These 20 colors are then used throughout the CSS whenever a product-color-related accent is desired.

  • Links (normal, hover, visited)
  • Buttons (gradients for normal, hover, pressed)
  • Product logo
  • Header colors
  • Scroll bar thumb
  • Bread crumb separators
  • Triggers in various UI widgets (combo, spinner, date picker, etc.)
  • List selection and hover
  • many other UI elements use versions of the product color !

In all, there are hundreds of places throughout the CSS where these 21 colors are used.

I think you’ll agree, that’s a lot of benefit for the customer …and they only had to define 1 color value to do so !!!

Note that in our final implementation, we ask the user to define approximately 15 primary colors in a single location at the top of the CSS file. And that’s it. Press refresh in your browser, and the entire color scheme changes throughout.

Includes

To make our files even simpler, we used ZUSS’s include ability to hide our function declarations and derived color definitions in separate include files that our customers will never see as they edit the CSS to make their own Themes.

@include functions.ncss;
@include derived_colors.ncss;

Provide a Theming Generator

Come to think of it, now that our CSS is sssssoooooooo simple, we could very easily produce a simple dialog within our product that allows the user to define the colors right from the UI …rather than having to find/copy/edit/save the CSS in the file system.

This “Theme Creator” dialog would be very simple to create. Just ask for a small set of color and font definitions, show examples of each in action, ask for a Theme name, and that’s it.

I’ll leave this for a future exercise to blog about.

So, which table is best?

I propose DataTables is the best choice for any project wanting to provide a single solution for both desktop and mobile devices.

While both jqGrid and DataTables are excellent technology and both meet the “good enough” criteria, DataTables has a slight edge for mobile devices.

* note that SlickGrid was eliminated as a candidate.

Here are my reasons for proposing DataTables:

  • DataTables has a smoother scrolling algorithm on mobile devices (iPad 3)
  • DataTables auto-eliminates the scroll bar and uses the device’s scrolling method
  • jqGrid’s styling is more heavily bound to JQuery UI, creating greater conflict as we try to be JQuery Mobile compliant
  • DataTables implements Virtual Rendering …deferring draw calls until needed
  • By Default, DataTables download size is considerably smaller: 25K vs 68K
  • DataTables has an excellent unit test suite comprising over 2800 tests
  • DataTables provides over 130 pre-built examples
  • DataTables provides a nicer ability to “expand” a row to show additional detail

Of course, jqGrid also has some advantages over DataTables. However, we do not need these in our current solution. For more details, see the jqGrid Evaluation post.

Using DataTables with ThemeRoller – Mobile styles

Since our project requires a single code base for both desktop and mobile clients, the list we choose needs to look good in both places. Ideally, we could limit ourselves to just the JQuery-Mobile styles, and it would look good on both. This post attempts to investigate that objective:

Useful Links

What styles apply to a list?

Here’s my first attempt at styling a DataTables table using JQuery-Mobile styles

Ignore how ugly it looks …I’m just learning about JQuery-Mobile styles, and I’m trying lots of different things in this image all at once.

NOTE 1: I have not yet redefined the style definitions in my Theme-Roller produced stylesheet. That’s why it looks so ugly.

NOTE 2: I tried letting JQuery-Mobile apply its styles based on the data-role type attributes …but you’ll note that doesn’t seem to work for a dynamically-produced table

NOTE 3: For now, I’m using swatch “A” from my stylesheet. Not quite sure yet if I’ll want to create a swatch just for tables or not. For now, I’m thinking no …each swatch could redefine the table’s appearance.

Here’s what I learned

JQuery Mobile – Applying the correct List styles

  • For now anyways, the closest thing to tables JQuery-Mobile has support for is “lists”
  • Therefore, I applied the following styles which are the same styles JQuery-Mobile lists use:
    • table headings – ui-li ui-bar-a
    • rows (<tr>) – ui-li ui-btn ui-btn-up-a
    • row hovers – ui-btn-hover-a
    • Heading data in cells – ui-li-heading
    • Normal text in cells – ui-li-desc
    • Bolded data in cells – just use <strong> around text within the ui-li-desc div
    • I still need to style the pagination control. I will probably use DataTable’s various $.fn.dataTableExt.oStdClasses.* variables to do that.
      • I guess on that note, you’ll find that I set the “bJQueryUI” flag to false
      • JQuery UI’s styles just conflict too much with JQuery-Mobile’s styles

Making Changes to the List style definitions

  • I also updated some of the styles in my ThemeRoller-produced style sheet
    • added ui-bar-a:hover – to give a hover effect on the column headers

JQuery Mobile – “Data-Role” Attributes

  • I also had to mess around with a few other things to get it to behave properly within a JQuery-Mobile environment
    • just to be proper, I added the “ui-listview” style to the DataTables table object
    • likewise, I added the data-role of “listview”
    • I had to redefine the display attribute for rows to table-row
    • and did the same thing for header rows: display:table-row;
  • Note the data-icon=’arrow-r’ text in the bar above the table. See the little “right arrow” icon at the far-right of the bar. Seems to work fine.
    • Now take a look at the same text in each row’s “Name” column. The text is there, but the actual icon isn’t.
    • In other words, I can’t seem to get JQuery-Mobile to dynamically render my styles within the table. More on this in a future post I suspect :-)

DataTables – sDOM – moving things around

  • Take a look at the navigation and search bars …they’re way at the top of the screen
    • That’s because I created my own <div>s and wanted to move these controls elsewhere in the document
      • var search = $(‘.dataTables_filter’); $(‘#search’).append ( search );
      • var navBar = $(‘.dataTables_paginate’); $(‘#page_nav_bar’).append ( navBar );
    • Why didn’t I just use sDOM to move things around?
      • Because sDOM can only create the various DataTable controls above or below the table (even both).
      • But it cannot create them disconnected from the table. In my case, I will have other controls between the table’s search box and the table itself.
      • I think using JQuery’s append() method to move things around is quite nice …except it does this after the items are already attached to the DOM …this might be a flicker or speed issue. More on this later…

SlickGrid Evaluation

SlickGrid Links

- Home: https://github.com/mleibman/SlickGrid/wiki
- Examples: https://github.com/mleibman/SlickGrid/wiki/Examples
- AJAX paging: http://mleibman.github.com/SlickGrid/examples/example6-ajax-loading.html
- Used By: https://github.com/mleibman/SlickGrid/wiki/Used-by

NOTE

A full evaluation of this product was not performed. Although I spent as much time in the evaluation as the other tables, I determined that SlickGrid is no longer a candidate for our use.

Here’s what I learned:

1) SlickGrid is primarily designed around the “paging via scroll bar” mechanism. Actually, to be even more precise, it’s really “rendering via scroll bar”. SlickGrid primarily attempts to load all records into JavaScript, then defers rendering of those records until they’re scrolled into view.

2) SlickGrid does have a remote paging capability as seen in Example 6. However, almost all of its examples, and most of its add-ons, are geared around the concept that everything’s already loaded into Javascript variables. When using server-side paging, it does offload the filtering and sorting to the server.

3) Example 4, the Grouping Example, and the Optimized DataView Example show a paging navigator control (enabled via the small icon at bottom-right). However, examples do not exist for server-side paged data.

  • The current Slick.Controls.Pager widget (which produces the nav bar) was intended for use with the DataView class. The DataView class, in turn, was designed to work with fully-loaded data. Hence, the navigation bar cannot at this time be used with AJAX- loaded data. There are people who have gotten it to work with various hacks, but this is not yet part of this library.

4) SlickGrid does NOT use <table><tr><td> codes. Instead, it uses a series of div’s
5) SlickGrid is not as mature, well supported, or well documented as jqGrid or DataTables

============================================================

Evaluation

In order to properly evaluate jqGrid, DataTables, and SlickGrid against our “good enough” criteria, I set up a test REST server that returns “real” JSON data. The server contains a list of over 10,000 objects.

While the data is real, the response time is not. The test REST server pre-fetches all real data from back-end services, then cache’s that data internally in order to eliminate server response time in the evaluation. While real server calls are measured in 10ths of seconds, my test REST server’s average response time is 3ms for any given page of 50 objects.

I had to create unique REST end-points for each of my tables in this evaluation because each uses different parameters to control the list behavior. They all pull from the same list of cached objects.

I created a test html file — /SlickGrid/slickgrid.html — which creates a SlickGrid table and loads Users (50 at a time from a set of 10,000) from a SlickGrid-specific REST end-point.

1) Performance is #1

  • performance of fetching remote data is outstanding …just like the other table controls
  • 50 records: desktop, round-trip is 3ms, iPad3 it’s about .3s – .5s
  • 500 records:
  • SlickGrid implements Virtual Rendering preventing the drawing of a given row until it is scrolled into view
  • SlickGrid is capable of post-rendering work. For example, filling a given cell with a value from the server even after the row’s been scrolled into view. Here’s an example. Post-rendering takes place only when the UI is idle. Rows are processed 1-by-1.

2) Device requirements: performance and functionality will be determined by ICS-based tablets, not older Honeycomb devices, not smart phones

  • As noted above, performance on an iPad3 is outstanding

3) Table paging and navigation will be performed by next, prev, first, last, and #’s links

  • SlickGrid does not provide a navigation control for ajax-loaded data since it is primarily a page-via-scrollbar solution
  • Turns out the current Slick.Controls.Pager widget (which produces the nav bar) was intended for use with the DataView class. The DataView class, in turn, was designed to work with fully-loaded data. Hence, the navigation bar cannot at this time be used with AJAX-loaded data. There are people who have gotten it to work with various hacks, but this is not yet part of this library.

4) The table will load 1 “page” of data at a time, if the rows don’t “fit” the vertical table size, users may scroll to see the rest of the page

  • SlickGrid’s loads 1 “page” of data at a time. Previously loaded data is cached.
  • However, it does not provide a navigation control. Hence, the only pagination is via the scroll bar.
  • If the fetched rows don’t “fit” the vertical table size, users may scroll to see the rest of the page
  • The table can be sized such that it grows as needed to accommodate all rows

5) The table will not cache previous requests (to protect mobile devices; and if #1 is met, no need)

  • SlickGrid by default CACHE’s previous requests
  • Uncertain if this can be turned off

6) All paging, filtering, sorting will be performed by the back-end; none in the client

  • SlickGrid can be set up to paging, filtering, and sorting in both the UI and the back-end
  • However, SlickGrid’s DataView (required for using the navigation widget) is only available for fully-loaded data (not AJAX data)
  • When loading AJAX data, SlickGrid performs paging, filtering, and sorting by the back-end

7) We will filter on only string data originating from the server for now

  • Unexamined

8) Code size should not exceed 200K (minified and gzip’d); the smaller the better

  • Unexamined

9) We will only select a mature, well supported Table widget. We will not make our own.

  • Current version: 2.0.1, actively developed
  • This product does not appear to be as mature, as well supported, or as well documented as jqGrid or DataTables

10) Theming Support :

  • Unexamined

11) Table must by stylable as in our mockups

  • Unexamined
  • Every cell can be given a specific style name. Hence, I believe the table is stylable
  • SlickGrid is able to use John Resig’s micro-templates while still using SlickGrid’s virtual rendering technology

12) Single select for Marketplace; likely multi-select for future

  • SlickGrid supports single selection via row-selection or checkboxes
  • multi-select with checkboxes …but mostly unexamined

13) In-row actions for Marketplace; likely top-of list actions for future

  • SlickGrid supports any buttons we’d like to place in a row
  • SlickGrid is capable of post-rendering work. For example, filling a given cell with a value from the server even after the row’s been scrolled into view. Here’s an example. Post-rendering takes place only when the UI is idle. Rows are processed 1-by-1.

14) No in-cell editing for now

  • SlickGrid does support in-cell editing, however this can easily be turned off

15) No “View As…” alternate views for now

  • SlickGrid does not directly support alternate views for its tables

16) No conclusion on table width handling. However, the survey says most people would like to see columns shrink until it’s ridiculous, then hide low-priority columns altogether

  • Columns can be fixed or proportionally sized
  • Data within the cells shows ellipses if cell contents exceed cell size

17) The table needs to support a distribution-friendly license

  • SlickGrid is licensed under the MIT

jqGrid Evaluation

Test REST Server
In order to properly evaluate jqGrid, DataTables, and SlickGrid against our “good enough” criteria, I set up a test REST server that returns “real” JSON data. The server contains a list of over 10,000 objects.

While the data is real, the response time is not. The test REST server pre-fetches all real data from back-end services, then cache’s that data internally in order to eliminate server response time in the evaluation. While real server calls are measured in 10ths of seconds, my test REST server’s average response time is 3ms for any given page of 50 objects.

I had to create unique REST end-points for each of my tables in this evaluation because each uses different parameters to control the list behavior. They all pull from the same list of cached objects.

jqGrid Links

- Home: http://www.trirand.com/blog/
- Wiki: http://www.trirand.com/jqgridwiki/doku.php
- Examples: http://www.trirand.com/blog/jqgrid/jqgrid.html
- Addl Examples: http://www.trirand.net/demo.aspx
- Code: http://www.trirand.com/blog/jqgrid/downloads/jqgrid_demo38.zip
- Column Model: http://www.trirand.com/jqgridwiki/doku.php?id=wiki:colmodel_options
- Params: http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options
- Themes: NOTE: jqGrid uses jQuery UI – ThemeRoller to style its table. This could be a problem for us because JQuery UI and JQuery-Mobile don’t play well together. We’ll see…
- Commercial Web Site: http://www.trirand.net/

Evaluation

I created a test html file which creates a jqGrid table and loads 50 objects at a time from the REST end-point mentioned above. Remember, it’s a cache’d list.

1) Performance is #1

  • Like DataTables, performance is outstanding …actually, when fetching records, it’s identical because it’s the same back-end
  • 50 records: desktop, round-trip is 3ms, iPad3 is about .3s – .5s
  • 500 records: desktop, round-trip is 15ms, iPad3 is about 1s
  • Unlike SlikGrid and DataTables, jqGrid does not implement Virtual Rendering. As far as I can tell, it renders the full result set as soon as it’s received. Don’t know how much of a performance hit this is, but it could be a big deal depending on what you put in your cells.
  • However, with jqGrid’s gridview parameter, it is able to “append” all the rows with a single call …making it a very fast operation. Note that this choice comes with some limitations: for example, no afterInsertRow event, etc.
  • I do not like how jqGrid handles the scroll bar on an iPad3. While it appropriately hides the scroll bar, the table does NOT take over the available space. Further, when scrolling, it does not use the iPad3′s “thin” scroll bar. Finally, when fast swiping, it stops scrolling immediately after you’ve quit touching …to smooth scroll stop like you’d expect.

2) Device requirements: performance and functionality will be determined by low-powered, ICS-based tablets, not older Honeycomb devices, nor smart phones

  • As noted above, performance on an iPad3 is outstanding
  • Performance on a Honeycomb smart phone (Galaxy S2 on T-Mobile) is acceptable (but not part of our required criteria)

3) Table paging and navigation will be performed by next, prev, first, last, and #’s links

4) The table will load 1 “page” of data at a time, if the rows don’t “fit” the vertical table size, users may scroll to see the rest of the page

  • jqGrid will load 1 “page” of data at a time
  • If the fetched rows don’t “fit” the vertical table size, users may scroll to see the rest of the page. Note my “scrolling” comments in the Performance section above.
  • The table can be sized such that it grows as needed to accommodate all rows

5) The table will not cache previous requests (to protect mobile devices; and if #1 is met, no need)

  • jqGrid by default does not cache previous requests
  • I am uncertain if jqGrid can be set up to pre-fetch addl pages or not ??????

6) All paging, filtering, sorting will be performed by the back-end; none in the client

  • jqGrid supports paging, filtering, and sorting in both the UI and the back-end

7) We will filter on only string data originating from the server for now

  • According to its doc, developers can specify sorting for various types including string, number, boolean, link, select and percent. However, I believe this is for client-side processing only, and is not part of ajax-based solutions.

8) Code size should not exceed 200K (minified and gzip’d); the smaller the better

  • File size: File size: CSS: 12K; JS 430K raw / 270K minified / 68K gzip’d;
  • 3 times larger than DataTables

9) We will only select a mature, well supported Table widget. We will not make our own.

  • jqGrid is currently in version 4.4.0 (released in June 2012)
  • and has been developed now for at least 3 years, since 2009 …but I actually suspect much longer since that was version 3.5.x
  • has over 8,500 threads (27,000 posts) in its on-line forums
  • Unknown number of unit tests …I’m uncertain how rock-solid this product is. Probably pretty good.
  • It does not provide very many pre-built examples …but the ones that are there suffice

10) Theming Support :

  • DataTables supports ONLY JQuery UI ThemeRoller classes
  • However, with the rich set of overridable events, I believe we could add/remove any styles we want …just like DataTables

11) Table must by stylable to may our particular look and feel

  • jqGrid does not specifically provide APIs to apply the styles we want throughout the table. However, with the rich set of overridable events, I believe it can be styled to match our needs …just like DataTables.
  • jqGrid provides a very rich Column Renderer which is passed the backing row Object and the property value …giving the renderer the opportunity to display addl fields in each cell
  • jqGrid does not really permit row expansion showing more details about a row Object. Any examples I’ve seen add additional rows …kinda klunky.

12) Row selection (single select for now; multi-select for future)

  • jqGrid supports single selection via row-selection or checkboxes
  • I do not believe jqGrid supports multi-select across page boundries like DataTables does. Not sure I care though either

13) Links / Actions – in-row actions for now; likely top-of list actions for future

  • With its column renderers, jqGrid supports placing any data into a cell, including buttons/actions
  • jqGrid will use any specified Object value (for example: id) as the row’s ID attribute
  • jqGrid supports a very rich set of custom events which code can bind to

14) Editing: no in-cell editing for now

  • jqGrid supports in-cell / in-row editing
  • 2 method exist: see “Row Editing -> In-Line Navigator” and “Live Data Manipulation -> Navigator” examples

15) Alternate Views: no “View As…” alternate views for now

  • jqGrid does not directly support alternate views for its tables

16) No conclusion on table width handling. However, most people would like to see columns shrink until it’s ridiculous, then hide low-priority columns altogether

  • A jqGrid table normally sizes to the combined widths of its visible columns
  • However, you can also set the grid width, and the columns will adjust accordingly
  • I have not seen any example where the table’s width sizes dynamically. Seems to always be based on the grid’s “set Width”
  • Data within a jqGrid cell by default does NOT wraps unto addl lines (However, I’m sure we could easily change this with the CSS whitespace property). By default, when a cell’s data exceeds the cell bounds, ellipses show…
  • Uncertain if jqGrid could auto-show/hide low priority columns based on table width

17) The table needs to support a distribution-friendly license

  • jqGrid is licensed under the free MIT license
  • However, they have also launched an official commercial website http://www.trirand.net

Special Notes

  • jqGrid supports a truly awesome Column Model
  • I’m not too impressed with its “row” editor …adequate, but not beautiful. Of course, we can style any way we want.
  • I don’t know why jqGrid’s “row expansion” feature simply adds more rows. In my testing, I learned that I can place any amount of data into each cell, independent of the other cells. In other words, rows can have variable row height, and I could auto-expand the current row if I wanted to. I think they should specifically make an “expand” feature for rows to show addl detail.
  • jqGrid supports a grid within a grid!
  • jqGrid support a “tree” control by adding additional rows with indented values. Kinda cool!. Check out the “simple” example at: http://www.trirand.net/demotreephp.aspx
  • jqGrid has launched an official commercial website http://www.trirand.net. Check it out; there are some impressive demos there. You’ll note that they’ve spent considerable time trying to make a list and tree out of the same control. IOW, if you need a tree control, this is one is pretty good.

Notable Params

- 100 params
- 20 Events
- over 50 Triggered Events !!

ajaxGridOptions  - override all AJAX parameters including: error, complete, and beforesend events
altclass         - specify the class you want for the "alternate/zebra" rows.  Hmmm ...do they have this for all styles?
autowidth        - table auto-sizes (width) according to the size of its parent div
cellEdit         - enable editing
cellsubmit       - when editing, determine where the edits are saved (remote or clientArray/local)
colModel         - array which describes the parameters of the columns
deepempty        - uses JQuery to empty a row; prevents memory leaks
direction        - good support for Right-to-Left and Left-to-Right languages
forceFit         - all columns will always consume 100% of the table width (adjacent columns adjust as needed)
hoverrows        - enable row hover effects
idPrefix         - add a prefix to a row's ID
loadui           - control what to do while loading: disabale, enable, block
mtype            - HTTP GET or POST
pager            - enable paging controls.  NOTE: this also controls into what HTML div to place the pager
pgtext           - show details about the current list
prmNames         - controls the names of all the parameters sent to the server
scroll           - tells jqGrid to disable paging controls and to enable paging-via-scrollbar
shrinkToFit      - recalculate column widths as the table shrinks
sortable         - uses JQuery UI to permit reordering of the columns.  Since we're trying to be JQuery Mobile compliant, we do not want this.
toolbar          - defines the tools available in the toolbar
treeGrid         - enable the "tree" aspects of the grid control
url              - the source of the ajax data
userData         - addl data to make part of the request
afterInsertRow   - method gets called after a row is created
beforeRequest    - before a request is made
beforeProcessing - after a response is received (but before doing anything with it)
gridComplete     - after all received data is fully processed
onPaging         - after selecting a paging options, but before processing the data
resizeStop       - fires after resizing event has taken place (resizeStart also)
tons and tons of other options and events

DataTables Evaluation

Test REST Server
In order to properly evaluate DataTables against our “good enough” criteria, I set up a test REST server that returned “real” JSON data. The server contains a list of over 10,000 objects.

While the data is real, the response time is not. The test REST server pre-fetches all real data from back-end services, then cache’s that data internally in order to eliminate server response time in the evaluation. While real server calls are measured in 10ths of seconds, my test REST server’s average response time is 3ms for any given page of 50 objects.

DataTables
- Home: http://datatables.net/
- Examples: http://www.datatables.net/examples/
- Tests: https://github.com/DataTables/DataTables/tree/master/media/unit_testing
- Params: http://datatables.net/ref (125 params supported)
- Themes: http://datatables.net/styling/themes/ui-darkness

I created a test html file which creates a DataTables table and loads 50 objects at a time from the REST end-point mentioned above. Remember, it’s a cache’d list.

1) Performance is #1

  • performance is outstanding
  • 50 records: desktop, round-trip is 3ms, iPad3 is about .3s – .5s
  • 500 records: desktop, round-trip is 15ms, iPad3 is about 1s
  • Like SlikGrid, DataTables implements Virtual Rendering with its bDeferRender parameter Rendered rows/cells are retained for 1-page scrolling
  • I like how it handles the scroll bar on an iPad3. With no addl coding, it auto hides the bar, and lets the table take over the available space. Further, when scrolling, I like how it uses the iPad3′s “thin” scroll bar. Finally, it uses the device’s fast swipe gesture to continue to scroll the list even after you’ve quit touching; obviously it stops after a second or two …just as you’d expect.

2) Device requirements: performance and functionality will be determined by low-powered, ICS-based tablets, not older Honeycomb devices, nor smart phones

  • As noted above, performance on an iPad3 is outstanding
  • Performance on a Honeycomb smart phone (Galaxy S2 on T-Mobile) is acceptable (but not part of our required criteria)

3) Table paging and navigation will be performed by next, prev, first, last, and #’s links

  • DataTables supports both paging-via-navigation-controls, and paging-via-scrollbar

4) The table will load 1 “page” of data at a time, if the rows don’t “fit” the vertical table size, users may scroll to see the rest of the page

  • DataTables will load 1 “page” of data at a time
  • If the fetched rows don’t “fit” the vertical table size, users may scroll to see the rest of the page
  • The table can be sized such that it grows as needed to accommodate all rows

5) The table will not cache previous requests (to protect mobile devices; and if #1 is met, no need)

  • DataTables by default does not cache previous requests
  • DataTables can be set up to pre-fetch addl pages as needed

6) All paging, filtering, sorting will be performed by the back-end; none in the client

  • DataTables supports paging, filtering, and sorting in both the UI and the back-end

7) We will filter on only string data originating from the server for now

  • DataTables has made some effort to support sorting and filtering on representations of the data other than what’s displayed (Enums vs their string implementation; dates; etc.) However, I believe this is for client-side processing only, and is not part of ajax-based solutions.

8) Code size should not exceed 200K (minified and gzip’d); the smaller the better

  • File size: 68K minified / 20K gzip’d. This is outstanding !!
  • With addl plugins (FixedColumns, Scroller, etc.), + 20K minified / 6K gzip’d

9) We will only select a mature, well supported Table widget. We will not make our own.

  • DataTables is currently in version 1.9.2
  • and has been developed now for 4 years, since 2008
  • has over 10,000 threads in its on-line forums
  • backed by a suite of 2800 unit tests
  • provides over 130 pre-built examples

10) Theming Support :

  • DataTables supports JQuery ThemeRoller classes
  • DataTables allows users to specify what class names to associate with HTML elements
  • DataTables can render its add-on widgets (nav bar, search field, etc.) in HTML-provided div’s

11) Table must by stylable to may our particular look and feel

  • With DataTables liberal handling of class names (user-definable globals hold class names), I believe it can be styled to match our needs
  • DataTables provides a Column Renderer which is passed the backing row Object and the property value …giving the renderer the opportunity to display addl fields in each cell
  • DataTables permits row expansion showing more details about a row Object

12) Row selection (single select for now; multi-select for future)

  • DataTables supports single selection via row-selection or checkboxes
  • DataTables supports multi-select across page boundries (sending selections to server)

13) Links / Actions – in-row actions for now; likely top-of list actions for future

  • DataTables supports any buttons you need to place in a row
  • If requested, DataTables will add unique IDs to each row in a paged table
  • DataTables also supports custom events which code can bind to

14) Editing: no in-cell editing for now

  • With its Editor plugin, DataTables does support in-cell editing if desired

15) Alternate Views: no “View As…” alternate views for now

  • DataTables does not directly support alternate views for its tables

16) No conclusion on table width handling. However, most people would like to see columns shrink until it’s ridiculous, then hide low-priority columns altogether

  • DataTables supports a dynamic width for its tables
  • Columns resize when the table resizes
  • Data within the cells re-wraps unto addl lines as needed (IOW, row height is not fixed when paginating via the navigation bar)
  • Uncertain if DataTables could auto-show/hide low priority columns based on table width

17) The table needs to support a distribution-friendly license

  • DataTables is dual licensed under the GPL v2 license or a BSD (3-point) license
  • I’m no lawyer, but I suspect the BSD license is sufficient

Notable Params — 125 params exist!!

sServerMethod    - HTTP method to use GET | POST
bAutoWidth       - enable auto col width calculation; disable if col widths are in aoColumns
bProcessing      - show a "processing request" message
bPaginate        - enable pagination
sPaginationType  - style of pagination buttons/links; two_buttons
bLengthChange    - show the page size combo; requires bPaginate
aLengthMenu      - [[values], [display]]: [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]]
iDisplayLength   - size of a page
bFilter          - show the search box; to remove box but keep filter ability, use sDom
bRegEx           - interpret search string as a regEx expression
bSmart           - use DataTable's smart filtering methods to match words at any point in the data
bJQueryUI        - enable JQuery UI ThemeRoller support; affects visibility of prev/next links
bInfo            - Show status bar details about the current table data; 1 to 10 of 100 (# filtered)
bScrollInfinite  - Pagination by using only the scroll bar
iScrollLoadGap   - Amount of scrolling left to go before pre-fetching the next page
bScrollCollapse  - Controls if the table's viewport should be shrunk on the last page
sScrollX         - Specify horizontal scrolling; blank = disabled
sScrollY         - Specify vertical scrolling
bSort            - Enable sorting; individual cols can be disabled /w bSortable option on each col "bSortClasses"
bStateSave       - Enable state saving; uses cookies
bDeferRender     - Only draw those rows that are visible; draw addl as needed
bServerSide      - filter, sort, page on server; must be used with sAjaxSource
sAjaxSource      - URL: /rest/service/endpoint
aoColumns        - Define column model
fnServerParams   - Define any addl data to send with page request
sDom             - Tell DataTables in what div's to render it search, msgs, & nav bar widgets
fnRender         - Rendering function used to draw cell contents

What’s Good Enough?

Based on survey results and subsequent discussions, here’s what we decided for a table widget:

  1. Performance is #1
  2. Device requirements: performance and functionality will be determined by low-powered, ICS-based tablets, not older Honeycomb devices, not smart phones
  3. Table paging and navigation will be performed by next, prev, first, last, and #’s links
  4. The table will load 1 “page” of data at a time, if the rows don’t “fit” the vertical table size, users may scroll to see the rest of the page
  5. The table will not cache previous requests (to protect mobile devices; and if #1 is met, no need)
  6. All paging, filtering, sorting will be performed by the back-end; none in the client
  7. We will filter on only string data originating from the server for now. Filters on dates, UI-localized strings, enums, etc. will not function in the first release
  8. Code size should not exceed 200K (minified and gzip’d); the smaller the better
  9. We will only select a mature, well supported Table widget. We will not make our own.
  10. We would prefer a Theming model based on
      - ThemeRoller for JQuery-Mobile
      - if not ThemeRoller for JQuery
      - if not code-specified style names
      - anything goes

  11. Table must by stylable as in our mockups
  12. Single select for now; likely multi-select for future
  13. In-row links / actions for now; likely top-of list actions for future
  14. No in-cell editing for now
  15. No “View As…” alternate views for now
  16. No conclusion on table width handling. However, most people would like to see columns shrink until it’s ridiculous, then hide low-priority columns altogether
  17. The table needs to support a distribution-friendly license

Next Steps – evaluate table controls along these criteria
- Those table controls that are still in the running after this analysis will be wired up against live / real data
- However, the data will be cached in the server in order to eliminate the server portion of the performance analysis (we want to see how well the grids perform …not how long the server takes to fulfill a request)
- We have narrowed the list to DataTables, jqGrid, and SlickGrid …and a quick peek at JQuery

- DataTables

- SlickGrid

- jqGrid

- JQuery UI Grid – not really a candidate since it appears this component is currently on hold