State of the jQuery UI Grid
We announced the Grid project back in February. Since then, we finished the first three stages and are now getting started on the fourth. In this post we’ll take a look at what we’ve built so far.
Grid
This is what we designed as the “zero feature grid”. All it does is enhance HTML tables, but it does that pretty well while also providing the right hooks for all kinds of other features that we can add on top of that. And that turns out to be really useful, as there are a bunch of things that regular HTML tables can’t do. With Grid, you get:
- styling with the CSS framework, making it ThemeRoller-ready
- a proper titlebar, based on the table’s caption
- markup and styles necessary for scrolling of the table body, while keeping the header fixed
The API for the Grid controls what content to render, and how to present it:
- The columns option specifies which columns to render. If not specified, it picks up existing table header elements.
- The rowTemplate option allows the grid to render each row from a custom template. If this option is not provided, each row is generated based on the columns option.
- The source option specifies the content to render, in the form of a plain array of objects. When not specified, existing table rows are used.
- By default, the grid’s body grows with the number of rows. With heightStyle: ‘fill’, it stays at a fixed height and the body starts scrolling if there are more rows.
- When picking up column information from the existing table headers, certain data-attributes are read. The grid itself uses only the data-property attribute (and the actual text of each header cell), but the dataFields option specifies a few more attributes that other components can use, such as “type”, “culture” and “format” to configure local sorting and filtering. If a grid add-on handles other data attributes, adding those to the dataFields option will make them automatically available as part of the columns option.
So far we only have an enhanced table, but often enough, a grid needs to be fed data from some remote resource. That’s where Dataview comes in.
Dataview
Dataview is a low-level abstraction for retrieving content. It has an API for specifying what content to retrieve, and an SPI (service provider interface), implemented by components that provide that content. There are built-in options for filtering, sorting and paging, and the design makes it easy to add more options, like grouping. The API is asynchronous by default, even for local data, so that all components relying on Dataview can work with both local and remote data.
Dataview only depends on Widget and Observable (we’ll get to that below), but not on Grid. This allows Dataview to be used in a variety of contexts. For example it could power a product listing, such as those on eBay or Amazon, where a table presentation is not the right format.
The Dataview SPI makes it easy to write implementations from scratch as well as to create reusable extensions.
As an example, we can use a custom dataview as the input for the Autocomplete widget. The same data is also displayed in the grid below the input field. This demonstrates how a Dataview can be used in multiple representations, where each decides on its own what data to show.
As for reusable extensions, we currently have three implemented:
- localDataview takes an input array and does sorting, paging and filtering on that array. It uses Globalize (see below) to implement filtering and sorting of localized numbers and dates. When combined with the grid on a table with existing content (without specifying the source option), you get a complete tablesorter.
- odataDataview takes a resource URL, pointing at a webservice that understands OData, the Open Data Protocol. While our implementation doesn’t yet cover all of the OData options, you can use it to sort, filter and page, without having to implement any custom request/response mapping. We have an example of a grid using the OData based Netflix API.
- preloaderDataview wraps a Dataview and adjusts the paging behaviour to load more data than rendered, paging locally before preloading another batch. In this Flickr API slideshow example we preload both the API responses and the actual images. This pushes all the loading in the background, allowing the user to page through images without interruptions.
All three need testing in actual projects before we can consider them stable. We’re also looking for other use cases for dataview that we might be missing.
Observable
Data binding is currently a common theme among newer JavaScript frameworks, with various competing solutions available. We don’t yet have a full-featured alternative, but we’ve developed a low-level abstraction that might power a data binding component in the future. We call this abstraction Observable. It provides an API for making changes on plain JavaScript objects and arrays that can be observed by listening to events that each change triggers. We’ve designed Observable to have a very small number of methods and events, with the purpose of making it easy to implement the same API in other contexts. These events are:
- change: Triggered on objects after one or more properties have changed.
- insert: Triggered on arrays after inserting one or more new items.
- remove: Triggered on arrays after removing one or more items.
- replaceAll: Triggered on arrays after replacing all items in an array.
That last event may seem odd at first, but this makes it possible to create a dataview, pass it to a grid, have the grid subscribe to events on that dataview’s output array, and then update itself when the dataview updates.
For all four events, Observable provides method counterparts:
- property: to work on objects
- insert, remove and replaceAll: to work on arrays.
Usage is consistent in both cases:
- $.observable( object ).property( “name”, “Fred” );
- $.observable( array ).insert({ name: “Peter” });
We’re still working on Observable. The next step is to find an abstraction for the array bindings, which would remove some overhead both from the Grid as well as from the todo-app demo.
When combining Observable with the Grid, we can easily add editing capabilities. In our grid editing demo, you can add, edit and remove developers from the table. Results are persisted via localStorage.
Instead of adding custom columns that have “Edit” and “Remove” buttons, we can use the selectable interaction to select one or more rows and then interact with the selection. In that demo, the selected
array is also an observable array, which the second grid displays. Note that you can select rows on one page, go to the next page (you may need to add a few developers for a second page to show up), select more rows with command/ctrl-click (to extend the selection) and it will display all those rows in the second grid. The selected state is separated from the visual representation, making selection over multiple pages pretty easy.
Globalize
Globalize originally started as the jquery-global plugin. We rewrote it as part of the Grid project to be independent of jQuery, allowing usage on both client and server. Our localDataview implementation (mentioned above) uses it, and its also behind custom inputs like Spinner and Timepicker.
Mask, Timepicker, Selectmenu
These three custom inputs are being developed as part of the Grid project. They are intended to be used within the Grid for inline editing, as well as standalone in regular forms or websites. We’re getting close to landing all three in master, to release them as part of 1.9.
And more…
Work is still in progress on Template, Datepicker and other Custom Inputs. We’ll report back on those once we have more stable solutions.
Up next
We’re finishing existing components and are starting on Stage 4. For details, check out the main Grid wiki page.
So, when is it done?
Our Roadmap has the Grid on the 2.1 release, while the main focus for jQuery UI is on 1.9. In other words, there is a lot that needs to get done before we can put the Grid into a stable release and support it along with all the other components. At the same time, we encourage you to start testing the features outlined above now. Grid, Observable and Dataview are all pretty stable and working well. Globalize is a separate project that you should start using now if you want to support localized number and date handling on the clientside.
We value your input and help. Please use the Developing jQuery UI forum, comment on individual wiki pages or visit us on IRC (#jqueryui-dev on Freenode). If you found a solution to an issue, send a pull request.
I have a question about the Observable plugin. Is this an alternative to backbone.js?
THanks.
What about treegrid functionality? Is it planned?
@ivan: There is overlap with Backbone’s Model and Collection objects, but that’s about it. Considering the overall limited scope of Backbone, you should be able to implement very similar applications using Observable and Dataview. If you need the router, use history.js.
@Finn: Eventually, yes, but not on our roadmap right now.
@Jorn, do you recommend using Backbone.js and Jquery?
And why do you develop a grid functionality when there’s datatables?
It’s not only the best plugin i’ve ever seen but also has all functionality i could imagine for a table, so why do the work twice? oO
Btw it even has jQuery UI compatibility, theming and stuff!
don’t understand why this could be necessary…
I kind of agree with @Conic – I’m not sure what this does that Datatables doesn’t.
@Conic and mattreyuk – It will get tested along the with the rest of the API for future releases and reflect the internal consistency of the rest of the jQuery UI. I’m already planning on converting all my old 3rd party plug-in driven crap to this because I know that the bugs will shake out at a reasonable pace and the integration will seriously lower my code maintenance overhead. Ever have to do a major refactor because of requiring a 3rd party plug-in? This may not be necessary for everyone, but it is sure nice for me.
Nice work, but why do you develop such a complex compontent, when there are easier and from most of the users needed things like the tooltip waiting for more than 1 year?
Is there a release date for 1.9 yet? I’m really looking forward to getting to use menu, menubar and tooltip.
I’m pleased the grid and tree components are underway but to be honest for now jqgrid and jstree are working for me.
If you’re questioning why we’re developing this project, please read the announcement post: http://blog.jqueryui.com/2011/02/unleash-the-grid/
@ninsky – We take particular care to ensure the work being done on the Grid happens in parallel to (and without slowing) other new widget development, such as 1.9, menu, tooltip, spinner, etc. So tooltip will come out in a final stable release just as soon as it would otherwise, if not sooner. Same thing with menu and spinner and mask and timepicker, etc. If anything, many of these (and others) are getting more attention and focus, not less, as a result of the jQuery UI Grid project and some of the dedicated resources that make it possible.
@John Reilly – We don’t set dates for releases, we work on them until they are done and we release them when they are done. You can see what’s left on getting 1.9 final out by checking the Roadmap: http://wiki.jqueryui.com/Roadmap . That time would be measured in months, not weeks nor years.
Nice work … I’d be using it now for a personal project, if it were ready. I’m certainly happy to test pre-release stuff if it’d prove useful …
謝謝~
正在更新中~
With Observable, why not use prop() instead of property() for brevity and consistency with jQuery core?
@shawn: A better place for that discussion is the wiki: http://wiki.jqueryui.com/w/page/47179578/Observable
The grid demos appear to be broken. Does anyone have a working link?
@Josh: There was a change to our view.jqueryui.com server, moving all branches to /branches. I’ve updated the demo links here, they should all be working again.
Will cell selection be supported?
I have been working rather intensely with jqGrid, which is a very powerful implementation of a grid using jQuery UI, similar in many ways to Datatables. How does this previous work fit in here? if it is meant to fit at all… For what it looks like, this grid is very broad minded, while jqGrid and Datatables have a very intense and portentous set of features covering a smaller range of uses. Of course, this is just the beginning. I find very interesting the approach towards OData, and how the ease of access to data will be able to interconnect resources. It’s one of those things both beautiful and scary of the new sematic web!
@Chris: On the grid-editing demo you can see cell selection in action. Its currently very much experimental.
@Hermes: Building small and simple components is a major goal of this project. That takes more time then building just a full-featured grid, but provides a lot more value in the long run.