Increase width of select lookup box in React Material-Table - reactjs

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.

Related

Ant design Transform component extracting selected data

I need to extract selected/filtered data into the state. I tried everything with onChange and on select change but only I got is the ID of one specific item.
ex. extracted_data = [ '1','2','3'....]
But I need a complete Item with id, name, price, etc...
I am passing data as source data, and after selecting I want to send in the parent component because I need to send it on the server.
Code is below
import { Table, Transfer } from "antd";
import difference from "lodash/difference";
import React, { useState } from "react";
// Customize Table Transfer
const TableTransfer = ({ leftColumns, rightColumns, ...restProps }) => (
<Transfer {...restProps}>
{({
direction,
filteredItems,
onItemSelectAll,
onItemSelect,
selectedKeys: listSelectedKeys,
disabled: listDisabled,
}) => {
const columns = direction === "left" ? leftColumns : rightColumns;
const rowSelection = {
getCheckboxProps: (item) => ({
disabled: listDisabled || item.disabled,
}),
onSelectAll(selected, selectedRows) {
const treeSelectedKeys = selectedRows
.filter((item) => !item.disabled)
.map(({ key }) => key);
const diffKeys = selected
? difference(treeSelectedKeys, listSelectedKeys)
: difference(listSelectedKeys, treeSelectedKeys);
onItemSelectAll(diffKeys, selected);
},
onSelect({ key }, selected) {
onItemSelect(key, selected);
},
selectedRowKeys: listSelectedKeys,
};
return (
<Table
rowSelection={rowSelection}
columns={columns}
dataSource={filteredItems}
size="small"
style={{
pointerEvents: listDisabled ? "none" : undefined,
}}
onRow={({ key, disabled: itemDisabled }) => ({
onClick: () => {
if (itemDisabled || listDisabled) return;
onItemSelect(key, !listSelectedKeys.includes(key));
},
})}
/>
);
}}
</Transfer>
);
const leftTableColumns = [
{
dataIndex: "name",
title: "Name",
},
{
dataIndex: "price",
title: "Price (€)",
},
{
dataIndex: "discount",
title: "Discount (%)",
},
];
const rightTableColumns = [
{
dataIndex: "name",
title: "Name",
},
{
dataIndex: "price",
title: "Price",
},
];
const App = ({ data, func }) => {
const mockData = data.map((item) => ({
key: item.id.toString(),
name: item.name,
price: item.price,
discount: item.discount,
}));
const originTargetKeys = mockData.map((item) => item.key);
const [targetKeys, setTargetKeys] = useState(originTargetKeys);
const [selected, setSelected] = useState([]);
const onSelectChange = (e) => {
setSelected(e);
};
const onChange = (e) => {
setTargetKeys(e);
func(selected);
};
return (
<>
<TableTransfer
dataSource={mockData}
targetKeys={targetKeys}
disabled={false}
showSearch={true}
onChange={onChange}
onSelectChange={onSelectChange}
filterOption={(inputValue, item) =>
item.name.indexOf(inputValue) !== -1
}
leftColumns={leftTableColumns}
rightColumns={rightTableColumns}
/>
</>
);
};
export default App;

Add autocomplete with multiple and creatable reactjs material ui

I want the users to be able to select multiple tags while also allowing them to add a tag if it does not exist, the examples on the material UI documentation work on the freeSolo option which works on string / object values as options whereas when we use multiple, that changes to an array
How do I implement a multiple creatable with material-ui?
My code:
// Fetch Adding tag list
const [listOpen, setListOpen] = useState(false);
const [options, setOptions] = useState<Tag[]>([]);
const loadingTags = listOpen && options.length === 0;
useEffect(() => {
let active = true;
if (!loadingTags) {
return undefined;
}
(async () => {
try {
const response = await getAllTagsForUser();
if (active) {
setOptions(response.data);
}
} catch (error) {
console.log(error);
}
})();
return () => {
active = false;
};
}, [loadingTags]);
useEffect(() => {
if (!listOpen) {
setOptions([]);
}
}, [listOpen]);
<Autocomplete
multiple
id="tags"
open={listOpen}
onOpen={() => {
setListOpen(true);
}}
onClose={() => {
setListOpen(false);
}}
options={options}
disableCloseOnSelect
getOptionLabel={(option) => option?.name || ""}
defaultValue={
contact?.tags?.map((element) => {
return { name: element };
}) || undefined
}
renderOption={(option, { selected }) => (
<React.Fragment>
<Checkbox
icon={icon}
checkedIcon={checkedIcon}
style={{ marginRight: 8 }}
checked={selected}
/>
{option.name}
</React.Fragment>
)}
style={{ width: 500 }}
renderInput={(params) => (
<TextField {...params} variant="outlined" label="Tags" />
)}
/>;
This is just fetching tags from the server and showing them as options, I understand that to be able to allow adding more, I would need to add filterOptions and onChange but, can someone please provide an example on how to deal with array there?
I know this isn't an quick answer but may someone else could use it. Found this Question buy searching an solution. Didn't find one so I tryed myself and this is what I Created and seems it works.
Based on the original Docs https://mui.com/components/autocomplete/#creatable
Complete example:
import React, { useEffect, useState } from "react";
//Components
import TextField from "#mui/material/TextField";
import Autocomplete, { createFilterOptions } from "#mui/material/Autocomplete";
//Icons
const filter = createFilterOptions();
export default function AutocompleteTagsCreate() {
const [selected, setSelected] = useState([])
const [options, setOptions] = useState([]);
useEffect(() => {
setOptions(data);
}, [])
return (
<Autocomplete
value={selected}
multiple
onChange={(event, newValue, reason, details) => {
let valueList = selected;
if (details.option.create && reason !== 'removeOption') {
valueList.push({ id: undefined, name: details.option.name, create: details.option.create });
setSelected(valueList);
}
else {
setSelected(newValue);
}
}}
filterSelectedOptions
filterOptions={(options, params) => {
const filtered = filter(options, params);
const { inputValue } = params;
// Suggest the creation of a new value
const isExisting = options.some((option) => inputValue === option.name);
if (inputValue !== '' && !isExisting) {
filtered.push({
name: inputValue,
label: `Add "${inputValue}"`,
create: true
});
}
return filtered;
}}
selectOnFocus
clearOnBlur
handleHomeEndKeys
id="tags-Create"
options={options}
getOptionLabel={(option) => {
// Value selected with enter, right from the input
if (typeof option === 'string') {
return option;
}
// Add "xxx" option created dynamically
if (option.label) {
return option.name;
}
// Regular option
return option.name;
}}
renderOption={(props, option) => <li {...props}>{option.create ? option.label : option.name}</li>}
freeSolo
renderInput={(params) => (
<TextField {...params} label="Tags" />
)}
/>
);
}
const data = [
{
id: 1,
name: 'Tag1'
},
{
id: 2,
name: 'Tag2'
},
{
id: 3,
name: 'Tag3'
},
{
id: 4,
name: 'Tag4'
},
]

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.

Material-Table with React: how to use star rating in the cell?

I would like to style my cell's rating into star by using Material-Table,
like the original Material-UI provided:
https://material-ui.com/components/rating/
Is it possible to use in Material-Table? I cannot find document related to this...just for the style for background, color, etc., not for writing functions in cell style.
https://material-table.com/#/docs/features/styling
thanks a lot!
You can use material-table's custom edit component to render the mui Rating component.
Full Working demo
Sample code snippet of columns array
const columns = propValue => [
{ title: "Id", field: "id" },
{ title: "First Name", field: "first_name" },
{
title: "Rating",
field: "rating",
render: rowData => {
return <Rating name="hover-feedback" value={rowData.rating} readOnly />;
},
editComponent: props => (
<Rating
name="hover-feedback"
value={props.value}
onChange={(event, newValue) => {
props.onChange(newValue);
}}
/>
),
cellStyle: {
backgroundColor: "#039be5",
color: "#FFF"
},
width: "30%"
}
];
Component
class App extends Component {
tableRef = React.createRef();
propValue = true;
state = { data: [] };
componentDidMount() {
const query = 0;
let url = "https://reqres.in/api/users?";
url += "per_page=" + query.pageSize;
url += "&page=" + (query.page + 1);
fetch(url)
.then(response => response.json())
.then(result => {
console.log("result", result);
this.setState({
data: result.data.map(d => ({ ...d }))
});
});
}
render() {
return (
<div style={{ maxWidth: "100%" }}>
<MaterialTable
icons={tableIcons}
tableRef={this.tableRef}
columns={columns(this.propValue)}
editable={{
onRowUpdate: (newData, oldData) =>
new Promise((resolve, reject) => {
console.log("newData", newData);
console.log("oldData", oldData);
const dataUpdate = [...this.state.data];
const index = oldData.tableData.id;
dataUpdate[index] = newData;
this.setState({ data: dataUpdate }, () => {
console.log("xx", this.state.data);
resolve(this.state);
});
})
}}
data={this.state.data}
title="Remote Data Example"
options={{ tableLayout: "fixed" }}
/>
<button
onClick={() => {
this.tableRef.current.onQueryChange();
}}
>
ok
</button>
</div>
);
}
}

React Material Table - New field when add row

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

Resources