I am working on a react app where I am rendering a table and 2 of the column fields instead of containing text contains a dropdown menu and I have different options in those dropdown menu,The dropdown is rendering but on opening the dropdown it gets hidden as if the row has a limited size which is quite unexpected.Here's my code:
const StyledTable = styled(CommonInfiniteTable)`
.ReactVirtualized__Table__Grid {
overflow-y: visible !important;
}
`;
export const StyledDropdownIcon = styled(Icon)`
top: 1px !important;
right: 5px !important;
`;
const rowHeight = 41;
const headerHeight = 30;
class DefaultCodeSetsTable extends React.Component {
constructor(props) {
super(props);
this.codeDataGetter = this.codeDataGetter.bind(this);
this.codeDescriptionDataGetter = this.codeDescriptionDataGetter.bind(this);
}
codeDataGetter = ({
dataKey,
rowData,
rowIndex,
}) => (
<div>
<Form.Select
name='Code'
value={this.props.codeSets.length ? this.props.codeSets[rowIndex][`${this.props.masterName}_code`] : ''}
options={this.props.defaultCodeSetsList[rowIndex].codesOptions}
onChange={this.handleDefaultCodeChange(rowIndex)}
icon={
<StyledDropdownIcon iconName={DownCheveron} iconSize='15' className='dropdown' />
}
/>
</div>
)
codeDescriptionDataGetter = ({
dataKey,
rowData,
rowIndex,
}) => (
<div>
<Form.Select
className='drop'
name='Code Description'
value={this.props.codeSets.length ? this.props.codeSets[rowIndex][`${this.props.masterName}_code_description`] : ''}
options={this.props.defaultCodeSetsList[rowIndex].codeDescOptions}
onChange={this.handleDefaultDescriptionChange(rowIndex)}
icon={
<StyledDropdownIcon iconName={DownCheveron} iconSize='15' className='dropdown' />
}
/>
</div>
)
render() {
const widthOfEachGrid = this.props.width / 16;
const columns = (
[<Column
key={1}
label='Master Name'
dataKey='master_name'
width={widthOfEachGrid * 2}
cellDataGetter={defaultCellDataGetter}
/>,
<Column
className='column'
key={2}
label='Code'
dataKey='code'
width={widthOfEachGrid * 1}
cellRenderer={this.codeDataGetter}
/>,
<Column
className='column'
key={3}
label='Code Description'
dataKey='code_description'
width={widthOfEachGrid * 2}
cellRenderer={this.codeDescriptionDataGetter}
/>,
]
);
return (
<StyledTable
height={this.props.height}
width={this.props.width}
headerHeight={headerHeight}
rowHeight={rowHeight}
rowRenderer={this.rowRenderer}
rowCount={this.props.codeSets.length}
rowGetter={({ index }) => this.props.codeSets[index]}
LoadingRow={this.props.LoadingRow}
overscanRowCount={5}
tabIndex={-1}
className='ui very basic small single line striped table'
columnsList={columns}
/>
);
}
}
In the above table,I have 3 columns 1 being a plain text and other two are dropdowns with options to select from,when I open the dropdown this is the behaviour:
The options gets hidden as there been an overflow,any leads on this would definitely help!
Related
I am working on a react project where I am using react-virtualized to render a table with columns and I am using a cellRenderer to render data in different cells but I want a Input field in one of the cells so I created a custom cellRenderer to return that component but in the table its showing as object.
Here's my code:
codeDataGetter = ({
dataKey,
rowData,
}) => {
let dataToReturn = '';
if (rowData) {
if (typeof rowData.get === 'function') {
dataToReturn = rowData.get(dataKey);
}
dataToReturn = rowData[dataKey];
} else dataToReturn = '';
console.log('codeDataGetter', dataToReturn);
return (
<Input
type='text'
className='form-control'
value={dataToReturn}
placeholder={translateText('Code')}
onChange={() => this.handleCodeChange(event, index)}
style={{ height: '70%' }}
/>
);
}
Table:
<StyledTable
height={this.props.height}
width={this.props.width}
headerHeight={headerHeight}
rowHeight={rowHeight}
rowRenderer={this.rowRenderer}
rowCount={this.props.codeSets.length}
rowGetter={({ index }) => this.props.codeSets[index]}
LoadingRow={this.props.LoadingRow}
overscanRowCount={5}
tabIndex={-1}
className='ui very basic small single line striped table'
columnsList={columns}
/>
Columns:
const columns = (
[ <Column
key={3}
label='Code'
dataKey='code'
width={widthOfEachGrid * 1}
cellDataGetter={this.codeDataGetter}
/>,
<Column
key={4}
label='Code Description'
dataKey='code_description'
width={widthOfEachGrid * 2}
cellDataGetter={this.codeDescriptionDataGetter}
/>,
]
);
Object... is getting shown in place of Input Box.Any help will be appreciated.
//ImagePlayer component
class ImagePlayer extends Component {
constructor(props) {
super(props)
this.state = {
image: [],
selectedImage: '',
}
this.handleImageSelection = this.handleImageSelection.bind(this);
}
handleImageSelection(source){
this.setState({ImageList : source})
}
render() {
return (
<Grid container spacing={3}>
<Grid item xs={8}>
<Paper>
{/* this is the larger div where I want to render the image clicked on the list */}
<ImageList handleImageSelection={this.handleImageSelection}/>
</Paper>
</Grid>
<Grid item xs={4}>
<Paper>
<ImageList />
</Paper>
</Grid>
</Grid>
);
}
}
//ImageList component
onst ImageList = (handleImageSelection) =>{
handleImageSelection=(image)=>{
console.log(image);
}
return(
images.map((image, id) =>
<List>
<ListItem key={id} >
<div>
<ListItemAvatar>
{<img src= {require(`../assets/${image.name}.jpeg`)} alt="thumbnail" onClick={()=>handleImageSelection(require(`../assets/${image.name}.jpeg`))}/>}
</ListItemAvatar>
</div>
<div >)
How to render the image from List component to Class component in React? My list component is list of images and that should appear enlarged in class component when I click on any image on the list.
I first defined the state: this.state ={ imageSelected: ''}
then, setState for the same.
Also passed handleImageSelection as a function in list component, but it says
'handleImageSelection' is not a function
onClick={()=> props.handleImageSelection()} //errr: not a function
If both your list and display component are wrapped by common parent, you may lift necessary state (e.g. chosen image id) as follows:
const { Component } = React,
{ render } = ReactDOM,
rootNode = document.getElementById('root')
const imageList = [
{id:0, name: 'circle', imgSrc: `data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48Y2lyY2xlIGN4PSI1MCIgY3k9IjUwIiByPSI1MCIvPjwvc3ZnPg==`},
{id:1, name: 'triangle', imgSrc: `data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNTAsMCBMMTAwLDEwMCBMMCwxMDAgeiIvPjwvc3ZnPg==`},
{id:2, name: 'square', imgSrc: `data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCwwIGgxMDAgdjEwMCBoLTEwMCB6Ii8+PC9zdmc+`},
]
const List = ({images, onSelect}) => (
<ul>
{
images.map(({imgSrc, name, id}) => (
<li key={id} onClick={() => onSelect(id)}>
<img className="thumbnail" src={imgSrc} alt={name}/>
</li>
))
}
</ul>
)
class Display extends Component {
render (){
const {imgSrc,name} = this.props.image
return (
<img className="fullsize" src={imgSrc} alt={name} />
)
}
}
class App extends Component {
state = {
chosenImg: null
}
images = imageList
onSelect = _id => this.setState({
chosenImg: this.images.find(({id}) => id == _id)
})
render(){
return (
<div>
<List images={this.images} onSelect={this.onSelect} />
{ this.state.chosenImg && <Display image={this.state.chosenImg} />}
</div>
)
}
}
render (
<App />,
rootNode
)
.thumbnail {
max-width: 50px;
cursor: pointer;
}
.fullsize {
width: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>
I have a problem if on page 1 and after (except 2) what I search (type) if there is data it will display the data that I search (type), see the picture below:
the problem is if on page 2, what I search for will appear on another page. even though on page 2 the data is there, :
This is page 2 before searching :
and this is page 1 before searching
if I'm on page 2 there is data that appears abc and dcs. if I search for dcs then dcs appear or if I type d it will appear d and if on other pages there is also data it will display
I use this codesanbox.io url:
https: //codesandbox.io/embed/condescending-pine-d7q3v
and this my code:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import dummyQnA from "./dummyQnA.json";
import "./styles.css";
import { Row, Col, Pagination, Button, Table, Divider } from "antd";
import Search from "antd/lib/input/Search";
import "antd/dist/antd.css";
const columns = [
{
title: "Question",
dataIndex: "questionAndAnswer",
key: "questionAndAnswer"
}
];
class App extends Component {
constructor(props) {
super(props);
this.state = {
search: ""
};
}
getHighlightedText(text, higlight) {
if (!higlight.trim()) {
return <span>{text}</span>;
}
let parts = text.split(new RegExp(`(${higlight})`, "gi"));
return (
<span>
{parts
.filter(part => part)
.map((part, i) => (
<mark
key={i}
style={
part.toLowerCase() === higlight.toLowerCase()
? { backgroundColor: "yellow" }
: {}
}
>
{part}
</mark>
))}
</span>
);
}
renderQnA = (qna, i) => {
return {
key: i,
questionAndAnswer: [
<Col key={i} md={24} style={{ marginTop: 20 }}>
<Row>
<Col md={23}>
<b>
{" "}
{this.getHighlightedText(qna.questionAdmin, this.state.search)}
</b>
<p style={{ color: "#417505" }}>
{" "}
{this.getHighlightedText(qna.answerCustomer, this.state.search)}
</p>
</Col>
</Row>
</Col>
]
};
};
onChange = e => {
this.setState({ search: e.target.value });
};
render() {
const { search } = this.state;
const lowercasedFilter = search.toLowerCase();
const filteredQnA = dummyQnA.filter(item => {
return Object.keys(item).some(key =>
item[key].toLowerCase().includes(lowercasedFilter)
);
});
return (
<div className="product-forum">
<Row className="title-inline">
<Col md={13} style={{ paddingTop: "6px" }}>
<span className="title-inline__title">
Pertanyaan terkait Produk ({dummyQnA.length})
</span>
</Col>
<Col md={3}>
<Button
type="link"
className="title-inline__button-live-chat"
onClick={this.handleLiveChat}
>
LIVE CHAT
</Button>
</Col>
<Col md={8}>
<Search
value={this.state.search}
placeholder="Cari pertanyaan terkait"
onChange={this.onChange}
/>
</Col>
</Row>
<Table
className="table-qna"
showHeader={false}
pagination={{ defaultPageSize: 5 }}
dataSource={filteredQnA.map((QnA, i) => this.renderQnA(QnA, i))}
columns={columns}
/>
<Divider />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
I'm trying to develop a fairly simplistic E-Mail template creator with React JS. I'm using the "react-sortable-hoc" library as a means to handle the ordering of elements on the page.
The goal is to allow users to create "Rows", rearrange rows, and within each row, have multiple "Columns" that can contain components like images, textboxes, etc...
But I keep running into the same issue with Sortable libraries. Form fields cannot maintain their own "state" when being dragged up or down. The State of a Component in React JS seems to be lost when it's in a draggable component. I've experienced similar issues with JQuery UI's Sortable but it required an equally ridiculous solution. Is it common to find that form fields are simply super difficult to rearrange?
As a "proof of concept", I am using a complex JSON object that stores all the information in the Letter.js component and passes it down as Props which are then passed down to each component. But as you can tell, this is becoming cumbersome.
Here is an example of my Letter component that handles the JSON object and sorting of Rows:
import React, {Component} from 'react';
import {render} from 'react-dom';
import {
SortableContainer,
SortableElement,
arrayMove
} from 'react-sortable-hoc';
import Row from './Row';
const SortableItem = SortableElement(({row, rowIndex, onChange, addPart}) => {
return (
<li>
<Row
row={row}
rowIndex={rowIndex}
onChange={onChange}
addPart={addPart} />
</li>
)
});
const SortableList = SortableContainer(({rows, onChange, addPart}) => {
return (
<ul id="sortableList">
{rows.map((row, index) => {
return (
<SortableItem
key={`row-${index}`}
index={index}
row={row}
rowIndex={index}
onChange={onChange}
addPart={addPart}
/> )
})}
</ul>
);
});
class Letter extends Component {
constructor(props) {
super(props);
this.state = {
rows: [],
}
this.onSortEnd = this.onSortEnd.bind(this);
this.onChange = this.onChange.bind(this);
this.addRow = this.addRow.bind(this);
this.addPart = this.addPart.bind(this);
}
addPart(event, index, value, rowIndex, columnIndex) {
console.log(value);
var part = {};
if(value === 'Text') {
part = {
type: 'Text',
value: ''
}
} else if(value === 'Image') {
part = {
type: 'Image',
value: ''
}
} else {
part = {
type: 'Empty',
}
}
const { rows } = this.state;
rows[rowIndex][columnIndex] = part;
this.setState({ rows: rows })
}
onChange(text, rowIndex, columnIndex) {
const { rows } = this.state;
const newRows = [...rows];
newRows[rowIndex][columnIndex].value = text;
this.setState({ rows: newRows });
}
addRow(columnCount) {
var rows = this.state.rows.slice();
var row = [];
for(var i = 0; i < columnCount; i++) {
var part = {
type: 'Empty',
}
row.push(part);
}
rows.push(row);
this.setState({ rows: rows })
}
onSortEnd = ({oldIndex, newIndex}) => {
this.setState({
rows: arrayMove(this.state.rows, oldIndex, newIndex),
});
};
render() {
console.log(JSON.stringify(this.state.rows));
const SideBar = (
<div className="sideBar">
<h3>Add a Row</h3>
<button className="uw-button" onClick={() => this.addRow(1)}>1 - Column</button><br/><br/>
<button className="uw-button" onClick={() => this.addRow(2)}>2 - Column</button><br/><br/>
<button className="uw-button" onClick={() => this.addRow(3)}>3 - Column</button>
<hr />
</div>
);
if(this.state.rows.length <= 0) {
return (
<div className="grid">
<p>This E-Mail is currently empty! Add some components to make a template.</p>
{SideBar}
</div>
)
}
return (
<div className="grid">
<SortableList
rows={this.state.rows}
onChange={this.onChange}
addPart={this.addPart}
lockAxis="y"
useDragHandle={true}
onSortStart={this.onSortStart}
onSortMove={this.onSortMove}
onSortEnd={this.onSortEnd}
shouldCancelStart={this.shouldCancelStart} />
{SideBar}
</div>
);
}
}
export default Letter;
And here is an example of Row:
import React, { Component } from 'react';
import { Text, Image } from './components/';
import { SortableHandle } from 'react-sortable-hoc';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import { Card, CardActions, CardHeader, CardMedia, CardTitle, CardText } from 'material-ui/Card';
import DropDownMenu from 'material-ui/DropDownMenu';
import MenuItem from 'material-ui/MenuItem';
const DragHandle = SortableHandle(() => <span className="dragHandle"></span>);
class Row extends Component {
constructor(props) {
super(props);
}
render() {
if(this.props.row !== undefined && this.props.row.length > 0) {
const row = this.props.row.map((column, columnIndex) => {
if(column.type === 'Empty') {
return (
<MuiThemeProvider key={columnIndex}>
<div className="emptyColumn">
<Card>
<DragHandle />
<CardTitle title="Empty Component"/>
<DropDownMenu value={"Empty"} onChange={(event, index, value) => this.props.addPart(event, index, value, this.props.rowIndex, columnIndex)}>
<MenuItem value={"Empty"} primaryText="Empty" />
<MenuItem value={"Text"} primaryText="Textbox" />
<MenuItem value={"Image"} primaryText="Image" />
</DropDownMenu>
</Card>
</div>
</MuiThemeProvider>
)
} else if(column.type === 'Text') {
return (
<MuiThemeProvider key={columnIndex}>
<div className="textColumn">
<Card>
<DragHandle />
<CardTitle title="Textbox"/>
<DropDownMenu value={"Text"} onChange={(event, index, value) => this.props.addPart(event, index, value, this.props.rowIndex, columnIndex)}>
<MenuItem value={"Empty"} primaryText="Empty" />
<MenuItem value={"Text"} primaryText="Textbox" />
<MenuItem value={"Image"} primaryText="Image" />
</DropDownMenu>
<Text
value={this.props.row[columnIndex].value}
onChange={this.props.onChange}
columnIndex={columnIndex}
rowIndex={this.props.rowIndex} />
</Card>
</div>
</MuiThemeProvider>
)
} else if(column.type === 'Image') {
return (
<MuiThemeProvider key={columnIndex}>
<div className="textColumn">
<Card>
<DragHandle />
<CardTitle title="Image"/>
<DropDownMenu value={"Image"} onChange={(event, index, value) => this.props.addPart(event, index, value, this.props.rowIndex, columnIndex)}>
<MenuItem value={"Empty"} primaryText="Empty" />
<MenuItem value={"Text"} primaryText="Textbox" />
<MenuItem value={"Image"} primaryText="Image" />
</DropDownMenu>
<Image
columnIndex={columnIndex}
rowIndex={this.props.rowIndex} />
</Card>
</div>
</MuiThemeProvider>
)
}
})
return (
<div className="row">
{row}
</div>
)
}
return <p>No components</p>;
}
}
export default Row;
Lastly, this is what Text.js looks like
import React, { Component } from 'react';
import ReactQuill from 'react-quill';
class Text extends Component {
constructor(props) {
super(props);
}
render() {
return (
<ReactQuill value={this.props.value}
onChange={(text) => this.props.onChange(text, this.props.rowIndex, this.props.columnIndex)} />
)
}
}
export default Text;
So, I keep having to pass ridiculous parameters to onChange functions and other functions in order to ensure that the state is maintained while sorting and editing. So, how should I be handling this? I don't want Letter.js (which is basically App.js) to handle all of my data handling. I want each component to handle it's own. I want Text.js to handle the onChange effects of its text. But I just can't see a way around passing everything down as props.
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.
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>
)
}
}
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;
As I mentioned earlier in the comments, you should have only one Dialog element along with the table component. Embedding Dialog in each row will impact the performance and is general a bad practice. Here is the solution for mocked tabs:
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;
This is how it works right now:
Few remarks:
you should split this code into smaller components, I wrote this all in one to make it easy to test it,
remember to use key prop in all the elements of the list (where you iterate over a list) - both rows and tabs (key is missing in your question).