Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactJS + Material-UI: How to use Material-UI’s FlatButton and Dialog in each TableRow?

I have a Material-UI’s <Table>, and in each <TableRow> (which is dynamically rendered) for the <TableBody>, I would like to have a button (<FlatButton>) for one of the columns. And once the button is clicked on, it will open up a <Dialog> and inside it would like to have a working <Tabs>.

So how can I display a <FlatButton> for each row for a particular column, and when the button is clicked on, display the <Dialog> along with a working <Tabs> on the inside as the content? And have the <Dialog> close when clicked on outside?

So far I have the following, but came across the following issues: the opens up but it is slow and clicking outside the <Dialog> is not closing it, the <Tabs> is visible but it is not working:

Main Table:

import React, { Component } from 'react'
import {
  Subheader,
  Table,
  TableBody,
  TableHeader,
  TableHeaderColumn,
  TableRow,
} from 'material-ui'

import RenderedTableRow from ‘./RenderedTableRow'

export default class MainTable extends Component {
  constructor() {
    super()
  }

  render() {

    return (
      <div>
        <div>
        <Subheader>Table</Subheader>
          <Table
            multiSelectable={true}
          >
            <TableHeader
              displaySelectAll={true}
              enableSelectAll={true}
            >
              <TableRow>
                <TableHeaderColumn>
                  Col 1
                </TableHeaderColumn>
                <TableHeaderColumn>
                  Col 2
                </TableHeaderColumn>
                <TableHeaderColumn>
                  Col 3
                </TableHeaderColumn>
              </TableRow>
            </TableHeader>
            <TableBody
              deselectOnClickaway={false}
              stripedRows
           >
              <RenderedTableRow {...this.props}/>
            </TableBody>
          </Table>
        </div>
      </div>
    )
  }
}

Rendered Table Row:

import React, { Component } from 'react'

import { Dialog, FlatButton, Tabs, Tab,  TableRow, TableRowColumn } from 'material-ui'
import ContentAdd from 'material-ui/svg-icons/content/add';

export default class RenderedTableRow extends Component {
  constructor(props) {
    super(props)

    this.state = {
      open: false,
    }

    this._handleOpen = this._handleOpen.bind(this)
    this._handleClose = this._handleClose.bind(this)
  }

  _handleOpen() {
    this.setState({
      open: true
    })
  }

  _handleClose() {
    this.setState({
      open: false
    })
  }

  render() {
    const {
      children,
      ...rest
    } = this.props

    const actions = [
      <FlatButton
        label="Cancel"
        primary={true}
        onClick={this._handleClose}
      />,
    ]

    return (
      <TableRow {...rest}>
        {children[0]}
        <TableRowColumn>Red</TableRowColumn>
        <TableRowColumn>John, Joshua</TableRowColumn>
        <TableRowColumn>
          <FlatButton
            icon={<ContentAdd/>}
            onClick={this._handleOpen}
          />
        </TableRowColumn>

        <Dialog
          actions={actions}
          autoScrollBodyContent={true}
          open={this.state.open}
          onRequestClose={this._handleClose}
          modal={false}
          title='Test'
        >
            <Tabs>
              <Tab label="Item One" >
                <div>
                  <h2 >Tab One</h2>
                  <p>
                    This is an example tab.
                  </p>
                </div>
              </Tab>

              <Tab label="Item Two" >
                <div>
                  <h2>Tab Two</h2>
                  <p>
                    This is another example tab.
                  </p>
                </div>
              </Tab>

            </Tabs>
        </Dialog>
      </TableRow>
    )
  }
}

Thank you in advance and will accept/upvote answer.

like image 494
Jo Ko Avatar asked Jan 18 '17 04:01

Jo Ko


People also ask

How do I use material UI in react?

What is Material UI? 1 Getting started. First, we need to set up and install the new react app by using the create-react-app command line tool. 2 Adding Nav bar. Let’s add the Navbar to our Header. ... 3 Material ui svg icons. Material UI provides us with SVG material icons to use in our react app. ... 4 Grid. ... 5 Contact form. ...

How to implement Google Material Design in react app?

Material UI provides us React components that implement google material design. First, we need to set up and install the new react app by using the create-react-app command line tool. Open your terminal and run following commands. Next, we need to change our working directory by using below commands.

What is the best React library for UI?

Material UI is our favorite React UI library and to be honest there isn't even a second UI library for React that we can even recommend. It's extremely difficult to make a good UI library for a variety of reasons.

How to use material UI components instead of HTML tables?

Material UI can be installed using npm package. Material UI recommends roboto fonts for UI. To use Roboto font, include it using Gooogleapi links. Let us recreate the expense list application and use material ui components instead of html tables.


2 Answers

You should probably only have one dialog for the whole table that lives in your MainTable component. This is more efficient because you don't need a dialog per row but only one dialog.

In order for the button in the RenderedTableRow to open the modal and tell it which row is selected you need to pass down a callback function from MainTable to RenderedTableRow that when called, sets the dialog to be opened and stores which row was selected:

export default class MainTable extends Component {
  state = {
    selectedRow: null,
  }
  handleSelectRow(rowIndex) {
    this.setState({
      selectedRow: rowIndex,
    })
  }
  render() {

    return (
      <div>
        <div>
          <Subheader>Table</Subheader>
          <Table
            multiSelectable={true}
          >
            // ...
            <TableBody
              deselectOnClickaway={false}
              stripedRows
              >
              {rows.map((row, index) => (
                <RenderedTableRow
                  row={row}
                  {...this.props}
                  onSelectRow={() => this.handleSelectRow(index)}
                  />
              ))}
            </TableBody>
          </Table>
        </div>
        // Dialog goes here and is only rendered once per table
        // it is only open when there is a row selected
        <Dialog
          open={Boolean(this.state.selectedRow)}
        >
          // you can get the selected row with rows[this.state.selectedRow]
        </Dialog>
      </div>
    )
  }
}
like image 75
PhilippSpo Avatar answered Oct 09 '22 14:10

PhilippSpo


Here is a working example below, it should work straight via copy pasta.

The answer to your question is that you need to be able to differentiate between the different rows, setting it to true will display all dialogs, or possibly just the last. Once you differentiate it, displaying the dialog you want shouldn't be a problem. There are ways to just have one dialog and still have this work, but I'll let you figure it out.

Somethings to note, is that you can definitely clean this code up. Create separate files for creating TableRows TableColumns etc.

I left it at two columns for now, however you should be able to understand the code. Feel free to ask any additional questions.

import React, { Component } from 'react'

import { Dialog, FlatButton, Tabs, Tab,  TableRow, TableRowColumn } from 'material-ui'
import ContentAdd from 'material-ui/svg-icons/content/add';

class MainTable extends Component {
  static fields = [{tab1:"a", tab2:"b"}, {tab1:"c", tab2:"d"}];

  state = {
    open: false,
  }

  handleOpen = (field) => () => {
    this.setState({
      open: field
    })
  }

  handleClose = () => {
    this.setState({
      open: false
    })
  }

  renderRows = (field) => {
    const { open } = this.state;

    const actions = [
      <FlatButton
        label="Cancel"
        primary={true}
        onTouchTap={this.handleClose}
      />,
      <FlatButton
        label="Submit"
        primary={true}
        keyboardFocused={true}
        onTouchTap={this.handleClose}
      />,
    ];

    return (<TableRow key={field.tab1}>
      <TableRowColumn>{field.tab1}</TableRowColumn>
        <TableRowColumn>
        <FlatButton
        icon={<ContentAdd/>}
        onClick={this.handleOpen(field.tab1)}
      />
      </TableRowColumn>
        <Dialog
          title="Dialog With Actions"
          actions={actions}
          modal={false}
          open={open === field.tab1}
          onRequestClose={this.handleClose}
        >
        <Tabs>
          <Tab label={field.tab1} >
            <div>
              <h2>{field.tab1}</h2>
              <p>
                This is one tab.
              </p>
            </div>
          </Tab>

          <Tab label={field.tab2}>
            <div>
              <h2>{field.tab2}</h2>
              <p>
                This is another example tab.
              </p>
            </div>
          </Tab>
        </Tabs>
      </Dialog>
    </TableRow>);
  }

  render() {
    const rows = MainTable.fields.map(this.renderRows);
    return (
      <div>
        {rows}
      </div>
    )
  }
}

export default MainTable;
like image 45
Danny Avatar answered Oct 09 '22 16:10

Danny