When the Modal component is inserted in a component that will be looped, say some money transactions sent from a server. When one of those components is clicked it creates the same number of Modal elements as the number of transactions.
It should only appear one Modal element in the DOM.
https://codesandbox.io/s/7k9kolkmv0
To replicate in the sandbox, please click on "grey" or "black" words in the table
Hi @luis-alves The state isActive, a boolean, will be shared for all the modals, so if one is toggled, all will be.
One option is to move the modal outside of the loop and the other one would be to change isActive to be a string or a number.
If you change the type to be a string, you can open each modal like this:
toggleModal = (id /* this value will be bound in the entries loop. */, event) => {
let st = null;
if (id > 0) {
st = "modal" + String(id);
}
this.setState({ isActive: st });
}
const rows = this.props.entries.map((row) =>
<div style={styleOfI} key={row._id} id={row._id}>
<i
onClick={this.toggleModal.bind(row._id)}>
<Modal isOpen={this.state.isActive == "modal" + String(row._id)}
onRequestClose={this.toggleModal.bind(0)}
...
If moved outside of the loop:
setRow => (row, event) => this.setState({ row });
const rows = this.props.entries.map((row) =>
....
<i onClick={this.setRow.bind(row)}>
return (
<div>
<div className="article-row">{rows}</div>
<Modal isOpen={this.state.row != null} ... onRequestClose={this.setRow.bind(null)}>
<h5 style={InsideOfI}>{this.state.row.date}</h5>
<h5 style={InsideOfI}>{this.state.row.payee}</h5>
<h5 style={InsideOfI}>{this.state.row.amount}</h5>
</Modal>
</div>
)
The second option is preferable because it won't create a modal per row.
Got it @diasbruno! But still can't close the modal by clicking the overlay.
Shouldn't it be <i onClick={this.setRow.bind(row, event)}> and setRow => (row, event) => this.setState({ row: event });? With these changes it works.
Oh sorry, it should be this.setRow.bind(null, row).
I prefer using setRow = row => event => { ... } and this.setRow(row) because it is a bit more clear.
Just as an example of how bind works (to remind myself).
var f = (x, y) => { console.log(x, y); };
f(1, 2);
1 2
var f2 = f.bind(null, 1 /* x */);
f2(2 /* y */);
1 2
var f3 = f.bind(null, 1 /* x */).bind(null, 2 /* y */);
f3();
1 2
And for me to know ;)
Hi @luis-alves The state
isActive, a boolean, will be shared for all the modals, so if one is toggled, all will be.One option is to move the modal outside of the loop and the other one would be to change
isActiveto be a string or a number.If you change the type to be a string, you can open each modal like this:
toggleModal = (id /* this value will be bound in the entries loop. */, event) => { let st = null; if (id > 0) { st = "modal" + String(id); } this.setState({ isActive: st }); } const rows = this.props.entries.map((row) => <div style={styleOfI} key={row._id} id={row._id}> <i onClick={this.toggleModal.bind(row._id)}> <Modal isOpen={this.state.isActive == "modal" + String(row._id)} onRequestClose={this.toggleModal.bind(0)} ...If moved outside of the loop:
setRow => (row, event) => this.setState({ row }); const rows = this.props.entries.map((row) => .... <i onClick={this.setRow.bind(row)}> return ( <div> <div className="article-row">{rows}</div> <Modal isOpen={this.state.row != null} ... onRequestClose={this.setRow.bind(null)}> <h5 style={InsideOfI}>{this.state.row.date}</h5> <h5 style={InsideOfI}>{this.state.row.payee}</h5> <h5 style={InsideOfI}>{this.state.row.amount}</h5> </Modal> </div> )
Thank you!!
Most helpful comment
Hi @luis-alves The state
isActive, a boolean, will be shared for all the modals, so if one is toggled, all will be.One option is to move the modal outside of the loop and the other one would be to change
isActiveto be a string or a number.If you change the type to be a string, you can open each modal like this:
If moved outside of the loop: