datatables.net-react 1.0.0 slots function does not consider all columns
datatables.net-react 1.0.0 slots function does not consider all columns
Description of problem: The use of columnDefs
with the string _all
- all columns (i.e. assign a default) doesn't work for datatables.net-react slots, in the source code, the check for string _all
is missing.
It seems that the datatables.net-react repo: https://github.com/DataTables/React is not visible, so I'll post my fix in here.
in the source code:
function applySlots(cache: SlotCache, options: DTConfig, slots: DataTableSlots) {
if (!options.columnDefs) {
options.columnDefs = [];
}
Object.keys(slots).forEach((name) => {
let slot = slots[name];
if (!slot) {
return;
}
// Simple column index
if (name.match(/^\d+$/)) {
// Note that unshift is used to make sure that this property is
// applied in DataTables _after_ the end user's own options, if
// they've provided any.
options.columnDefs!.unshift({
target: parseInt(name),
render: slotRenderer(cache, slot)
});
}
else {
// Column name
options.columnDefs!.unshift({
target: name + ':name',
render: slotRenderer(cache, slot)
});
}
});
}
the fix:
function applySlots(cache: SlotCache, options: DTConfig, slots: DataTableSlots) {
if (!options.columnDefs) {
options.columnDefs = [];
}
Object.keys(slots).forEach((name) => {
let slot = slots[name];
if (!slot) {
return;
}
// Apply to all columns
if (name === '_all') {
options.columnDefs!.unshift({
targets: '_all',
render: slotRenderer(cache, slot)
});
}
// Simple column index
else if (name.match(/^\d+$/)) {
// Note that unshift is used to make sure that this property is
// applied in DataTables _after_ the end user's own options, if
// they've provided any.
options.columnDefs!.unshift({
target: parseInt(name),
render: slotRenderer(cache, slot)
});
}
else {
// Column name
options.columnDefs!.unshift({
target: name + ':name',
render: slotRenderer(cache, slot)
});
}
});
}
with this fix, slots like below can work.
slots={{
_all: (data, type, row) => {
return "<div class='whitespace-normal max-w-60'>" + data || "-" + "</div>";
}
}}
which now applies to all columns
Hope it helps!
Edit: Oh! This is not perfect and the _all will overwrite other columns!
Replies
Also another performance issue is about the render of React component using slots. It seems that the deferRender is not applied for the slots.
If I have more than 30 rows (with a button (React component) in column 0, rendered with slots), I can see a slightly delay. And noticeable delay when over 80 rows. And my Chrome crashes when I have 20000 rows. But I do need to render those buttons for some interactions.
Any advice on how to solve this performance issue? I have deferRender and pagination enabled. But it seems that the slots are making React render all the rows, causing a significant performance issue.
https://stackblitz.com/edit/datatables-net-react-simple-pm4amf?file=src%2FApp.tsx
This is the demo case using slots to render button.
Try to feel the delay from 20, 200, 2000, and 20000 rows. it took me ~5 seconds to see the result for 2000 rows.
Doh - sorry about that. I had it private during the initial development of the component and then must have forgotten to update it. Don enow.
Good point about the
_all
- thank you - I'll get that included.Performance-wise - try only to return JSX for the
display
type (second parameter to the rendering function). If you return JSX for all, you are forcing it to render that JSX and then extract the data needed. For type detection, sorting and filtering that normally is not needed and you can just return the underlying data.The
display
type will only be requested when DataTables needs to draw the cell on the page, so with pagination enabled, you should hopefully see a decent difference in performance.Allan
Thank you Allan for pointing out that! I just tried to wrap the JSX for only display type.
it will just run for only the first page indeed.
But then, when I resize the page. It continues to render the rest on init! And then the whole page freezes for a moment.
See the demo case below.
https://stackblitz.com/edit/datatables-net-react-simple-e5jf2a?file=src%2FApp.tsx
Open the dev tool first, and then reload the preview. See that only 10 rows are rendered and print
display
in console. Resize the page (or click the column to sort), see that all the rest rows are being rendered and printdisplay
in console.In my case since I have sidebar so I must call
columns.adjust()
right after init, which means the all JSX components are being rendered actually. And that causes the performance issue.Is it possible to stop rendering all rows when sorting or resizing? That is, when resizing, only the current rows on the first page are taken into account for the draw. And when sorting, sort the orthogonal data first and then render the JSX in the cells for the first page.
There isn't an option for that. What I think must be happening is that it is trying to find the longest string to optimise the column widths. I'll need to have a look into finding a way to either limit that to the current page, or some other option.
Allan
That's it!
Disable the
autoWidth
works! But then the columns are not automatically adjusted when the window size is changed.I use
draw
andorder
to adjust the column instead.See here:
https://stackblitz.com/edit/datatables-net-react-simple-ijtxhg?file=src%2FApp.tsx
I think this would be fine for me to disable
autoWidth
as I must call thecolumns.adjust()
anyway later on.This one listens to the window resize event:
https://stackblitz.com/edit/datatables-net-react-simple-trcv79?file=src%2FApp.tsx
It would be nice if there were an option (or built-in default) for optimization, as you mentioned.
Cunning! That hadn't crossed my mind, but good to hear you found a workaround for now. Yes, it would definitely be good to improve this aspect of the software.
Allan
Hi Allan, I just realized that the slots doesn't have
meta
argument.From https://datatables.net/reference/option/columns.render
There is 4 arguments
But for the slots described in https://datatables.net/manual/react#React-Components:
I tried to get the row index while rendering but the
meta
doesn't exist for the slots.I wasn't sure about adding the meta property - the main use of it was to get the rendered cell node, but that is redundant in React. I can certainly add it in though. What's the use case?
Allan
For example I use Scroller plug-in and slots to render button in cells.
When I click the button, I want to add its row index in the onClick event so that I can replace the classes of the button to change its color to indicate that it is selected. However, since it does not update itself when the state/class changes, I have to use
cell().data()
andcell().invalidate()
to manually update the button when I click it I guess.And another use case would be restoring:
since I create the table in a Dialog (Modal), I would open it again later and use
row().scrollTo()
to scroll the table to the selected button, so that the selected button is visible/findable when it opens. Especially if the table is unmounted, we can restore the state later using the row index.I'm not sure if I'm overthinking whether or not they need a row index to do that.
Would:
do the job for you? Where
this
is the button (modify as needed). I generally try to steer people away from the meta property. I don't have a good solid reason, but it just always felt like a bit of a workaround.Allan
Hi Allan, it works for the onClick event. Thank you!
I use:
But I'm a bit stuck again. How can I do to change the
variant
prop value of the Button based on the selectedIndex?I want to change the variant value from
outline
todefault
(which will render to another button style) if the button's index euqals to the selected indexI will then update it with
useEffect
:any workarounds without using the meta property?
BTW, I noticed that the
row().scrollTo()
does not scroll exactly the row indexposition
. I suspect it is due to the rendered button that causes the changing in the height that I mentioned in another discussion's comment in here. I will try to provide a test case if needed.In general, I guess it would be the
scroller.rowHeight
that is not fixed so the height is changingHere's the test case about the Scroller
row().scrollTo()
with slots render issue:https://stackblitz.com/edit/datatables-net-react-simple-fvmt9f?file=src%2FApp.tsx
It will have slightly shift after using
row().scrollTo()
. And even more shift when I don't provide a fixed height using:I don't think so I'm afraid. Not in this case since it is happening inside the renderer rather than externally in an event handler. I'll see about getting that change in next week.
Regarding the scrolling issue - you might need to call
scroller.measure()
when the table is displayed.I do have a plan to have resizing calculations happen automatically - probably DataTables 2.2 when that happens.
Allan
It seems that it cannot scroll to the last cell correctly.
For the clicked cell in the middle, the scroll position seems to be different each time the table is opened, even if the
scroller.measure()
is used.Here's the test case: https://stackblitz.com/edit/datatables-net-react-simple-yq8xph?file=src%2FApp.tsx
Thank you - I'll take a look at it when I'm back in the office.
Allan
Hi Allan,
Is there any updates about getting the
meta
property available for slot for React?Regarding the issue with the scroller, below is another post that may relate to the scroller scroll shift issue:
https://datatables.net/forums/discussion/80158/scroller-plug-in-breaks-info-configuration
Apologies - not yet. I've been focusing on some changes for Editor. React updates will be the first thing I do once that work is complete.
Allan