TODO: bung this all in a git repo etal... meanwhile click here for the craft...
have all the fun with it ;)
Filter Min | ||
Filter Max |
The Slickgrid API provides all that we need in order to create dynamically sizing row-heights and all without any need to hack on the Slickgrid codebase. Because:
onRenderIDCell
and using this to overlay the padding with a detail panel.
onRowClick
event handler with the codes for adding and removing the padding rows highlighted:slick-row
.. here's all the codes with the relevant sections highlighted:DataView.getItemMetadata
default implementation (which is to do nothing) must be overridden.
_dataView.getItemMetadata=onRenderRow; //override the dataview callback with our own
onRenderRow
callback that i am providing another callback: onRenderDetailCell
.
This is like the onRenderIDCell
column formatter but works per cell & can be provided in the run-time.
We at least need to use this callback in order to dynamically set the new height of the detail cell.
But i am also wrapping the detail in a custom container to provide a further styling opportunity for our cell content.
dynamic-cell
class that sets the overflow
to visible
in order to style away the per cell overflow clipping.
I'm doing this stuff in here instead of say, the onRowClick
handler because Slickgrid maps
the css to a fixed row number. Which is a bit strange.
It means that if rows are added or removed the style slips away from the row it was originally applied to.
We only want the css applied to expanded parent rows; if the row is padding or a collapsed parent, it needs to be removed.
Therefore on lines 127 & 156 we invoke the
Grid.removeCellCssStyles
API to get rid of the unwanted dynamic-cell
class, if it happens to exist for that row.
NB: beware! attempting calls to addCellCssStyles
, removeCellCssStyles
(or
getCellNode)
when a row does not exist (ie: it's disappeared out of the viewport) can cause Slickgrid to bork :(
zero
underhanded hax ;)var getIdxDetailCol=function() {return _grid.getColumnIndex(_attribs.exampleDetailField);}
kookupDynamicContent
content generating function.
And that's about all there is to sorting.
All that remains to do is subscribe to the Slickgrid Grid.onSort event and provide a handler:////////////////////////////////////////////////////////////// //delegate the sorting to DataView; which will sort the data using our //comparer callback; fire appropriate change events and update the grid ////////////////////////////////////////////////////////////// var sort=function() { _dataView.sort(comparer.compare, comparer.getSortAsc()); } ////////////////////////////////////////////////////////////// //fired when the user clicks on a column header ////////////////////////////////////////////////////////////// var onRowSort=function(e,args) {comparer.setInfos(args.sortCol, args.sortAsc); sort();}
I also provide a wrapper for the call into the
DataView.sort.
In addition to being called from our onRowSort
handler, this can also be invoked
anytime we feel like it; on initialisation, on a data update; whenever.
Filter Min | ||
Filter Max |
onFilter
callback we provide to the
DataView.setFilter API:
var onFilter=function(item) { return pcFilter.onFilter(item); }
acu
Now. As can be seen in the last three examples, i'm cooking up some funky on-the-fly svg. which is xml & not very jQuery friendly. & it's a bit of an overhead to get the html string for the Slickgrid cell render.
And it's slightly vexing to keep adding & removing the dynamic-cell
css class all over the place.
All of which, i'm going to use as justification for something that not only makes life easier; but also provides an option for some optimisation..
Slick.Grid.
API does provide an
asyncPostRender
column option
where we can supply an event handler. But the event fires on a setTimeout
(; perhaps
@Tin
was trying to cut-down on the
event-hell
With a caniuseit rating of 83% (figure will rot for the better) we can instead use a MutationObserver to generate custom post-render events:
Filter Min | ||
Filter Max |
MutationObserver
:
slick-row
css class get added:
internationalObserver(_grid.getCanvasNode(), _attribs.slickRow, onAddRow);
onRenderDetailCell
formatter callback, instead of supplying the detail as a raw html string like before;
we now add a container element with an id
that identifies the item/row and the column and we give it a css class
name of dynamic-cell-detail-ctr
which we will use merely as a selector.
onAddRow
event handler that gets fired by the MutationObserver
. This in turn fires
our onPostRender
handler for any cells in the row that have been marked
with the dynamic-cell-detail-ctr
class:
var onAddRow=function(row){$(_attribs.classSelector("cellDetailCtr"), row).each(onPostRender)}
dynamic-cell
css class in order to escape the overflow-clipping
on the slick-cell
container:
Something that also seems to work as an alternative means of generating onPostRender
events
is a bit of a hack involving inserting dummy <style>
elements with an onload
attribute.
onRenderDetailCell
callback:
onPostRender
function is almost the same as before only now the
item.id
is provided directly as the first function argument:
This approach may have more cross-browser compatibility than MuationObservers
& seems
to work ok in the latest versions of Firefox, Safari and Chrome.
But on Chrome there is a touch more latency. And in an older version of Chrome i
tried (Version 20.0.1150.1/Linux) it seemed to be generating garbage
that the gc was unable to retrieve.?. i'm not sure why. there are no circularities afaik.. :/
Right-ho, so now we have millions of rows of data + a shed-load of padding. filtering is O(n) so that's not too bad.
but the standard sort
implementation in the DataView is a bubble-sort; the worst-case complexity of
an unsorted list is O(n2)..
It would be nice *not to have to wade thro all the out-of-scope padding.
Well obviously, having expandable/collapsible rows helps to mitigate the issue. But suppose we don't want that feature? -in that case, we can implement our own caching system. The following example is based on the previous example but reaps out-of-scope padding beyond a certain threshold. And of course it revives the padding as the expanded detail rows come back into scope.
I have chucked in a logger to highlight the process. (; And for this reason the example still features expando-rows; so there's not a total flood of messages ;)
Filter Min | ||
Filter Max |
MutationObserver
so that it additionally fires removed-row events:
onDetailRemoved
event-handler, we add the row-item to an internal list.
All padding rows within this list are going to remain cached:
onSysIdle
events whenever the application is not up to much.
In this example, the revivePadding
function gets invoked from
within the onPostRender
event handler, once the row moves back onto the
Slickgrid canvas.
reapPadding
function gets invoked by the onSysIdle
event handler
[NB: this could be improved by only kicking-off idle-events in response to say the grid being scrolled].
The big (&hopefully) noticeable differences are that i have done away with the expandable rows feature and i have made it so that there are two fields that contain dynamic cell detail content.
So this example really is a kind of place-holder for what needs to be done next in order to make a generic Dataview-like Slickgrid extension-mod.kookupDynamicContent
function
with a couple of new functions: setCallsContent
and setStatusContent
,
which are specific to each dynamic field. These should be part of the application and *not inside
any extension-mod.
See also lines 557-615, where i have provided an API to add/update/remove data items.
So likely, it is in here that an extension-mod should instead invoke callback-handlers provided by the application
for the above custom setters
.