Можно ли динамически изменять высоту строки SlickGrid?

Мы реализуем пользовательское предпочтение (мгновенно) отображать «больше» или «меньше» данных в сетке. «Больше» должно увеличить высоту строки (каждая строка имеет одинаковую увеличенную высоту).

Когда пользователь переключается, мы обновляем наш DataView и вызываем setOptions в сетке с обновленным значением rowHeight. Затем мы вызываем invalidate() и render().

Но высота строки не обновляется. :(

Может кто подскажет решение? Должны ли мы изменять высоту напрямую через CSS? Если да, то какие советы по этому поводу?


person Dave Clausen    schedule 10.05.2012    source источник


Ответы (3)


Действительно, можно динамически обновлять высоту строки в зависимости от взаимодействия с пользователем. Slickgrid API предоставляет все, что нам нужно.

Так как:

  1. мы можем динамически добавлять/удалять строки;
  2. мы можем динамически применять пользовательские css на уровне строк и ячеек.


Вот простая демонстрация для начала работы:

////////////////////////////////////////////////////////////////////////////////
//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 [email protected] ~ 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>

Менее 200 строк кода.
поиграйте с этим!

Между прочим, именно такой подход предлагает отличная Datatables (почти) изначально через API. &imo это правильный шаблон; и как я решаю реализовать свои собственные вещи, используя Slickgrid. Но это связано с небольшим взломом и в любом случае *не совсем соответствует требованиям OP; что я утверждаю, что это возможно.


Чтобы сделать динамическую высоту строки на ячейку, мы используем аналогичный трюк, но мы также должны иметь дело с несколькими побочными эффектами:~

удаление разделения строк

Мы должны:

  1. избежать отсечения переполнения per-cell
  2. удалить нежелательную стеснительность строк
  3. удалить границы строк

Slickgrid API обеспечивает стиль на основе строк через Grid. .getItemMetadata интерфейс обратного вызова. В следующей скрипке в строке 107 см. onRenderRow реализацию этого интерфейса:
возиться с этим!

Обратите также внимание на строки 148-150, я вызываю Slickgrid Grid.setCellCssStyles API для добавления пользовательского класса dynamic-cell css, который задает для overflow значение visible, чтобы убрать отсечение переполнения на ячейку.

изменение размера столбца

Если содержание сведений является статическим, изменение размера столбца не представляет сложности.

Детальное содержание, которое отвечает на изменение ширины столбца (текущий текст или wotnot), требует некоторой доработки. Строки заполнения должны динамически добавляться и удаляться соответствующим образом. См. (со строки 66) функции addPadding и trimPadding в следующей скрипте:
возиться с этим!

сортировка

Здесь тоже есть над чем поработать. нам нужно убедиться, что независимо от того, сортируем ли мы вверх или вниз, заполнение остается непрерывным под родителем. См. comparer в строке 136 в следующей скрипке:
поиграйте с ней !

фильтрация

В значительной степени однострочный: если это заполнение, то делегируйте сравнение родителю. Работа выполнена. См. pcFilter в строке 192 в следующей скрипке:
поиграйте с ней !

Ура! это изменение размера, сортировка и фильтрация в менее чем 500 строк довольно разборчивых, щедро прокомментированных пользовательских javascripts.. я действительно видел некоторые причудливые input-range-slider pollyfills с большим количеством строк кода;)


Предостережения

Я рассмотрел только основы. В Slickgrid есть целый аспект выбираемого/редактируемого, который выходит за рамки моих текущих требований (извините).
Также:

  • только пример кода; не готов к производству. вы были предупреждены и т. д. и т. д. =)
  • примеры работают в большинстве современных браузеров; я /не/ пробовал с iE; версии >= 11 могут быть в порядке..

Дополнительная информация

Об этом можно сказать больше, чем можно разумно втиснуть в SO ответ, несмотря на правила политики без ссылок. Любой, кто хочет узнать больше обо всем этом, может перейти здесь, где я расскажу подробнее.

Последний пример

Вот последний забавный пример. он использует все вышеперечисленные функции, но, как видно, я отказался от расширяемых строк и теперь есть два поля динамического содержимого. Кроме того, к сведению, в этом примере используются MutationObservers для создания onPostRender в качестве альтернативы Slickgrid родному asyncPostRender параметру столбца обратный вызов:
поиграйте с этим!

И вот оно. - часть пути к DataView-like Slickgrid extension-mod; и все это без необходимости прибегать к ужасному хакерству с прекрасными кодами Slickgrid. ура ;)

Оооок! Этому посту несколько лет; и теперь я вижу, что есть несколько ответвлений исходного проекта, который в настоящее время не поддерживается. например: https://github.com/6pac/SlickGrid

person violet313    schedule 01.04.2015
comment
Привет @ violet313. Я пробую ваше решение, описанное выше, но оно мне кажется трудным. чтобы больше не ложиться.. пытался получить его через какой-то интернет-архив, но безуспешно.. вы могли бы опубликовать эту информацию где-нибудь еще, или она исчезла навсегда? Спасибо! - person Shorttylad; 02.03.2020
comment
@Shorttylad, да. извините, мне нужно было исправить ссылку: / в настоящее время у меня нет веб-хостинга, но, возможно, я смогу проверить все howto хотя бы на github :) - вы можете потерпеть несколько дней, , всегда есть jsfiddles; они еще работают.. - person violet313; 03.03.2020
comment
Спасибо - ценю это. Я использовал скрипки в качестве системы отсчета и пытался внедрить их в свою собственную сетку, но новая строка не будет отображаться. Я, вероятно, недостаточно хорошо понимаю, как это работает, поэтому дополнительная информация будет большим подспорьем. - person Shorttylad; 04.03.2020
comment
@Shorttylad. готово. эта ссылка, где я рассказываю подробнее в разделе Дополнительная информация, должна снова подойти. к вашему сведению, rawgit cdn вот-вот умрет, так что теперь я загружаю javascripts slickgrid из 6pac.github.io/ SlickGrid - если есть какие-либо критические изменения. кто-нибудь дайте мне знать, и я полагаю, что я буду служить со своих страниц github .. вздыхает - person violet313; 05.03.2020
comment
Вау.. это много деталей.. теперь никаких оправданий :). Я думаю, что это может быть связано с тем, что я использую группировку в своей сетке, которая вызывает у меня проблемы, но я попробую еще раз! Спасибо - person Shorttylad; 06.03.2020
comment
лол, я чувствую, что это самое меньшее, что я могу сделать. Я многим обязан тем, кто приложил гораздо больше усилий, чтобы быть полезным, чем я когда-либо. хаха. удачи с javascripts @Shorttylad! - person violet313; 06.03.2020

Вы можете сделать это через css. Взгляните на файл slick.grid.css и внесите в него нужные изменения.

Взгляните на

.slick-row.ui-widget-content, .slick-row.ui-state-active классы

OR

Вы можете использовать свойство rowHeight SlickGrid

взгляните на параметры сетки

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

person G-Man    schedule 18.05.2012
comment
Спасибо GX за ответ. Обратите внимание, что я стремлюсь динамически обновлять высоту строки в зависимости от взаимодействия с пользователем... изменение свойства rowHeight, похоже, этого не делает. Когда я смогу, я попробую маршрут CSS - если это сработает, я отмечу это как принятый ответ. Еще раз спасибо! - person Dave Clausen; 21.05.2012
comment
Спасибо, что спросили @epotter ... На самом деле у меня не было возможности (или расстановки приоритетов) вернуться к этому. Тем не менее, я продолжу и отмечу ответ GX как принятый. - person Dave Clausen; 02.06.2012
comment
Если вы не пробовали, зачем отмечать как выполненное? У меня тот же вопрос о высоте строки, но теперь я не знаю, полезен ли этот ответ. - person bradley.ayers; 25.10.2012
comment
Я пытался использовать rowHeight, но по умолчанию он рассчитывается в px.. Я не могу сделать его autoIncrease.. Я пытаюсь изменить строку 909 (slickGrid.js) на auto. Дайте знать, если у кого-то получилось - person Viral; 22.02.2013
comment
Из-за общественного протеста я снял этот флажок как принятый ответ. Это казалось приемлемым ответом; но я провел рефакторинг, так что мне больше не нужно было динамическое изменение. Кроме того, тогда я был скорее ТАКИМ новичком. Извинения. - person Dave Clausen; 19.02.2016

Я прикрепил к своей сетке функцию, которая позволяет мне увеличить высоту строки:

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();
}

Кажется, работает хорошо, надеюсь, это полезно для кого-то.

person JstnPwll    schedule 18.02.2016
comment
Прошло много времени с тех пор, как я использовал это, поэтому я не уверен на 100%, но я думаю, что у меня был флажок, чтобы переключать, было ли медиа развернуто или свернуто. Я вызывал эту функцию всякий раз, когда менялся флажок. - person JstnPwll; 20.06.2017