2017-01-18 50 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)。
相關問題