Can SlickGrid's row height be dynamically altered?

后端 未结 3 1518
攒了一身酷
攒了一身酷 2020-12-10 05:02

We are implementing a user preference to (instantly) show \"more\" or \"less\" data on the grid. \"More\" should increase the row-height (with every row having the same incr

相关标签:
3条回答
  • 2020-12-10 05:28

    Indeed it is possible to dynamically update row height based on user interaction. the Slickgrid API provides all that we need.

    Because:

    1. we can add/remove rows dynamically;
    2. we can dynamically apply custom css at row & cell level.


    Here is a simple demo to get things started:

    ////////////////////////////////////////////////////////////////////////////////
    //example codez re trying to create a grid with rows of dynamic height to
    //cater for folks that wanna bung loads of stuff in a field & see it all...
    //by violet313@gmail.com ~ visit: www.violet313.org/slickgrids
    //have all the fun with it  ;) vxx.
    ////////////////////////////////////////////////////////////////////////////////
    modSlickgridSimple=(
    function()
    {
        var _dataView=null;
        var _grid=null;
        var _data=[];
    
    
        //////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////
        var getPaddingItem=function(parent , offset)
        {
            var item={};
    
            for (var prop in _data[0]) item[prop]=null;
            item.id=parent.id+"."+offset;
    
            //additional hidden padding metadata fields
            item._collapsed=     true;
            item._isPadding=     true;
    
            return item;
        }
    
        //////////////////////////////////////////////////////////////
        //this just builds our expand collapse button
        //////////////////////////////////////////////////////////////
        var onRenderIDCell=function(row, cell, value, columnDef, item)
        {
            if (item._isPadding==true); //render nothing
            else if (item._collapsed) return "<div class='toggle expand'></div>";
            else
            {
                var html=[];
                var rowHeight=_grid.getOptions().rowHeight;
    
                //V313HAX:
                //putting in an extra closing div after the closing toggle div and ommiting a
                //final closing div for the detail ctr div causes the slickgrid renderer to
                //insert our detail div as a new column ;) ~since it wraps whatever we provide
                //in a generic div column container. so our detail becomes a child directly of
                //the row not the cell. nice =)  ~no need to apply a css change to the parent
                //slick-cell to escape the cell overflow clipping.
    
                //sneaky extra </div> inserted here-----------------v
                html.push("<div class='toggle collapse'></div></div>");
    
                html.push("<div class='dynamic-cell-detail' ");   //apply custom css to detail
                html.push("style='height:", item._height, "px;"); //set total height of padding
                html.push("top:", rowHeight, "px'>");             //shift detail below 1st row
                html.push("<div>",item._detailContent,"</div>");  //sub ctr for custom styling
                //&omit a final closing detail container </div> that would come next
    
                return html.join("");
            }
        }
    
        //////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////
        var onRowClick=function(e, args)
        {
            _dataView.beginUpdate();
    
            if ($(e.target).hasClass("toggle"))
            {
                var item=_dataView.getItem(args.row);
    
                if (item)
                {
                    if (!item._collapsed)
                    {
                        item._collapsed=true;
                        for (var idx=1; idx<=item._sizePadding; idx++)
                            _dataView.deleteItem(item.id+"."+idx);
                        item._sizePadding=0;
                    }
                    else
                    {
                        item._collapsed=false;
                        kookupDynamicContent(item);
                        var idxParent=_dataView.getIdxById(item.id);
                        for (var idx=1; idx<=item._sizePadding; idx++)
                            _dataView.insertItem(idxParent+idx, getPaddingItem(item,idx));
                    }
                    _dataView.updateItem(item.id, item);
                }
                e.stopImmediatePropagation();
            }
    
            _dataView.endUpdate();
        }
    
        //////////////////////////////////////////////////////////////
        var gridOptions={ enableColumnReorder:  true };
    
        //////////////////////////////////////////////////////////////
        var _gridColumns=
        [
            {
                id:         "id",
                name:       "",
                field:      "id",
                resizable:  false,
                width:      20,
                formatter:  onRenderIDCell,
            },
            {id: "title",        name: "Title",         field: "title",        resizable: true},
            {id: "duration",     name: "Duration",      field: "duration",     resizable: true},
            {id: "pcComplete",   name: "% Complete",    field: "pcComplete",   resizable: true},
            {id: "start",        name: "Start",         field: "start",        resizable: true},
            {id: "finish",       name: "Finish",        field: "finish",       resizable: true},
            {id: "effortDriven", name: "Effort Driven", field: "effortDriven", resizable: true},
        ];
    
        //////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////
        var kookupTestData=(function()
        {
            for (var i = 0; i < 100; i++)
                _data[i] =
                {
                    id:               i,
                    title:            "Task " + i,
                    duration:         "5 days",
                    pcComplete:       Math.round(Math.random() * 100),
                    start:            "01/01/2009",
                    finish:           "01/05/2009",
                    effortDriven:     (i % 5 == 0),
    
                    //additional hidden metadata fields
                    _collapsed:       true,
                    _sizePadding:     0,     //the required number of pading rows
                    _height:          0,     //the actual height in pixels of the detail field
                    _isPadding:       false,
                };
        })();
    
        //////////////////////////////////////////////////////////////
        //create the detail ctr node. this belongs to the dev & can be custom-styled as per
        //////////////////////////////////////////////////////////////
        var kookupDynamicContent=function(item)
        {
            //add some random oooks as fake detail content
            var oookContent=[];
            var oookCount=Math.round(Math.random() * 12)+1;
            for (var next=0; next<oookCount; next++)
                oookContent.push("<div><span>oook</span></div>");
            item._detailContent=oookContent.join("");
    
            //calculate padding requirements based on detail-content..
            //ie. worst-case: create an invisible dom node now &find it's height.
            var lineHeight=13; //we know cuz we wrote the custom css innit ;)
            item._sizePadding=Math.ceil((oookCount*lineHeight) / _grid.getOptions().rowHeight);
            item._height=(item._sizePadding * _grid.getOptions().rowHeight);
        }
    
        //////////////////////////////////////////////////////////////
        //jquery onDocumentLoad
        //////////////////////////////////////////////////////////////
        $(function()
        {
            //initialise the data-model
            _dataView=new Slick.Data.DataView();
            _dataView.beginUpdate();
            _dataView.setItems(_data);
            _dataView.endUpdate();
    
            //initialise the grid
            _grid=new Slick.Grid("#grid-simple", _dataView, _gridColumns);
            _grid.onClick.subscribe(onRowClick);
    
            //wire up model events to drive the grid per DataView requirements
            _dataView.onRowCountChanged.subscribe
                (function(){ _grid.updateRowCount();_grid.render(); });
    
            _dataView.onRowsChanged.subscribe
                (function(e, a){ _grid.invalidateRows(a.rows);_grid.render(); });
    
            $(window).resize(function() {_grid.resizeCanvas()});
        });
    }
    )();
    //////////////////////////////////////////////////////////////
    //done ;)
    ::-webkit-scrollbar       
    { 
        width:              12px; 
        background-color:   #B9BACC; 
    }
    ::-webkit-scrollbar-track 
    { 
        color:              #fff; 
        -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); 
        border-radius:      10px;  
    }
    ::-webkit-scrollbar-thumb 
    { 
        color:              #96A9BB; 
        border-radius:      10px;  
        -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5); 
    }
    
    body
    {
        font-family:        Arial, Helvetica, sans-serif;
        background-color:   #131313;
        position:           absolute;
        top:                5px;
        bottom:             5px;
        left:               5px;
        right:              5px;
    }
    
    #grid-simple
    {
        position:         absolute;
        top:              0px;
        left:             0px;
        right:            0px;    
        bottom:           0px;
        margin:           auto;
        font-size:        12px;
        background-color: #ECEEE9;
    }
    
    .toggle
    {
        height:           16px;
        width:            16px;
        display:          inline-block;
    }
    .toggle.expand
    {
        background: url(https://violet313.github.io/assets/expand.gif) no-repeat center center;
    }
    
    .toggle.collapse
    {
        background: url(https://violet313.github.io/assets/collapse.gif) no-repeat center center;
    }
    
    
    /*--- generic slickgrid padding pollyfill  ----------------------*/
     
    .dynamic-cell-detail
    {
        z-index:            10000;
        position:           absolute;
        background-color:   #F4DFFA;
        margin:             0;
        padding:            0;
        width:              100%;
        display:            table;
    }
    
    .dynamic-cell-detail > :first-child
    {
        display:            table-cell;
        vertical-align:     middle;
        text-align:         center;
        font-size:          12px;
        line-height:        13px;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script type="text/javascript" src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
    <script type="text/javascript" src="https://cdn.rawgit.com/Celebio/SlickGrid/master/lib/jquery.event.drag-2.2.js"></script>
    <script type="text/javascript" src="https://cdn.rawgit.com/Celebio/SlickGrid/master/slick.core.js"></script>
    <script type="text/javascript" src="https://cdn.rawgit.com/Celebio/SlickGrid/master/slick.grid.js"></script>
    <script type="text/javascript" src="https://cdn.rawgit.com/Celebio/SlickGrid/master/slick.dataview.js"></script>
    <link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/Celebio/SlickGrid/master/slick.grid.css">
    <link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/Celebio/SlickGrid/master/slick-default-theme.css">
    <link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/themes/base/jquery-ui.css">
    
    
    <div id="grid-simple"></div>

    Less than 200 lines of codes.
    fiddle with it!

    Incidentally, this is the kind of approach that the also excellent Datatables provides (almost) natively through it's API. &imo it is the correct pattern; & how i am choosing to implement my own stuff using Slickgrid. But it involves a slight hack and in any case does *not exactly meet the OP requirements; which i claim is possible.


    To do dynamic row-heights per-cell, we employ a similar trick but we must also deal with a few side-effects:~

    styling away the row divisions

    We must:

    1. escape the per-cell overflow clipping
    2. remove unwanted row stipeyness
    3. remove row borders

    The Slickgrid API provides row-based styling via the Grid.getItemMetadata callback interface. In the next fiddle, on line 107, see the onRenderRow implementation of this interface:
    fiddle with it!

    Notice also on lines 148-150, i invoke the Slickgrid Grid.setCellCssStyles API to add a custom dynamic-cell css class that sets the overflow to visible in order to style away the per-cell overflow clipping.

    column resizing

    If the detail content is static, column resizing is a gimme.

    Detail content that responds to a change in column width (flowing text or wotnot) requires some work. Padding rows need to be dynamically added and removed accordingly. See (from line 66) the addPadding and trimPadding functions in the next fiddle:
    fiddle with it!

    sorting

    There's some work to do here also. we need to ensure that no matter whether we are sorting up or down, the padding remains contiguously underneath the parent. See the comparer on line 136 in this next fiddle:
    fiddle with it!

    filtering

    Pretty much a one-liner: if it's padding, then delegate the comparison to the parent. job done. See the pcFilter on line 192 in the next fiddle:
    fiddle with it!

    Yay! that's resizing, sorting & filtering in under 500 lines of fairly legible, liberally commented custom javascripts.. i have in fact seen certain fancy input-range-slider pollyfills with more lines of code ;)
    acu


    Caveats

    I have only covered the basics. There is that whole selectable/editable aspect to Slickgrid,, ~which goes beyond my current requirements (sry).
    Also:

    • example-code only; not production ready. you have been warned etc etc =)
    • examples seem to work in most modern browsers; i have /not/ tried with iE; versions >= 11 might be ok..

    Further infos

    There is more to be said about this than can reasonably be squeeezed into a SO answer -notwithstanding the no-references policyguidelines. Anyone interested in knowing more about all this stuff can go here where i go into a fair bit more detail.

    One final example

    Here's a final fun example. it employs all of the above functionality but as can be seen, i have ditched the expando-rows and there are two dynamic content fields. Also, fyi, this example makes use of MutationObservers in order to generate onPostRender events as an alternative to the Slickgrid native asyncPostRender column option callback:
    fiddle with it!

    And there we have it. -some of the way towards a DataView-like Slickgrid extension-mod; & all without needing to resort to horrid hax on the lovely Slickgrid codes. yippee ;)

    OoOok! This post is some years old; and i see now that there are several forks of the currently unmaintained original project. ie: https://github.com/6pac/SlickGrid

    0 讨论(0)
  • 2020-12-10 05:33

    I attached a function to my grid which enables me to expand the row height:

    var normalHeight = 25;
    var expandedHeight = 100;
    var columns = [
        {id: "col1", name: "Column 1", field: "col1", expanded: false},
        {id: "col2", name: "Column 2", field: "col2"}
    ];
    var options = {
        rowHeight: normalHeight
    };
    var dataView = new Slick.Data.DataView();
    var grid = new Slick.Grid(element, dataView, columns, options);
    grid.updateOptions = function(expanded){
        var columns = grid.getColumns();
        if(!expanded){
            options['rowHeight'] = normalHeight;
            columns[0]['expanded'] = false;
        }else{
            options['rowHeight'] = expandedHeight;
            columns[0]['expanded'] = true;
        }
        grid.setOptions(options);
        grid.setColumns(columns);
        grid.invalidate();
        grid.render();
    }
    

    It seems to work nicely, hopefully this is helpful to someone.

    0 讨论(0)
  • 2020-12-10 05:38

    You can do this via css. Take a look at the slick.grid.css file, and make your desired changes there.

    Take a look at the

    .slick-row.ui-widget-content, .slick-row.ui-state-active classes

    OR

    You can use the rowHeight property of the SlickGrid

    take a look at the grid options

    https://github.com/mleibman/SlickGrid/wiki/Grid-Options

    0 讨论(0)
提交回复
热议问题