I'm using AntD components to build a table and one of my columns consists of the InputNumber component. I would like the InputNumber component to have a default value that is contained in a prop that is passed to the table component. However I'm unsure how to access the props from the parent, or more specifically pass them to the InputNumber component as the render prop for the columns exists outside of the table component. Here is an example of the code
import React, { Component } from 'react';
import { Table, Divider, InputNumber } from 'antd';
const pageSize = 30; // Page size to show pagination
const reqColumns = [
{
title: 'Filled',
dataIndex: 'slotFilled',
editable: false,
},
{
title: 'Required',
dataIndex: 'slotMinimum',
render: () => (
<InputNumber min={0}/>
),
},
];
export default class RequirementsTable extends Component {
render() {
return (
<div>
<Divider type="horizontal" orientation="left">
Requirements
</Divider>
<Table
rowKey="senateShortname"
bordered
dataSource={this.props.data}
columns={reqColumns}
pagination={1 > pageSize && { pageSize }}
size="small"
/>
</div>
);
}
}
I've attempted to set the defaultValue = {this.props.data} but of course that points to the props of the InputNumber.
The AntD table already was attempting to pass the value to the cell. The solution was quite simple.
{
title: 'Required',
dataIndex: 'slotMinimum',
render: (value) => (
<InputNumber min={0} defaultValue={value}/>
),
},
Related
How to redirect to another page with passing selected row data as a prop?
I'm using material-table and I want to pass the selected rows data to another page after clicking the "Export" button, so I can use that data to create some kind of report in another page.
I think I should use history.push() method but it's not working in the onClick method. Can someone please give me any hint?
import React from 'react'
import MaterialTable from 'material-table';
class LeadTable extends React.Component{
constructor(props) {
super(props);
this.state = {
leads : [],
};
}
componentDidMount() {
fetch('http://localhost:5000/api/Leads')
.then(res => res.json())
.then((data) => {
// console.log('Data: ', data[0])
this.setState({
leads: data[0]
})
})
.catch(console.log);
}
redirectToReport = () => {
const { history } = this.props;
history.push('report');
}
render(){
return (
<div style={{ maxWidth: '100%' , align: 'center'}}>
<MaterialTable
title="Reporting"
columns={[
...
]}
data = {this.state.leads}
options={{
selection: true,
filtering: true,
sorting: true
}}
actions = {[{
position: "toolbarOnSelect",
tooltip: 'Export the selected activities!',
icon: 'Export',
onClick: (event, rowData) => {
console.log("Row Data: " , rowData)
// rowData has all the selected row and I want to redirect to another page with passing those data.
}
}]}
/>
</div>
)}
}
export default LeadTable
This answer mainly addresses OP's code base which is using class components. If you are using function components you can use react-router hooks such as useHistory
Use withRouter HOC to enable LeadTable component access to history so you can push
const LeadTableWithRouter = withRouter(LeadTable);
Pass object to push function to pass row data
redirectToReport = (rowData) => {
const { history } = this.props;
history.push({
pathname: "/report", // re-route to this path
state: { name: rowData.name, surname: rowData.surname } // your row data
});
};
In your other component, use this.props.location.state.<data_name> to access the row data you've passed
class AnotherPage extends React.Component {
render() {
return (
<>
<p>{this.props.location.state.name}</p>
<p>{this.props.location.state.surname}</p>
<Link to="/">go back</Link>
</>
);
}
}
I have one Component which shows a list of data in a dropdown and there is an option to search these data which works as a filter. Here is my code:
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import Popover from '../../Popover';
import Input from '../../Input';
import Icon from '../../Icon';
import IconButton from '../../IconButton';
const DropDownFilter = props => {
const { label, options, onChange, isSearchEnabled } = props;
const [activeOption, setActiveOption] = useState({});
const [filter, setfilter] = useState('');
const searchFilter = event => {
setfilter(event.target.value);
};
const removeFilter = () => {
setfilter('');
};
const lowercasedFilter = filter.toLowerCase();
const filteredData = options.filter(item => {
return Object.keys(item).some(
key => typeof item[key] === 'string' && item[key].toLowerCase().includes(lowercasedFilter)
);
});
const labelText = activeOption.label ? activeOption.label : label;
const handleSelectedOption = option => {
setActiveOption(option);
onChange(option);
};
return (
<div className="filter">
<Popover linkText={labelText} size="small" direction="bottom-left">
{isSearchEnabled && (
<div className="filter__search">
<Input
value={filter}
onChange={searchFilter}
preIcon={
<div role="presentation">
<Icon name="search" />
</div>
}
placeholder="Search"
postIcon={
filter.length > 0 && (
<IconButton
icon={<Icon name="close" />}
size="tiny"
onClick={removeFilter}
standalone={true}
isIconOnly={true}
/>
)
}
/>
</div>
)}
<ul className="filter__options filter__options--scrollbar">
{filteredData.map(option => (
<li
key={option.value}
role="presentation"
className={classNames('filter__options-option', {
'filter__options-option--active': option.value === activeOption.value,
})}
onClick={() => handleSelectedOption(option)}
>
{option.label}
</li>
))}
</ul>
</Popover>
</div>
);
};
DropDownFilter.defaultProps = {
label: 'Filter Menu',
options: [],
isSearchEnabled: true,
};
DropDownFilter.propTypes = {
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
options: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
})
),
onChange: PropTypes.func.isRequired,
isSearchEnabled: PropTypes.bool,
};
export default DropDownFilter;
Here is a gif of it: https://recordit.co/HtalUtuPsj
Now during searching I want to send the value of the search param to another component, the value will be used to search from a DB or any other external data source which is being handled in that new component. Such as, if I am searching for Ratings, this component should search for it in the existing options list it has in its own component, as well as the same time it will search for Ratings in any other external data source or DB. This external network call, search or any other functionality will be processed in the other component. So this component will only send the search param; for example Ratings to the other component in real time.
I can think of an idea like I will get the searchParam in a state and pass the setState value to a new props which will be called through an onSearchParamChange function, this new function will pass the data through a callback and the other component will get the data through calling that props of this component. I am not sure if this is the correct way and also I am not able to implement this thought in the code either. Is there any better way to do it? if so what would be that coding implementation?
If you need to pass to a parent component you should be able to use for example the onChange prop which is passed to your component, like you are doing in the handleSelectedOption function. That function is in fact passing the chosen option to the parent component. If you want to pass to the parent component when the user is typing, then you should call the onChange function also in searchFilter:
const searchFilter = event => {
const option = event.target.value);
setfilter(option);
onChange(option);
};
If you want to pass it to a child component, the you can just pass it as prop:
<ChildComponent filter={ filter } />
In ReactTable, I want to render my own Checkbox component using Field from redux-form through the Cell renderer of react-table.
But I'm getting a getting this error:
Uncaught Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
I don't know why.
Check my code:
import { Field } from 'redux-form';
import Checkbox from 'Components/Checkbox';
const setTableColumns = () => {
return [
{
Header: 'Entities',
accessor: 'target',
Cell: rowData => (
<span className="RoleTarget" key={rowData.original.target}>
<AllCheckerCheckbox
name={`CheckAll-${rowData.original.userId}`}
id={rowData.original.userId}
/>
<span className="RoleTarget__name">{rowData.original.target}</span>
</span>
),
width: 190,
},
{
Header: 'Add',
accessor: 'add',
Cell: rowData => {
// Problematic code below.
return <Field name="ADD" component={Checkbox} type="checkbox" />;
},
minWidth: 60,
},
]
}
export default setTableColumns
Also outside the table, Field component works fine! It's only inside the table that causes trouble. Can someone tell me what going on between react-table and redux-form, and how to make them work together?
Many Thanks
what links a Field to the redux-form store is the 'name' prop. In the case of an Array of Fields it should be something like name={${member}.ADD}.
So you need to render your table inside a FieldArray:
<FieldArray
name=your-array-of-fields-in-redux-form
component={renderTable}
columns={renderTable}>
Redux-form will pass to renderTable the fields prop, which you can use to hidrate the data props you pass to react-table (with the field names and respective values).
const renderCellField = ({ input, label, type, meta: { touched, error } }, ...custom) => (
<div>
<input {...input} type={type} placeholder={label} />
{touched && error && <span>{error}</span>}
</div>
)
const renderTable = ({fields, columns}) => {
// console.log(equipments)
return(
<Table columns={columns} data={fields.map((name, index, fields)=>({...fields.get(index), id:name})
)}/>
)}
class MyTable extends React.Component{
render() {
let columns = [
{ (...)
Header: 'Select',
accessor: 'selected',
Cell: (row: any) => {
return(
<Field
name={`${row.row.original.id}.selected`}
component={renderCellField}
type="checkbox"
placeholder="Enter equipment name"
/>
);
}
},
]
return(
<FieldArray name="equipments" component={renderTable} columns={columns}/>
)
}
}
export default reduxForm({
form: 'creatInstallForm',
fields: ['equipments'],
})(MyTable)
here is my code scenario
const components = {
body: {
row: EditableFormRow,
cell: EditableCell,
},
};
I am using components in another component like below.
<CustomTable
columns={updatedcolumns}
dataSource={dataSource}
components={components}
rowClassName={() => 'editable-row'}
bordered
size="middle"
pagination={false}
// scroll={{ x: '130%', y: 240 }}
/>
I want to pass a prop to EditableCell which is a component defined in another file.
when I do following it gives me error
const components = {
body: {
row: EditableFormRow,
cell: <EditableCell type="text"/>,
},
};
I am not sure how do I pass props. Please help.
You need to wrap the component in a function:
cell: () => <EditableCell type="text"/>,
cell: (props) => <EditableCell type="text" {...props}/>
With react-semantic-ui, I made a searchable, paginationable Table React Component
working example: https://codesandbox.io/s/23q6vlywy
Usage
<PaginationTable
items={[
{
id: 1,
name: "test-item-1 ???"
},
{
id: 2,
name: "test-item-2"
},
{
id: 3,
name: "test-item-3"
}
]}
columnOption={[
{
header: "idHeader",
cellValue: "id",
onItemClick: item => {
alert(item.id);
},
sortingField: "id"
},
{
header: "Name~",
cellValue: item =>
`*custom text cannot be searched* property can item.name => ${
item.name
} `,
onItemClick: item => {
alert(item.name);
},
sortingField: "name"
}
]}
initSortingField={"id"}
initSortingOrderAsc={false}
pagination
itemsPerPage={2}
searchKeyProperties={["id", "name"]}
/>
But this component currently can only have a certain order
1.SearchBar on top
2.Table on middle
3.PaginationBar on bottom
And actually, I didn't write 3 child components in the Component, SearchBar, Table, PaginationBar
So it's hard for me to rewrite it to render props way to change the order such as below
<PaginationTable {...props}>
{({ SearchBar, Table, PaginationBar })=>
<div>
<SearchBar />
<Table />
<SearchBar />
</PaginationTable>
</div>
</PaginationTable>
Because when I tried to change to render props, I first have to write 3 components independently, which means I have to change all variables under this( this.state, this.props, this.xxxFunction ) to something else.
For example:
In , I can use
<Input onChange={()=>{
this.setState({ searchBarText: e.target.value });
}}/>
But If I change it to 3 components, I have to rewrite it to something like
const SearchBar = ({onTextChange}) => <Input onChange=
{onTextChange}/>
<SearchBar onTextChange={()=>{
this.setState({
searchBarText: e.target.value
});
}} />
Is there any way I can adjust child components order elegantly or is there any way I can write render props easier?
Updated # 2018.10.27 17:36 +08:00
I modified <PaginationTable>'s render function as below but it will be lost mouse cursor focus when typing on <SearchInput>
render(){
const SearchBar = ()= (<Input onChange={()=>{...} />);
const TableElement = ()=>(<Table {...} > ... </Table>);
const PaginationBar = ()=>(<Menu {...} > ... </Menu>);
enter code here
return(
<React.Fragment>
{this.props.children({ SearchBar,TableElement, PaginationBar })}
</React.Fragment>)};
Then I found out, in this way, DOM will update every time when my state updated because every render will make a new component reference by const SearchBar = ()=>(...).
Thanks to #Ralph Najm
If I declare child component as below, DOM will not update every time.
render(){
const SearchBar = (<input onChange={...} />);
const TableElement = (<Table .../>);
const PaginationBar = (<Menu .../>);
//... same as above
}
In this way, I can change my component to render props in order to arrange the order very easily.
Thanks in advance.
In the PaginationTable component change your render function and before the return statement, assign the elements to variables (SearchBar, Table, PaginationBar, etc...) then just reference those variables in the render function.
I modified your example here https://codesandbox.io/s/vy4799zp45