react-bootstrap-table2
react-bootstrap-table2 copied to clipboard
How to pass editable state into column formatters
I am trying to implement a toggle button which has its own jsx inside one of the boostrap table's columns (for leftmost cell each row).
My issue is I can't seem to find a way to pass the parent's callback function from the react-bootstrap-table itself into a column formatter (i.e. there is no bind this allowed) such that a callback gets called from the parent that can change state based on whether someone hits the toggle button in each cell or not.
Basically my overall goal is to have some "parent rows" with expander button on left-hand most column and if a person hits that expander button it will change the state of a hiderow[] array of booleans and redraw the table data showing the once hidden child rows based on parent expansion. (These are basically the same display style as the parents, it's just that the parent expander button "uncoils them into view".)
Every other bit of the logic works in this pipeline except how to get a state-changing function passed to an external .jsx as a callback. Because as opposed to normal React parent-child interaction I have to somehow feed the callback function through the column formatter function, which seems to reside outside the React component that uses it (hence passing state functions not easy).
I have to go through the column formatter obviously because this toggle button appears on every single row and so has to be replicated, calling different ids, etc... I tried to use a generic column click event but lol can't get rowID from that nor grab the inner toggle imagebutton except for maybe low-level js. Similarly the row click event. (There does not appear to be a cell-click event but this too would need a further "zoom in" on the image button inside it).
I'm also not able to update columns with dynamic data in the formatter: functions of column definition. Each time state gets updated the column formatter: functions were never run
@JohnVLinton It is possible to do so.. formatters: are pure functions and you need to pass external state data using formatExtraData along with formatter
please check doc below
https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnformatextradata-any
I have the same issue. if I set formatExtraData: this.props.teams and the data attached to this cell or row with isDummyField: true, the cell doesn't update when this.props.teams change (immutability respected). Do you have the same problem?
I could be wrong but I think that the issue is it updates only if the number of column change
https://github.com/react-bootstrap-table/react-bootstrap-table2/blob/9d2a6a1b23078be9426ce6130e8d156553600088/packages/react-bootstrap-table2/src/row/should-updater.js#L23-L31
It would be great to trigger rows update if formatExtraData is modified. Would this change work in should-updater.js? shouldComponentUpdate should be modified accordingly in cell.js too to track change on formatExtraData
shouldUpdatedByNormalProps(nextProps) {
const shouldUpdate =
this.props.rowIndex !== nextProps.rowIndex ||
this.props.editable !== nextProps.editable ||
!_.isEqual(this.props.row, nextProps.row) ||
this.props.columns !== nextProps.columns;
return shouldUpdate;
}
@AllenFang your thoughts?
Same here, passing this.state.something into formatExtraData does not seem to re-run the formatter
Did any of your find a workaround for this? I'm hitting the same issue right now. For now, I'm using this dirty little hack to get around it by setting a hidden field to a random value on the desired row. That way, it forces a re-render
this.setState({
data: data.map(row => {
if (row.id == id) {
return { ...id, dirty: Math.random() }
}
return row;
});
}
Yes I believe there is a way we found (not right in front of me).
Key is for you to console.log() inside the formatter the objects and you should be able to find how to pass an additional property. You basically walk it out until you use up all the fields the library needs, (p1, p2, p3, ...) then the next space is where you can add your own, I think, if I recall right...
@jvlinton ,Could you please provide an example for this..i need to show a tooltip on hover of a cell..stuck with the same issue,state is updated but formatter is not being invoked.
`formatter: (cell, row, rowIndex, { showTooltip }) => {
console.log('in cel', cell) // not being logged when showTooltip is changed
console.log('tooltipOpen in formatter', showTooltip)
const tags = cell.split(',').filter(a => a)
console.log('tags', tags)
if (tags.length <= 2) {
console.log('in first')
return <div>{cell}</div>
} else {
return (
<div>
<div id={`TooltipExample${row.id.replace(/\//g, '')}`}>{`${
tags[0]
},${tags[1]} + ${tags.length - 2} more`}</div>
<Tooltip
placement="right"
isOpen={showTooltip}
target={`TooltipExample${row.id.replace(/\//g, '')}`}
toggle={this.toggleTooltip}
>
{`${tags.slice(2).join(',')}`}
</Tooltip>
</div>
)
}
},
formatExtraData: {
showTooltip
}`
toggleTooltip = () => {
console.log('in toggle')
this.setState(prevState => ({ showTooltip: !prevState.showTooltip }))
}
I had to re-render the component with a show/hide react condition after trying to solve it for hours. It used to work in previous version(^1.1) but after 2, i believe performance checks inside the component has made this update to not happen.
The same issue for me unfortunately :/
EDIT #1: Upgrading to version 4.0.1 resolved my issue
@DorienMay
Do you have a working example? I still can't get this to work even on 4.0.1...
I'll try to find an example of the code... The secret to figuring out how is to console.log each of the things coming into the formatter, if I remember rightly, and keep adding params until you can add something new that the library isn't already sending in... Or else I think you can hack/overwrite the row object and return extra param or something like that
Try: static keyword
-
Bind the static method in constructor MyClass.showModal = MyClass.showModal.bind(this);
-
Define the method static showModal() { this.setState({ show: true }) };
-
Call the static method from Formatter method
const cellFormatter = () => { return ( <Button className={'btn btn-primary'} onClick={MyClass.showModal}>Attend</Button> ); };
First set a key on the bootstrap table. When you update the data which you're not seeing reformatted, also change the key name of the bootstrap table. That will force React to re-rendered the table and your formatter method will, just like magic, do its thing.
did you find any solution for this ?