As part of a SaaS Enablement project we are currently working on for a customer using Oracle JET, a requirement came up to present an hierarchical data set – in a way that quickly provides an overview as well as allows access to detail information and the ability to focus on specific areas of the hierarchy. The data describes planning and availability of employees and the hierarchy is by time: months, weeks and days. One presentation that would fit the requirements bill was a spreadsheet like data grid with employees in the rows, the time hierarchy in [nested]columns and the hours planned and available in the cells. A popup that appears when the mouse hovers over a cell will present detail information for the planned activities for that day and employee. Something like this:
This article will not describe in detail how I implemented this functionality using Oracle JET – although I did and all the source code is available in GitHub: https://github.com/lucasjellema/jet-nestedheader-datagrid-planandresource .
When I first looked at the requirements, it was not immediately clear to me that JET would be able to easily take on this challenge. I certainly did not rush out to give estimates to our customer – depending on the the shoulders we could stand on, this could be a job for weeks or more. However, browsing through the Oracle JET Cookbook, it did not take too long to identify the data grid (the smarter sibling of the table component) as the obvious starting point. And to our good fortune, the Cookbook as a recipe for Data Grid with Nested Headers: http://www.oracle.com/webfolder/technetwork/jet/jetCookbook.html?component=dataGrid&demo=nestedHeaderDataSource:
With this recipe – that includes source code – as starting point, it turned out to be quite straightforward to plug in our own data, rewrite the code from the recipe to handle our specific data structure and add custom cell styling. When that was done – rather easily – it was very seductive to start adding some features, both to take on the challenge and to further woo (or wow – but not woe as I had mistyped originally) our customer.
Because the data set presented in the grid is potentially quite large, it is convenient to have ways to narrow down what is shown. An intuitive way with hierarchical data is to collapse branches of the data set that are currently not relevant. So we added collapse icons to month column headers; when a month is collapse, the icon is changed to an expand icon. Clicking the icon has the expected effect of collapsing all weeks and days under the month or expanding them. From here it is a small step to allow all months to be collapsed or expanded by single user actions – so we added icons and supporting logic to make that happen.
Also intuitive is the ability to drill down or zoom into a specific column – either a month or a week. We added that feature too – by allowing the month name or week number in the column header to be clicked upon. When that happens, all data outside the selected month and week are hidden.
Finally, and very rough at present, we added a search field. The user can currently enter a number; this is interpreted as the number of the month to filter on. However, it would not be hard to interpret the search value more intelligently – also filtering on cell content for example.
Did we not have any challenges? Well, not major stumbling blocks. Some of the topics that took a little longer to deal with:
- understand the NestedHeaderDataGridDataSource code and find out where and how to customize for our own needs
- create a custom module and use require to make it available in our ViewModel (see http://requirejs.org/docs/api.html#jsfiles)
- use of Cell template and knock out tag for conditional custom cell rendering
- capture the mouseover event in the cell template and pass the event and the cell (data) context to a custom function
- generate a unique id for span element in cell in order to have an identifiable DOM element to attach the popup to
- programmatically notify all subscribers to KnockOut observables that the observable has been updated (and the data grid component should refresh) (use function valueHasMutated() on observable)
- programmatically manipulate the contents of the popup
- take the input from the search field and use it (instantly) to filter and refresh the data grid
- include images in a ReadMe.md in GitHub (yes, that is a very different topic from Oracle JET)
- create an animated gif (and that too) – see the result below, using http://gifmaker.me/
I hope to describe these in subsequent blog posts.
This animated gif gives an impression of what the prototype I put together does. In short:
– present all data in an hierarchical grid
– show a popup with cell details when hovering over a cell
– collapse (and expand) months (by clicking the icon)
– drill down on (zoom into) a single month or week (by clicking the column header)
– collapse or expand all months and weeks
– filter the data in the grid by entering a value in the search field
And here is the JSFiddle where you can inspect the code and see the data grid in action:
In the end, the customer decided to have us use the Gantt Chart to present the hierarchical data. Mainly because of its greater visual appeal (the data grid looks too much like Excel) and the more fluid ability to zoom in and out. I am sure our explorations of the data grid will come in handy some other time. And if not, they have been interesting and fun.
Source code for the article (and the nested header data grid component): https://github.com/lucasjellema/jet-nestedheader-datagrid-planandresource
Oracle JET Cookbook:
– Nested Headers with Data Grid – http://www.oracle.com/webfolder/technetwork/jet/jetCookbook.html?component=dataGrid&demo=nestedHeaderDataSource
– CRUD with Data Grid – http://www.oracle.com/webfolder/technetwork/jet/jetCookbook.html?component=crud&demo=CRUDGrid
Documentation for KnockOut – http://knockoutjs.com/documentation/introduction.html
Documentation for RequireJS – http://requirejs.org/docs/api.html#jsfiles
The foundation of JS Fiddles for JET 3.2 – https://jsfiddle.net/peppertech/a593LL2r/
Blog Article on AMIS Blog – Oracle JET – Filtering Rows in Table with Multiselect and Search Field Filters