bootstrap-table icon indicating copy to clipboard operation
bootstrap-table copied to clipboard

bootstrapTable object of sub-table lost after refresh of main table

Open kkozlik opened this issue 2 years ago • 3 comments

Bootstraptable version(s) affected

1.21.1

Description

When I create a nested tables (using detailView) and do refresh of the main table, the bootstrapTable object of the nested tables are lost.

The html code of the tables is still there, but calling: $('.subtable').bootstrapTable('some method') return always just the jquery collection (like calling just $('.subtable')). That's because the $('.subtable').data('bootstrap.table') is undefined

Example(s)

See the example here:

https://live.bootstrap-table.com/code/kkozlik/13116

  • Expand a row
  • Pressing the button get sub-table data correctly shows output of getData method
  • Pressing the button get sub-table object shows an object (that is the $('.subtable').data('bootstrap.table'))
  • Now press the 'refresh' button
  • Pressing the button get sub-table data now shows jQuery collection
  • Pressing the button get sub-table object now shows undefined

Possible Solutions

IMO this piece of code of initBody function is problematic:

          const oldTr = this.$body.find(Utils.sprintf('> tr[data-uniqueid="%s"][data-has-detail-view]', itemUniqueId))
          const oldTrNext = oldTr.next()

          if (oldTrNext.is('tr.detail-view')) {

            toExpand.push(i)

            if (!updatedUid || itemUniqueId !== updatedUid) {
              tr += oldTrNext[0].outerHTML
            }
          }

It should be replaced with something like:

          const oldTr = this.$body.find(Utils.sprintf('> tr[data-uniqueid="%s"][data-has-detail-view]', itemUniqueId))
          const oldTrNext = oldTr.next()

          if (oldTrNext.is('tr.detail-view')) {

            toExpand.push(i)

            trFragments.append(oldTrNext)
          }

Maybe some additional changes in the function will be needed, but basically do not copy just the outerHTML, but whole DOM node.

Another solution might be to call onExpandRow event (or a different, new one) when table is refreshed, so there is a chance to re-initialize the subtables. Maybe one event before the refresh and second after it? So the data can be saved before destroyed by the refresh and then restored. Just a suggestion...

Additional Context

No response

kkozlik avatar Oct 07 '22 12:10 kkozlik

I think I have found workaround for the issue. But it would be nice having it implemented directly in the initBody function:


        var expandedRows = {};

        tableEl.on('pre-body.bs.table', function(e){

            // skip bubbled events from nested tables
            if (e.target != e.currentTarget) return;

            expandedRows = {};

            tableEl.find(">tbody>tr.detail-view").each(function(index, tr){
                var $tr = $(tr);
                row_uniqueid = $tr.prev().data('uniqueid');
                expandedRows[row_uniqueid] = $(document.createDocumentFragment());
                expandedRows[row_uniqueid].append($tr.find('>td'));
            });
        });

        tableEl.on('post-body.bs.table', function(e){

            // skip bubbled events from nested tables
            if (e.target != e.currentTarget) return;

            tableEl.find(">tbody>tr.detail-view").each(function(index, tr){
                var $tr = $(tr);
                row_uniqueid = $tr.prev().data('uniqueid');
                if (expandedRows[row_uniqueid] && expandedRows[row_uniqueid].children().length){
                    $tr.empty();
                    $tr.append(expandedRows[row_uniqueid]);
                }
            });
        });

kkozlik avatar Oct 11 '22 13:10 kkozlik

We're running into a similar problem where the click events on the pagination for a sub-table is broken after calling 'updateByUniqueId' on a different row.

Quintinon avatar Nov 17 '22 17:11 Quintinon

We had a weird interaction with the suggested workaround and using virtual-scroll without a default item height set. If the first row was expanded, the auto-detection of rowHeight from virtual scroll was picking one of the detail rows which now had no contents and thus a zero height.

We fixed this by modifying the provided example to instead of storing the tr>td inside a dom fragment, we stored the entire tr in a dom fragment. Then in the after we needed to call bootstrapTable('expandRowByUniqueId') on the row to correct the row expansion icon as the detection code in bootstrap table saw that there was no detail row and was putting the "+" icon back instead of a "-" icon.

        var expandedRows = {};

        tableEl.on('pre-body.bs.table', function(e){

            // skip bubbled events from nested tables
            if (e.target != e.currentTarget) return;

            expandedRows = {};

            tableEl.find(">tbody>tr.detail-view").each(function(index, tr){
                var $tr = $(tr);
                row_uniqueid = $tr.prev().data('uniqueid');
                expandedRows[row_uniqueid] = $(document.createDocumentFragment());
                expandedRows[row_uniqueid].append($tr));
            });
        });

        tableEl.on('post-body.bs.table', function(e){

            // skip bubbled events from nested tables
            if (e.target != e.currentTarget) return;

            tableEl.find(">tbody>tr").each(function(index, tr){
                var $tr = $(tr);
                row_uniqueid = $tr.data('uniqueid');
                if (expandedRows[row_uniqueid] && expandedRows[row_uniqueid].children().length){
                    $tr.after(expandedRows[row_uniqueid]);
                    tabelEl.bootstrapTable('expandRowByUniqueId', row_uniqueid);
                }
            });
        });

Quintinon avatar Jan 26 '23 17:01 Quintinon