Reputation: 79
I'm attempting to create a component that consists of rows of data, which when clicked, open a modal with information relating to that table row. For example, when a user clicks on "team 1", a modal would appear showing a new table displaying each of the users assigned to that team.
I've managed to achieve this using manually provided parameters, however I have no idea how to make the modal dynamically display data depending on which table row has been clicked. Here is a link to a jsfiddle that i've made to show my problem.
getInitialState: function () {
return {
teams:[
{
id: '1',
teamName: 'team 1',
users: ['dave', 'steve', 'jim', 'barry', 'tom', 'harry']
},
]
};
render: function () {
var self = this;
var projectsTable = this.state.teams.map(function (obj, index) {
return (
<tr className="table-teamProject" key={index} data-toggle="modal" data-target="#projectUsersModal" data-id='3'>
<div className="mCellsContainer">
<div className="mCellsNames">{obj.teamName}</div>
<div className="mCellsCount">{obj.users.length} Users</div>
</div>
</tr>
);
});
var projectUsersModal = this.state.teams.map(function (obj, index) {
return (
<div className="modal projectUsersModal fade" id="projectUsersModal" tabIndex={-1} role="dialog" aria-labelledby="myModalLabel">
<div className="modal-dialog" role="document">
<div className="modal-content">
</div>
</div>
</div>
);
});
return (
<div>
<div className="projectsColContainer">
<div className="panel panel-default">
<div className="panel-heading">Projects</div>
<table className="scroll-table">
{projectsTable}
{projectUsersModal}
</table>
</div>
</div>
</div>
);
}
Upvotes: 0
Views: 3200
Reputation: 571
You can use https://github.com/fckt/react-layer-stack .
It allows you to both use variables from closure (which will propagate automatically if you'll provide it to "use" property of Layer) and also set event data from your toggle to modal window. Also you can have "stack" of layers with zIndex, one on another.
import { Layer, LayerContext } from 'react-layer-stack'
// ... for each `object` in array of `objects`
const modalId = 'DeleteObjectConfirmation' + objects[rowIndex].id
return (
<Cell {...props}>
// the layer definition. The content will show up in the LayerStackMountPoint when `show(modalId)` be fired in LayerContext
<Layer use={[objects[rowIndex], rowIndex]} id={modalId}> {({
hideMe, // alias for `hide(modalId)`
index } // useful to know to set zIndex, for example
, e) => // access to the arguments (click event data in this example)
<Modal onClick={ hideMe } zIndex={(index + 1) * 1000}>
<ConfirmationDialog
title={ 'Delete' }
message={ "You're about to delete to " + '"' + objects[rowIndex].name + '"' }
confirmButton={ <Button type="primary">DELETE</Button> }
onConfirm={ this.handleDeleteObject.bind(this, objects[rowIndex].name, hideMe) } // hide after confirmation
close={ hideMe } />
</Modal> }
</Layer>
// this is the toggle for Layer with `id === modalId` can be defined everywhere in the components tree
<LayerContext id={ modalId }> {({showMe}) => // showMe is alias for `show(modalId)`
<div style={styles.iconOverlay} onClick={ (e) => showMe(e) }> // additional arguments can be passed (like event)
<Icon type="trash" />
</div> }
</LayerContext>
</Cell>)
// ...
Upvotes: 0
Reputation: 793
The render()
method is creating, what I think would be, a hidden modal for every team you have in your teams array, regardless of if the user requested the modal to show up (clicked on the team's link) or not. A better approach would be to create the specific modal on demand, that's when the user clicks on the team's link.
This can be done by creating a click handler and inside that function you would modify the state by setting the id of the team the modal is about, like so:
onClickTeam: function(teamId) {
this.setState({
openModalTeamId: this.state.openModalTeamId == teamId ? null : teamId
});
}
Then in your render()
method you will want to check if this openModalTeamId
state property has some value in it, if so and since your are storing the team's id in there, you would want to look for this particular team in your state teams array using the Array.prototype.find
and then use the returned result to construct your modal's content.
render: function() {
...
var modalBody;
if (this.state.openModalTeamId) {
var team = this.state.teams.find(function(el) {
return el.id == self.state.openModalTeamId
});
modalBody =
...
<div className="modal-body">
Lets assume this is your modal containing the
following info about the selected team:
<br /><br />
{JSON.stringify(team)}
<br /><br />
<div onClick={(this.onClickTeam.bind(this, team.id))}>
Click me to close
</div>
</div>
...
}
...
}
Once you have that you can just append this new modalBody
variable to your render's JSX just like you do in your code using the projectUsersModal
variable. If no team was clicked on, then this variable would be undefined
and no modal will show up.
return (
<div>
<div className="projectsColContainer">
<table className="scroll-table">
{projectsTable}
{modalBody}
</table>
</div>
</div>
);
Upvotes: 3