Material-table editable: Making all rows editable at once - javascript

I have a table with multiple rows and I want to be able to make them all editable at once. Using the editable tag I've been able to go into edit mode and make one row at a time editable, but if I tab from one row to the next it doesn't save changes. I need to stop and click on a button to save changes. I want to be able to make changes throughout the table before hitting a save button. Is there a way to do this with material-table?
class Editable extends React.Component {
constructor(props) {
super(props);
this.state = {
columns: [
{ title: 'Name', field: 'name' },
{ title: 'Surname', field: 'surname', initialEditValue: 'initial edit value' },
{ title: 'Birth Year', field: 'birthYear', type: 'numeric' },
{
title: 'Birth Place',
field: 'birthCity',
lookup: { 34: 'İstanbul', 63: 'Şanlıurfa' },
},
],
data: [
{ name: 'Mehmet', surname: 'Baran', birthYear: 1987, birthCity: 63 },
{ name: 'Zerya Betül', surname: 'Baran', birthYear: 2017, birthCity: 34 },
]
}
}
render() {
return (
<MaterialTable
title="Editable Preview"
columns={this.state.columns}
data={this.state.data}
editable={{
onRowUpdate: (newData, oldData) =>
new Promise((resolve, reject) => {
setTimeout(() => {
{
const data = this.state.data;
const index = data.indexOf(oldData);
data[index] = newData;
this.setState({ data }, () => resolve());
}
resolve()
}, 1000)
}),
}}
/>
)
}
}

You always have an option to override EditRow component and for example add an ability to save the row when you tab out of it. I'm afraid there's no other way for incorporating such functionality at the moment.

Related

Can not hide add-button like isEditHiden/isDeleteHiden in material table conditionally

In material-table there is option for hiding edit and delete button conditionally like
<MaterialTable
/// other props
editable={
10 > 5 && {
isEditHidden: () => !10 > 5, // This is condition
isDeleteHidden: () => !10 > 5, // This is condition
onRowAdd: newData =>
}),
onRowUpdate: (newData, oldData) =>
}),
onRowDelete: oldData =>
})
}
}
/>
if isEditHidden or isDeleteHidden is true those button hide. I want to hide add button (beside search icon) also. But i couldn't find any option. Is there any option?
You need to remove editable props and actions props for custom actions if needed and then can use hidden/disabled property to hide/disable action button.
import React from "react";
import MaterialTable from "material-table";
export default function DisableFieldEditable() {
const { useState } = React;
const [columns, setColumns] = useState([
{ title: "Name", field: "name", editable: "onUpdate" },
{ title: "Surname", field: "surname", editable: "never" },
{ title: "Birth Year", field: "birthYear", type: "numeric" },
{
title: "Birth Place",
field: "birthCity",
lookup: { 34: "İstanbul", 63: "Şanlıurfa" }
}
]);
const [data, setData] = useState([
{ name: "Mehmet", surname: "Baran", birthYear: 1987, birthCity: 63 },
{ name: "Zerya Betül", surname: "Baran", birthYear: 2017, birthCity: 34 }
]);
return (
<MaterialTable
title="Disable Field Editable Preview"
columns={columns}
data={data}
actions={[
{
icon: "add",
tooltip: "Add User",
hidden: 10 < 5,
isFreeAction: true,
onClick: (event, rowData) => {
// Perform add operation
}
},
{
icon: 'edit',
tooltip: 'Edit User',
hidden: true,
onClick: (event, rowData) => {
// Perform edit operation
}
},
{
icon: 'delete',
tooltip: 'Delete User',
disabled: true,
onClick: (event, rowData) => {
// Perform delete operation
}
}
]}
/>
);
}

React.js: Add action icons (edit, delete) in table using material-ui

I have an existing table wherein I used a library called react-bootstrap-table-next
It serves its purpose of showing data in a table in which the values are from a JSON response
However, I want to add an Action column containing edit and delete
I want to achieve this using material-ui icons
Any advice as to how should I start? Should I fully convert my table first into material-ui to achieve this?
OR I can just edit profiles state array and map it into a new array containing icons?
ProfileMaintenance.js
const [profiles, setProfiles] = useState([]); // populate table with saved profiles
const retrieveProfiles = useCallback(() => {
ProfileMaintenanceService.retrieveProfiles()
.then((response) => {
console.log(
"ProfileMaintenance - retrieveProfiles response.data >>> ",
response.data
);
setProfiles(response.data);
})
.catch((error) => {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers); // send to logger
if (
error.response.data.error !== undefined &&
error.response.data.error != ""
) {
store.addNotification({
...notification,
type: "danger",
message: error.response.data.error,
dismiss: {
duration: 5000,
},
});
} else {
store.addNotification({
...notification,
type: "danger",
message:
"Server responded with a status code that falls out of the range of 2xx",
dismiss: {
duration: 5000,
},
});
}
} else if (error.request) {
// if API is down
console.log(error.request); // send to logger
store.addNotification({
...notification,
type: "danger",
message: "Request was made but no response was received",
dismiss: {
duration: 5000,
},
});
}
});
});
const columnsProfile = [
// {
// headerStyle: {
// backgroundColor: '#b3b3b3'
// },
// dataField: 'id', // for dev only
// text: 'ID',
// sort: true
// },
{
headerStyle: {
backgroundColor: "#b3b3b3",
},
dataField: "profileName",
text: "Name",
sort: true,
filter: textFilter(),
},
{
headerStyle: {
backgroundColor: "#b3b3b3",
},
dataField: "createdBy",
text: "Creator",
sort: true,
},
{
headerStyle: {
backgroundColor: "#b3b3b3",
},
dataField: "creationDate",
text: "Creation Date",
sort: true,
// filter: dateFilter()
},
{
headerStyle: {
backgroundColor: "#b3b3b3",
},
dataField: "lastModifier",
text: "Last Modifier",
sort: true,
},
{
headerStyle: {
backgroundColor: "#b3b3b3",
},
dataField: "lastModification",
text: "Last Modification",
sort: true,
},
{
headerStyle: {
backgroundColor: "#b3b3b3",
},
dataField: "action",
text: "Action",
},
];
const options = {
paginationSize: 4,
pageStartIndex: 1,
alwaysShowAllBtns: true,
hideSizePerPage: true,
firstPageText: "First",
prePageText: "Back",
nextPageText: "Next",
lastPageText: "Last",
nextPageTitle: "First page",
prePageTitle: "Pre page",
firstPageTitle: "Next page",
lastPageTitle: "Last page",
showTotal: true,
paginationTotalRenderer: customTotal,
sizePerPageList: [
{
text: "5",
value: 5,
},
{
text: "10",
value: 10,
},
{
text: "All",
value: profiles.length,
},
],
};
return (
<BootstrapTable
keyField="id"
hover
data={profiles}
columns={columnsProfile}
defaultSorted={defaultSorted}
filter={filterFactory()}
selectRow={selectRowClient}
noDataIndication="No record(s) found."
pagination={paginationFactory(options)}
/>
)
As you want material icon, I suggest to use material ui table. Please below example to edit or delete row from material ui table.
import React from 'react';
import MaterialTable from 'material-table';
export default function MaterialTableDemo() {
const [state, setState] = React.useState({
columns: [
{ title: 'Name', field: 'name' },
{ title: 'Surname', field: 'surname' },
{ title: 'Birth Year', field: 'birthYear', type: 'numeric' },
{
title: 'Birth Place',
field: 'birthCity',
lookup: { 34: 'İstanbul', 63: 'Şanlıurfa' },
},
],
data: [
{ name: 'Mehmet', surname: 'Baran', birthYear: 1987, birthCity: 63 },
{
name: 'Zerya Betül',
surname: 'Baran',
birthYear: 2017,
birthCity: 34,
},
],
});
return (
<MaterialTable
title="Editable Example"
columns={state.columns}
data={state.data}
editable={{
onRowAdd: (newData) =>
new Promise((resolve) => {
setTimeout(() => {
resolve();
setState((prevState) => {
const data = [...prevState.data];
data.push(newData);
return { ...prevState, data };
});
}, 600);
}),
onRowUpdate: (newData, oldData) =>
new Promise((resolve) => {
setTimeout(() => {
resolve();
if (oldData) {
setState((prevState) => {
const data = [...prevState.data];
data[data.indexOf(oldData)] = newData;
return { ...prevState, data };
});
}
}, 600);
}),
onRowDelete: (oldData) =>
new Promise((resolve) => {
setTimeout(() => {
resolve();
setState((prevState) => {
const data = [...prevState.data];
data.splice(data.indexOf(oldData), 1);
return { ...prevState, data };
});
}, 600);
}),
}}
/>
);
}

How to search an antd table onChange without closing input box with confirm

AntD has a couple of examples for how to search a table with their event handlers, but they use buttons for confirm and reset which are too clunky in my context. I need to be able to search onchange, so that when they remove the filter, it removes the search. I have changed the sample to remove the buttons, and added the handleSearch handler to the onChange listener.
however.
There is this stupid confirm function that is not defined anywhere, and it is closing the search dialogue every keystroke. If I comment it out, it never actually filters the table. If I leave it in, I can only search one letter at a time.
How do I modify my code so that it filters the column on change, but leaves the search input open for further input?
Data:
const data = [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
},
{
key: '2',
name: 'Joe Black',
age: 42,
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Jim Green',
age: 32,
address: 'Sidney No. 1 Lake Park',
},
{
key: '4',
name: 'Jim Red',
age: 32,
address: 'London No. 2 Lake Park',
},
];
Handlers:
constructor(props) {
super(props);
this.state = {
searchText: '',
searchedColumn: '',
};
}
handleSearch = (selectedKeys, confirm, dataIndex) => {
**confirm();//This function is not defined in code anywhere where I can edit.**
this.setState({
searchText: selectedKeys[0],
searchedColumn: dataIndex,
});
};
getColumnSearchProps = dataIndex => ({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm }) => (
<div style={{ padding: 8 }}>
<Input
ref={node => {
this.searchInput = node;
}}
placeholder={`Search ${dataIndex}`}
value={selectedKeys[0]}
onChange={e => {
setSelectedKeys(e.target.value ? [e.target.value] : []);
this.handleSearch(selectedKeys, confirm, dataIndex);
}
}
style={{ width: 188, marginBottom: 8, display: 'block' }}
/>
</div>
),
filterIcon: filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />,
onFilter: (value, record) =>
record[dataIndex].toString().toLowerCase().includes(value.toLowerCase()),
onFilterDropdownVisibleChange: visible => {
if (visible) {
setTimeout(() => this.searchInput.select());
}
},
render: text =>
this.state.searchedColumn === dataIndex ? (
<Highlighter
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
searchWords={[this.state.searchText]}
autoEscape
textToHighlight={text.toString()}
/>
) : (
text
),
});
Render:
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
width: '30%',
...this.getColumnSearchProps('name'),
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
width: '20%',
...this.getColumnSearchProps('age'),
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
...this.getColumnSearchProps('address'),
},
];
return (
<Table columns={columns} dataSource={data} />
);
EDIT: Screenshot showing behavior without the confirm method. Sidney should disappear.
That is really simple.
Just do below change:
confirm()
↓
confirm({ closeDropdown: false })
By doing so, you will be able to overwrite the filterDropdown Interface props in antd/lib/table lib, in which controls the behavior of this function.
there is no problem
remove confirm(); from handleSearch function and then search working without closing search dropdown.
Edit:
to achieve this, you should handle data filtering yourself. create state variable filteredData and isFiltered and filter data manually.

How to show the data I got from API to react-material datatable

I'm new when using materialUI table in react.js, I want to try using react-material table but I got lost as how can I show my data in the table, Let say I have 28 data and in fact it already show the right number in the pagination but the data itself doesn't show anything. this is the documentation link for react-material table Check this.
I already read several topic about this but all of them using tableRow, tableHead, and etc.
this is my component code:
import React, { Component } from 'react';
import MaterialTable from 'material-table';
import { history } from '../../../../Helpers/history';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import { orderActions } from '../../../../Actions/orderActions';
import { withStyles } from '#material-ui/core/styles';
// Component
import './tabledata.css';
const styles = theme => ({
'#global': {
body: {
backgroundColor: theme.palette.common.white,
},
},
});
class Tabledata extends Component {
constructor(props) {
super(props);
// const { orders } = this.props;
this.state = {
columns: [
{ title: 'Nama Pemesanan', field: 'name' },
{ title: 'Status', field: 'status' },
{ title: 'Estimasi Pengerjaan (Hari)', field: 'estimate', type: 'numeric' },
{ title: 'Jumlah Pesanan (pcs)', field: 'unit', type: 'numeric' },
{ title: 'Harga (Rp)', field: 'price', type: 'numeric' },
],
data: [
{
id: 2,
name: 'lala',
status: 'Penyablonan',
estimate: 8,
unit: 36,
price: '36.000.000',
},
],
}
}
componentDidMount() {
if(localStorage.getItem('auth')) {
const { dispatch } = this.props;
dispatch(orderActions.getAllOrder());
// history.push('/dashboard');
}
}
componentWillReceiveProps(newProps){
this.setState({ loading: newProps.loading }); // remove the loading progress when logged in or fail to log in
}
handleChange = prop => event => {
this.setState({ [prop]: event.target.value });
};
change(data){
console.log("Check ID : ", data);
}
render(){
const { orders } = this.props;
console.log("test console : ", orders)
return (
<div className="tabledata-order">
<div className="row item-section">
<div className="col">
<div className="card">
<div className="card-body">
<MaterialTable
title="Daftar Pesanan"
columns={this.state.columns}
key={orders._id}
data={orders}
/>
</div>
</div>
</div>
</div>
</div>
);
}
}
Tabledata.propTypes = {
classes: PropTypes.object.isRequired
};
const mapStateToProps = (state) => {
const { orders } = state.orderPage;
return {
orders
};
}
const connectedTableDataPage = withRouter(connect(mapStateToProps, '', '', {
pure: false
}) (withStyles(styles)(Tabledata)));
export { connectedTableDataPage as Tabledata };
As you can see, this material table have a component like this
<MaterialTable
title="Daftar Pesanan"
columns={this.state.columns}
key={orders._id}
data={orders}
/>
As you can see, in the bottom of the image you can see 1-5 of 28 and in my console there is exactly 28 data but the table itself doesn't show any data
can someone help me? how can I show the data in orders and this is the example of the image json that I have:
Finally I can fix this problem, this answer for you who have facing the same problem with react-material table if your data doesn't show but it show in console.log. you must check the field in column
this.state = {
columns: [
{ title: 'Nama Pemesanan', field: 'name' },
{ title: 'Status', field: 'status' },
{ title: 'Estimasi Pengerjaan (Hari)', field: 'estimate', type: 'numeric' },
{ title: 'Jumlah Pesanan (pcs)', field: 'unit', type: 'numeric' },
{ title: 'Harga (Rp)', field: 'price', type: 'numeric' },
],
data: [
{
id: 2,
name: 'lala',
status: 'Penyablonan',
estimate: 8,
unit: 36,
price: '36.000.000',
},
],
}
let say, json that I got have city, color, and weight then you must state the column field as such:
this.state = {
columns: [
{ title: 'detail Address', field: 'city' },
{ title: 'color', field: 'color' },
{ title: 'weight', field: 'weight' },
],
}
and for the MaterialTable you can just put all the variable you have like this
<MaterialTable
title="Daftar Pesanan"
columns={this.state.columns}
key={orders._id}
data={orders}
/>
and you can get the data like I show you below
I hope this answer can help you who have a hard time with react-material table

Is it possible to make fields required on material-table

I am working on a project, where I basically do crud using material-table interface. I am wondering is there a way if I can make fields required if I want too?
I tried researching but not much results. Please see the code below which is straight forward from https://material-ui.com/components/tables/ last example. Of course I have modified on my codebase for my personal use and everything works fine, but I am not sure how is it possible to make fields required if I want too? If yes, how would I do it? Would I pass something as a prop option on MaterialTable ?
Thank you for any suggestions.
import React from 'react';
import MaterialTable from 'material-table';
export default function MaterialTableDemo() {
const [state, setState] = React.useState({
columns: [
{ title: 'Name', field: 'name' },
{ title: 'Surname', field: 'surname' },
{ title: 'Birth Year', field: 'birthYear', type: 'numeric' },
{
title: 'Birth Place',
field: 'birthCity',
lookup: { 34: 'İstanbul', 63: 'Şanlıurfa' },
},
],
data: [
{ name: 'Mehmet', surname: 'Baran', birthYear: 1987, birthCity: 63 },
{
name: 'Zerya Betül',
surname: 'Baran',
birthYear: 2017,
birthCity: 34,
},
],
});
return (
<MaterialTable
title="Editable Example"
columns={state.columns}
data={state.data}
editable={{
onRowAdd: newData =>
new Promise(resolve => {
setTimeout(() => {
resolve();
const data = [...state.data];
data.push(newData);
setState({ ...state, data });
}, 600);
}),
onRowUpdate: (newData, oldData) =>
new Promise(resolve => {
setTimeout(() => {
resolve();
const data = [...state.data];
data[data.indexOf(oldData)] = newData;
setState({ ...state, data });
}, 600);
}),
onRowDelete: oldData =>
new Promise(resolve => {
setTimeout(() => {
resolve();
const data = [...state.data];
data.splice(data.indexOf(oldData), 1);
setState({ ...state, data });
}, 600);
}),
}}
/>
);
}
Material-table has native support for validation which can trivially be used to make a field required. All you have to do is specify the validation field in the columns specification as per docs here: https://material-table.com/#/docs/features/validation.
Here's what that would look like for your code, say if you wanted to make the "Surname" required:
...
const [state, setState] = React.useState({
columns: [
{ title: 'Name', field: 'name' },
{
title: 'Surname',
field: 'surname',
validate: rowData => Boolean(rowData.surname),
},
{ title: 'Birth Year', field: 'birthYear', type: 'numeric' },
{
title: 'Birth Place',
field: 'birthCity',
lookup: { 34: 'İstanbul', 63: 'Şanlıurfa' },
},
],
data: [
{ name: 'Mehmet', surname: 'Baran', birthYear: 1987, birthCity: 63 },
{
name: 'Zerya Betül',
surname: 'Baran',
birthYear: 2017,
birthCity: 34,
},
],
});
...
p.s. there's no need to put your columns data in the state here unless it's going to change, which seems unlikely in this case.
#HereticMonkey's comment essentially solves my question.
Making fields required is done through editable components as example shown by Heretic Monkey ^^.
Thank you
You need to use editComponent,TextField and validation handling on onRowAdd and onRowUpdate.
See below sample revise code.
import React from "react";
import MaterialTable from "material-table";
import TextField from "#material-ui/core/TextField";
export default function App() {
const [nameError, setNameError] = React.useState({
error: false,
label: "",
helperText: "",
validateInput: false,
});
const columnsHeader = [
{
title: "Name",
field: "name",
editComponent: (props) => (
<TextField
type="text"
error={
!props.value &&
nameError.validateInput &&
props.rowData.submitted
? nameError.error
: false
}
helperText={
!props.value &&
nameError.validateInput &&
props.rowData.submitted
? nameError.helperText
: ""
}
value={props.value ? props.value : ""}
onChange={(e) => {
if (nameError.validateInput) {
setNameError({
...nameError,
validateInput: false,
});
}
props.onChange(e.target.value);
}}
/>
),
},
{ title: "Surname", field: "surname" },
{ title: "Birth Year", field: "birthYear", type: "numeric" },
{
title: "Birth Place",
field: "birthCity",
lookup: { 34: "İstanbul", 63: "Şanlıurfa" },
},
{ title: "submitted", field: "submitted", hidden: true },
];
const [state, setState] = React.useState({
data: [
{
name: "Mehmet",
surname: "Baran",
birthYear: 1987,
birthCity: 63,
submitted: false,
},
{
name: "Zerya Betül",
surname: "Baran",
birthYear: 2017,
birthCity: 34,
submitted: false,
},
],
});
return (
<MaterialTable
title="Editable Example"
columns={columnsHeader}
data={state.data}
editable={{
onRowAdd: (newData) =>
new Promise((resolve, reject) => {
setTimeout(() => {
newData.submitted = true;
if (!newData.name) {
setNameError({
error: true,
label: "required",
helperText: "Name is required.",
validateInput: true,
});
reject();
return;
}
resolve();
const data = [...state.data];
data.push(newData);
setState({ ...state, data });
}, 600);
}),
onRowUpdate: (newData, oldData) =>
new Promise((resolve, reject) => {
setTimeout(() => {
newData.submitted = true;
if (!newData.name) {
setNameError({
error: true,
label: "required",
helperText: "Name is required.",
validateInput: true,
});
reject();
return;
}
resolve();
const data = [...state.data];
data[data.indexOf(oldData)] = newData;
setState({ ...state, data });
}, 600);
}),
onRowDelete: (oldData) =>
new Promise((resolve) => {
setTimeout(() => {
resolve();
const data = [...state.data];
data.splice(data.indexOf(oldData), 1);
setState({ ...state, data });
}, 600);
}),
}}
/>
);
}
just validate and use Reject() like this ( calling reject() keeps open row editable ):
onRowAdd: (newData) =>
new Promise((resolve) => {
if(---!validate(newData)---) {
// alert('required');
reject();
}else{ /*addRow*/ }

Categories

Resources