简体   繁体   中英

Dynamically displaying data from a clickable table row into a modal

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>
    );
  }

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>
);

jsFiddle

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>)
// ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM