bootstrap-table
bootstrap-table copied to clipboard
bootstrapTable object of sub-table lost after refresh of main table
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 ofgetData
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
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]);
}
});
});
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.
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);
}
});
});