React Material Table - New field when add row - reactjs

In the Material Table below taken from the example, how would I do to make the 'ahiddenfield' appear when adding a new row? I'm not really sure how to access the state when the new row is about to be added (Before onRowAdd). Is it possible without too much headache?
constructor(props) {
super(props);
this.state = {
columns: [
{ title: 'Name', field: 'name' },
{ title: 'Hidden Field', field: 'hiddenfield', hidden: true }
],
data: [
{ name: 'Mehmet' },
{ name: 'Zerya Betül'},
]
}
}
render() {
return (
<MaterialTable
title="Editable Preview"
columns={this.state.columns}
data={this.state.data}
editable={{
onRowAdd: newData =>
new Promise((resolve, reject) => {
setTimeout(() => {
{
const data = this.state.data;
data.push(newData);
this.setState({ data }, () => resolve());
}
resolve()
}, 1000)
}),
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)
}),
onRowDelete: oldData =>
new Promise((resolve, reject) => {
setTimeout(() => {
{
let data = this.state.data;
const index = data.indexOf(oldData);
data.splice(index, 1);
this.setState({ data }, () => resolve());
}
resolve()
}, 1000)
}),
}}
/>
)
}
} ```

In your <MaterialTable /> component, you should replace the data prop like this:
data={Array.from(this.state.data)}.
This is not documented in the docs. More info here: https://github.com/mbrn/material-table/issues/1900

Related

react-google-maps/api polyline weird lines issue

i am trying to draw directions with a dynamic latitude and longitude array of objects coming from a realtime database, its working properly but there is a extra weird lines like the image below
what i want
if anyone can help thats will be great, thanks
here is my code snippets:
const [tripsState, setTripsState] = useState([]);
useEffect(() => {
const unsubscribe = onSnapshot(collection(db, "LiveTrips"), (snapshot) => {
setTripsState(
snapshot.docs.map((doc) => ({ id: doc.id, data: doc.data() }))
);
// setStopNames(
// snapshot.docs.map((doc) => ({ id: doc.id, data: doc.data() }))
// );
});
return () => {
unsubscribe();
};
}, []);
const handleDisplayMapById = (id) => {
setTripID(id);
tripsState.map((item) => {
if (id === item.id) {
setCurrentTrip(item);
setStops(item.data.Stops);
} else {
console.log("not working");
}
});
};
const getCurrentTripData = () => {
for (var key in currentTrip) {
if (currentTrip.hasOwnProperty(key)) {
SiteLocation = currentTrip[key].SiteLocation;
}
}
};
getCurrentTripData();
const handlePolylineDraw = () => {
var PathLatLong = [];
var polylinePath = [];
if (tripID > 0) {
PathLatLong.length = 0;
polylinePath.length = 0;
PathLatLong = currentTrip.data.Polyline.map((line) => {
return decode(line);
});
// console.log(PathLatLong);
for (let x of PathLatLong) {
x.map((i) => {
polylinePath.push({ lat: i[0], lng: i[1] });
});
}
}
return { polylinePath };
};
<Polyline
path={handlePolylineDraw().polylinePath}
options={{
strokeColor: "#42A9E7",
strokeOpacity: 1,
strokeWeight: 3,
fillOpacity: 0,
clickable: false,
draggable: true,
editable: false,
visible: true,
radius: 30000,
path: handlePolylineDraw().polylinePath,
zIndex: 1,
}}
/>

calling setState from onClick JavaScript function not working

I am trying to create a button that will make visible a form to edit any contact on my list. However, when I press the button, nothing happens.
I have the initial state set to
this.state = {
contacts: [],
showEditWindow: false,
EditContactId: ''
};
I added a function:
editContact = (id) => {
this.setState({
showEditWindow: true, EditContactId: {id}
});
};
and a column:
{
title: "",
key: "action",
render: (record) => (
<button onClick={() => this.editContact(record.id)}
>
Edit
</button>
)
},
I imported EditContactModal and call it as
<EditContactModal reloadContacts={this.reloadContacts}
showEditWindow={this.state.showEditWindow}
EditContactId={this.state.EditContactId}/>
If I manually set this.state to showEditWindow:true, the window appears; however, either this.editContact(id) is not being called or it is not changing the state.
Calling this.deleteContact(id) works fine, as does setState in loadContacts() and reloadContacts()
What I am doing wrong?
Below are the full components.
Contacts.jsx
import { Table, message, Popconfirm } from "antd";
import React from "react";
import AddContactModal from "./AddContactModal";
import EditContactModal from "./EditContactModal";
class Contacts extends React.Component {
constructor(props) {
super(props);
this.state = {
contacts: [],
showEditWindow: false,
EditContactId: ''
};
this.editContact = this.editContact.bind(this);
};
columns = [
{
title: "First Name",
dataIndex: "firstname",
key: "firstname"
},
{
title: "Last Name",
dataIndex: "lastname",
key: "lastname"
},{
title: "Hebrew Name",
dataIndex: "hebrewname",
key: "hebrewname"
},{
title: "Kohen / Levi / Yisroel",
dataIndex: "kohenleviyisroel",
key: "kohenleviyisroel"
},{
title: "Frequent",
dataIndex: "frequent",
key: "frequent",
},{
title: "Do Not Bill",
dataIndex: "donotbill",
key: "donotbill"
},
{
title: "",
key: "action",
render: (record) => (
<button onClick={() => this.editContact(record.id)}
>
Edit
</button>
)
},
{
title: "",
key: "action",
render: (_text, record) => (
<Popconfirm
title="Are you sure you want to delete this contact?"
onConfirm={() => this.deleteContact(record.id)}
okText="Yes"
cancelText="No"
>
<a type="danger">
Delete{" "}
</a>
</Popconfirm>
),
},
];
componentDidMount = () => {
this.loadContacts();
}
loadContacts = () => {
const url = "http://localhost:3000/contacts";
fetch(url)
.then((data) => {
if (data.ok) {
return data.json();
}
throw new Error("Network error.");
})
.then((data) => {
data.forEach((contact) => {
const newEl = {
key: contact.id,
id: contact.id,
firstname: contact.firstname,
lastname: contact.lastname,
hebrewname: contact.hebrewname,
kohenleviyisroel: contact.kohenleviyisroel,
frequent: contact.frequent.toString(),
donotbill: contact.donotbill.toString(),
};
this.setState((prevState) => ({
contacts: [...prevState.contacts, newEl],
}));
});
})
.catch((err) => message.error("Error: " + err));
};
reloadContacts = () => {
this.setState({ contacts: [] });
this.loadContacts();
};
deleteContact = (id) => {
const url = `http://localhost:3000/contacts/${id}`;
fetch(url, {
method: "delete",
})
.then((data) => {
if (data.ok) {
this.reloadContacts();
return data.json();
}
throw new Error("Network error.");
})
.catch((err) => message.error("Error: " + err));
};
editContact = (id) => {
this.setState({
showEditWindow: true, EditContactId: {id}
});
};
render = () => {
return (
<>
<Table
className="table-striped-rows"
dataSource={this.state.contacts}
columns={this.columns}
pagination={{ pageSize: this.pageSize }}
/>
<AddContactModal reloadContacts={this.reloadContacts} />
<EditContactModal reloadContacts={this.reloadContacts}
showEditWindow={this.state.showEditWindow}
EditContactId={this.state.EditContactId}/>
</>
);
}
}
export default Contacts;
EditContactModal.jsx
import { Button, Form, Input, Modal, Select } from "antd";
import React from "react";
import ContactForm from './ContactForm';
const { Option } = Select;
class EditContactModal extends React.Component {
formRef = React.createRef();
state = {
visible: this.props.showEditWindow,
};
onFinish = (values) => {
const url = `http://localhost:3000/contacts/${this.props.EditContactId}`;
fetch(url, {
method: "put",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(values),
})
.then((data) => {
if(data.ok) {
this.handleCancel();
return data.json();
}
throw new Error("Network error.");
})
.then(() => {
this.props.reloadContacts();
})
.catch((err) => console.error("Error: " + err))
};
showModal = () => {
this.setState({
visible: true,
});
};
handleCancel = () => {
this.setState({
visible: false,
});
};
render() {
return (
<>
{/*<Button type="primary" onClick={this.showModal}>
Create New +
</Button>*/}
<Modal
title="Edit Contact"
visible={this.state.visible}
onCancel={this.handleCancel}
footer={null}
>
<ContactForm />
</Modal>
</>
);
}
}
export default EditContactModal;
if your aim is to perform an update to the state object, you must not pass mutable data, but copy it instead into a new object.
this will allow the state changes to be picked up.
so, prefer setState({ ...state, ...someObject }) over setState(someObject).

Increase width of select lookup box in React Material-Table

I am using Material-Table in React and trying to increase the width of this 'lookup' column in 'Requirement' field. I have tried cellStyle: {columnWidth: 800}. Also, tried width, padding. None seem to accomplish this. I've checked through the documentation, and a few other places, but not able to resolve this. Appreciate anyone who knows how to make this change.
enter code here
const [columns] = useState([
{ title: 'Skills', field: 'type' },
{ cellStyle: {columnWidth: 800}, title: 'Requirement', field: 'mustHave', lookup: {34: 'Required', 63: 'Must-have'} /*initialEditValue: 'initial edit value'*/ },
{ cellStyle: {textAlign: 'left'}, headerStyle: {textAlign: 'left'}, title: 'Desired Rating', field: 'desiredRating',
editComponent: (props) => (
<Input
defaultValue={props.value}
onChange={(e) => props.onChange(e.target.value)}
type="number"
min="0"
max="10"
onInput={maxLengthCheck}
/>
)
}
]);
const [data, setData] = useState([]);
useEffect(() => {
setData(workExp);
}, [workExp]);
console.log(workExp);
return (
<MaterialTable
style={{fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif', fontSize: '0.875rem', textAlign: 'left'}}
title="Hiring Criteria"
columns={columns}
options={{actionsColumnIndex: -1}}
data={data}
editable={{
onRowAdd: newData =>
new Promise((resolve, reject) => {
setTimeout(() => {
setData([...data, newData]);
resolve();
}, 1000)
}),
onRowUpdate: async (newData, oldData) => {
try {
const index = oldData.tableData.id;
let newWorkExp = [...workExp];
newWorkExp[index] = newData;
console.log(data);
console.log(newWorkExp[index].mustHave === '63');
if(newWorkExp[index].mustHave === '63' || newWorkExp[index].mustHave === 'Must-have') {
newWorkExp[index].mustHave = 'Must-have';
}
console.log(newWorkExp);
setData(newWorkExp);
await dispatch(updateRequisition(id, {workExp: newWorkExp}));
await wait(1000);
} catch (err) {
console.error(err);
}
},
onRowDelete: oldData =>
new Promise((resolve, reject) => {
setTimeout(() => {
const dataDelete = [...data];
const index = oldData.tableData.id;
dataDelete.splice(index, 1);
setData([...dataDelete]);
resolve()
}, 1000)
}),
}}
/>
)
}
export default HiringCriteria;
Was able to resolve this. Used browser tools to get class name and created stylesheet using !important to override styles.

How to override MTablePagination from material-table reactjs?

I have more than one million rows and want to display them in material-table reactjs. How do I get data from back-end only for rows on one page and then get next set of rows on next page click?
import React, { useState, useEffect } from 'react';
import MaterialTable from 'material-table';
import Axios from 'axios'
export default function MaterialTableDemo() {
var columns = [
{title: "stationid", field: "stationid", editable: 'never'},
{title: "model", field: "model", editable: 'never'},
{title: "version", field: "version", editable: 'never'},
{title: "lat", field: "lat", editable: 'never'},
{title: "lon", field: "lon", editable: 'never'},
{title: "status", field: "status"}
]
const [data, setData] = useState([]);
useEffect(() => {
Axios.get("/ListView")
.then(res => {
setData(res.data.data)
console.log(res.data.data)
})
.catch(error=>{
console.log("Error")
})
}, [])
const handleRowUpdate = (newData, oldData, resolve) => {console.log("updating row")
let errorList = []
if(newData.status === ""){
errorList.push("Please enter Status")
}
if(errorList.length < 1){
Axios.post("/update", newData)
.then(res => {
const dataUpdate = [...data];
const index = oldData.tableData;
dataUpdate[index] = newData;
setData([...dataUpdate]);
resolve()}
)
.catch(error => {
resolve()
})
}else{
resolve()
}
window.location.reload(true);
}
const handleRowDelete = (oldData, resolve) => {
Axios.post("/delete", oldData)
.then(res => {
const dataDelete = [...data];
const index = oldData.tableData;
dataDelete.splice(index, 1);
setData([...dataDelete]);
resolve()
})
.catch(error => {
resolve()
})
window.location.reload(true);
}
return (
<MaterialTable
title="Station MetaData from DB"
columns={columns}
data={data}
options={{
exportButton: true,
showFirstLastPageButtons: false,
}}
localization={{
pagination: {
labelDisplayedRows: '{from}-{to}'
},
}}
editable={{
onRowUpdate: (newData, oldData) =>
new Promise((resolve) => {
handleRowUpdate(newData, oldData, resolve);
}),
onRowDelete: (oldData) =>
new Promise((resolve) => {
handleRowDelete(oldData, resolve)
}),
}}
/>
);
}
How do I make get only as many rows from backend as possible on 1 page for display? For example, if I want to display only 5 rows per page then I should get only 5 rows from backend and on click on next page get next 5 rows.
I know its a bit late but maybe it will help others with the same question.
You should override Pagination in components:
<MaterialTable
options={options}
data={data}
columns={columns}
editable={{onRowUpdate}}
localization={localization}
components={{
Pagination: (props) =>
<CustomPagination
props={props}
rowsPerPage={pageSize}
pageIndex={pageIndex}
setPageIndex={setPageIndex}
setPageSize={setPageSize}/>
}
}}
/>
where
<CustomPagination
rowsPerPageOptions={rowsPerPageOptions}
rowsPerPage={rowsPerPage}
count={totalPages}
page={pageIndex}
onChangePage={(event, page) => {
props.onChangePage(event, page);
setPageIndex(page)
}}
onChangeRowsPerPage={event => {
props.onChangeRowsPerPage(event);
setPageSize(parseInt(event.target.value));
}}
/>
All the fields in CustomPagination are hooks from it's parent component so that you will do your api calls and re-render when they change .
Using the same way you can change the text of this buttons, please check this example https://material-table.com/#/docs/features/localization.

How can we disable/hide the Add ,edit and delete icons in material table in react JS?

I have highlighted the buttons which needs to be disabled/hidden.
You need to remove the editable prop.
<MaterialTable
editable={{
isEditable: rowData => rowData.name === "a", // only name(a) rows would be editable
isDeletable: rowData => rowData.name === "b", // only name(a) rows would be deletable
onRowAdd: newData =>
new Promise((resolve, reject) => {
setTimeout(() => {
{
/* const data = this.state.data;
data.push(newData);
this.setState({ data }, () => resolve()); */
}
resolve();
}, 1000);
}),
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);
}),
onRowDelete: oldData =>
new Promise((resolve, reject) => {
setTimeout(() => {
{
/* let data = this.state.data;
const index = data.indexOf(oldData);
data.splice(index, 1);
this.setState({ data }, () => resolve()); */
}
resolve();
}, 1000);
})
}}
/>
would become just
<MaterialTable/>
You can find more information in the official documentation.
If that doesn't help, please post your code.
you can check that document for more details.
Editable Example check this tab on that page
https://material-table.com/#/docs/features/editable
or this think help you
components={{
Action:
props => {
if(props.action.icon === 'edit'){
return(
<Button
onClick={(event) => props.action.onClick(event, props.data)}
color="primary"
variant="contained"
style={{textTransform: 'none'}}
size="small"
disabled
>
My Button
</Button>
)
}
if(props.action.icon === 'save'){
return(
<Button
onClick={(event) => props.action.onClick(event, props.data)}
color="primary"
variant="contained"
style={{textTransform: 'none'}}
size="small"
>
My Button
</Button>
)
}
}
}}
Just remove the functionality from createTableActions.
For eg if you don't want delete and add but want edit.
const createTableActions = (tableName: string, setData:React.Dispatch<React.SetStateAction<object[]>>) => {
const { isEditable } = SP_LIST_CONFIG[tableName];
return isEditable
? {
onRowUpdate: (newData, oldData) =>
new Promise((resolve, reject) => {
resolve();
}),
}
: {};
};

Resources