2017-01-18 30 views
8

我有一个Material-UI的<Table>,并且在<TableBody>的每个<TableRow>(它是动态呈现的)中,我想为其中一列提供一个按钮(<FlatButton>)。一旦按钮被点击,它会打开一个<Dialog>,并在其内部想要有一个工作<Tabs>ReactJS + Material-UI:如何在每个TableRow中使用Material-UI的FlatButton和对话框?

那么我怎样才能显示一个特定列的每一行<FlatButton>,当点击该按钮时,显示<Dialog>以及作为内容的内部工作<Tabs>?在外面点击时有<Dialog>关闭吗?

到目前为止,我有以下,但遇到下列问题就来了:在打开了,但它是缓慢的,点击<Dialog>外不打烊吧,<Tabs>是可见的,但它不工作:

主要表:

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

渲染表行:

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

谢谢你在前进,并会接受/给予好评的答案。

+1

会在对话框中显示什么?对于每一行你生成一个新的对话框 - 是否有必要?如你所说,它会很慢。更好的方法是在主表组件中有一个Dialog元素并传递必要的道具。 – szymonm

+0

我想将对话框移到表格外,将回调传递给表格行中的按钮,点击后,打开对话框并将选定的行传递给它 – Mateusz

+0

@szymonm每行的内容不同,但会显示在对话框中使用'',但是当前选项卡不起作用。我之所以为每一行做这件事,是因为每个对话框对每一行都有不同的表示。我该如何解决这个问题? –

回答

2

您应该只对位于MainTable组件中的整个表格有一个对话框。这样更高效,因为每行不需要对话框,只需要一个对话框。

为了在RenderedTableRow按钮打开模态,并告诉它该行被选中,你需要一个回调函数传递下去从MainTableRenderedTableRow调用时,将要打开的对话框并存储行是选择:

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> 
    ) 
    } 
} 
+0

为了有动态多行,我会使用具有每行特定属性的数组填充表,如下所示:' {array.map(row => {return()})};'。如果是这种情况,我将如何区分行被点击并在对话框中显示该特定内容的特定内容,因为每行都会在对话框中显示不同的内容。为什么''工作? –

+0

我扩展了代码示例以包含多行。不知道为什么'Tabs'不起作用。他们看起来很好。我甚至试过你的'Dialog'代码,'Tabs'为我工作。 – PhilippSpo

+0

你介意用codepen或类似的东西来展示它吗?似乎没有工作.. :( –

2

下面是一个工作示例,它应该通过复制面食直接工作。

的回答你的问题是,你需要能够在不同rows进行区分,将其设置为true将显示所有对话框,或者可能只是最后一个。一旦你区分它,显示你想要的dialog应该不成问题。有办法只有一个dialog,仍然有这项工作,但我会让你弄明白。

需要注意的一点是,您绝对可以清理此代码。创建单独的文件创建TableRowsTableColumns

我现在把它留在两列,但你应该能够理解代码。随意问任何其他问题。

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; 
+0

为了有动态多行,我会填充表中的数组每行的具体属性如下: {array.map(row => {return()})};。如果是这种情况,我将如何区分哪个行被点击并显示因为每一行都会在对话框中显示不同的内容,所以为什么不能工作?如果你能显示实际工作的内容,那肯定会有所帮助。 –

+0

I'现在工作,但我会在今晚晚些时候更新答案,以显示工作'选项卡'。我把这部分留下了。 –

+0

顺便说一句,你是否尝试过上面的代码?点击不同的'rows'显示不同的类型数据的pes。我没有看过的唯一东西是'tabs',我不确定他们做了什么,但我可以稍后检查文档。 –

1

正如我在前面的评论中提到,你应该与表组件沿只有一个Dialog元素。在每一行中嵌入Dialog将会影响性能,并且通常是不好的做法。这里是嘲笑标签解决方案:

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

class MainTable extends Component { 
    // mocked data to show you the example: 
    static fields = [{ 
    id: 1, 
    name: 'John', 
    tabs: [{ 
     header: 'Tab 1 John', 
     content: 'Content of tab 1 for John' 
    }, { 
     header: 'Tab 2 John', 
     content: 'Content of tab 2 for John' 
    }] 
    }, { 
    id: 2, 
    name: 'George', 
    tabs: [{ 
     header: 'Tab 1 George', 
     content: 'Content of tab 1 for George' 
    }, { 
     header: 'Tab 2 George', 
     content: 'Content of tab 2 for George' 
    }] 
    }]; 

    state = { 
    activeRowId: null // we will store the `id` of the active row (opened dialog) 
    }; 

    handleOpen = (rowId) =>() => { 
    this.setState({ 
     activeRowId: rowId // set `id` taken from the row 
    }); 
    }; 

    handleClose =() => { 
    this.setState({ 
     activeRowId: null // reset active `id` 
    }); 
    }; 

    renderRows = (field) => (
    <TableRow key={`row-${field.id}`}> 
     <TableRowColumn>{field.name}</TableRowColumn> 
     <TableRowColumn> 
     <FlatButton 
      icon={<ContentAdd />} 
      onClick={this.handleOpen(field.id)} 
     /> 
     </TableRowColumn> 
    </TableRow> 
); 

    render() { 
    const rows = MainTable.fields.map(this.renderRows); 
    const { activeRowId } = this.state; 
    const actions = [ 
     <FlatButton 
     label="Cancel" 
     primary 
     onTouchTap={this.handleClose} 
     />, 
     <FlatButton 
     label="Submit" 
     primary 
     keyboardFocused 
     onTouchTap={this.handleClose} 
     />, 
    ]; 
    const activeRow = find(MainTable.fields, { id: activeRowId }); // find the data for this active row `id` 
    return (
     <div> 
     {rows} 
     {activeRow ? (
      <Dialog 
      title="Dialog title" 
      actions={actions} 
      modal={false} 
      open 
      onRequestClose={this.handleClose} 
      > 
      <Tabs> 
       {activeRow.tabs.map((tab, index) => (
       <Tab label={tab.header} key={`tab-${index}`}> 
        <div> 
        <h2>{tab.header}</h2> 
        <p>{tab.content}</p> 
        </div> 
       </Tab> 
      ))} 
      </Tabs> 
      </Dialog> 
     ) : null} 
     </div> 
    ); 
    } 
} 

export default MainTable; 

这是它是如何工作现在:

enter image description here

几句话:

  • 你应该拆分此代码到更小的组件中,我将它全部写入其中以便于测试,
  • 记得在列表的所有元素中使用key prop(在列表中迭代的地方) - 行和选项卡(您的问题中缺少key)。
相关问题