Extending React-Table using composition - issues with props - reactjs

I'm trying to create a component based on react-table using composition so that we can use a customised version everywhere without repeating boiler plate. I'm using Typescript while react-table doesn't use it. I don't see any examples around of doing this so here's what I've come up with so far:
import * as React from 'react'
import ReactTable, {TableProps} from 'react-table'
import './../components/react-table-styling.css'
import 'react-table/react-table.css'
import Pagination from './pagination'
import { Paper } from '#material-ui/core'
export interface IReactTableProps{
textCols:Array<string>;
}
export class ExtReactTable extends React.Component<IReactTableProps & TableProps> {
static defaultProps = {
}
constructor(props: IReactTableProps & TableProps) {
super(props);
}
rows = (state, rowInfo) => {//set taller height and vertical centering
return {
style: { height:40, display:'flex', alignItems: 'center'},
}
}
headerRows = (state, rowInfo, column) => {
return {
style: { height: 40, display:'flex', alignItems: 'center',
paddingLeft: (column.Header === 'Product'||column.Header ===
'Client') ? '20px':'',
justifyContent: (column.Header === 'Product'||column.Header ===
'Client') ? '': 'center' }
}
}
render() {
return(
<Paper>
<ReactTable style={{cursor:'pointer', fontSize: 13, background:'#fff', borderLeft: 0, borderRight: 0}} PaginationComponent={Pagination}
getTrProps={this.rows} getTheadThProps={this.headerRows} />
</Paper>)
}
}
Trying to get it initially working, I use it like this:
import { ExtReactTable } from '../../components/ext-react-table';
<ExtReactTable data={products} textCols={["Product"]} columns={[
{Header: "Product", accessor: "permitProductName", minWidth: 200, style: { paddingLeft:20}},
{Header: "Client",accessor: "clientName", minWidth: 300, style: { paddingLeft:20}},
{Header: "Spaces", accessor: "spaces", minWidth:80, style: { textAlign: 'right', paddingRight:'4%'}},
{Header: "Active VRMs", accessor: "activeVRMs", minWidth:80, style: { textAlign: 'right', paddingRight:'4%'}},
{Header: "Max VRMs", accessor: "maxVRMs", minWidth:80, style: { textAlign: 'right', paddingRight:'4%'}},
{Header: "Start Date", accessor: "startDate", style: { textAlign: 'center'}, Cell: (props) => { return <span>{dateTimeHelper.shortDate(props.original.startDate)}</span>}},
{Header: "End Date", accessor: "endDate", style: { textAlign: 'center'}, Cell: (props) => { return <span>{(props.original.endDate !== "0001-01-01T00:00:00" && props.original.endDate !== null) ? dateTimeHelper.shortDate(props.original.endDate) : '-'}</span>}}
]}
defaultSorted={[ { id: "permitProductName", asc: true }]}
defaultPageSize={10} className={" -highlight"}
/>
but it complains that I am not supplying the optional prop 'loading' (and if you supply that then dozens of other props of react-table for which you wouldn't want to supply values). What's the approach to solving this issue? Do you have to provide dozens of values as defaultProps or is there some other way? Thanks

It looks like loading and so forth are required properties of the TableProps interface (here), but ReactTable actually uses Partial<TableProps> as its props type (here). If you replace TableProps with Partial<TableProps> in your code to be consistent, then the errors should go away.

Related

Rows Duplicates MUI DataGrid

I have a Data Grid component of the MUI and I am fetching data using axios, of course the objective is to show the data fetched in the Data Grid component, when I looked in the console it returns me correct, but in the page it returns me only one result o duplicating.
I believe there is a problem with the front-end but I am not able to identify it.
JSON
//Code
export default function ListGrid() {
const [load, setLoad] = useState(false);
const [users, setUsers] = useState<IDados[]>([]);
interface IDados {
empresa: number,
nome: string,
matricula: number,
ano: number,
}
useEffect(() => {
setLoad(true);
if (load === true) {
axios
.get("http://localhost:8080/questionarios/all", {
headers: {
...getTokenAuth()
},
})
.then((res) => {
setUsers(res.data);
// console.log(res.data);
})
}
}, [load]);
const columns: GridColDef[] = [
{
field: 'empresa',
headerName: 'Empresa',
width: 120,
headerAlign: 'center',
align: 'center',
},
{
field: 'nome',
headerName: 'Nome',
width: 250,
headerAlign: 'center',
align: 'center',
valueGetter: (params) => {
return params.getValue(params.id, "colaborador").nome;
}
},
{
field: 'matricula',
headerName: 'MatrĂ­cula',
width: 150,
headerAlign: 'center',
align: 'center',
},
{
field: 'ano',
headerName: 'Ano',
width: 150,
headerAlign: 'center',
align: 'center',
},
];
return (
<Box sx={{ height: 400, width: '100%' }}>
<DataGrid
rows={users}
columns={columns}
checkboxSelection
disableSelectionOnClick
experimentalFeatures={{ newEditingApi: true }}
localeText={ptBR.components.MuiDataGrid.defaultProps.localeText}
pageSize={pageSize}
onPageSizeChange={(newPageSize) => setPageSize(newPageSize)}
rowsPerPageOptions={[5, 10, 20]}
pagination
initialState={{
filter: {
filterModel: {
items: [],
quickFilterLogicOperator: GridLinkOperator.Or,
},
},
}}
components={{ Toolbar: barraPesquisa }}
getRowId={(row: any) => row.name + row.matricula}
/>
</Box>
);
}
Your warning message seems to indicate some keys are NaN. Maybe you have a problem with
getRowId={(row: any) => row.name + row.matricula}
which return NaN for some rows

react-select styling issues when resizing for height and width

I am trying to make a react-select component but I keep running into an issue where if I change the high and width of the original react-select it throws everything else of center.
Here is the original react-select box code:
import React from 'react'
import Select from 'react-select'
const options = [
{ value: 'item-1', label: 'item-1' },
{ value: 'item-2', label: 'item-2' },
{ value: 'item-3', label: 'item-3' },
{ value: 'item-4', label: 'item-4' }
]
export default function Example(){
return (
<Select options={options}
closeMenuOnSelect={true}
placeholder="Placeholder"
/>
)}
and a picture:
original react-select image
this is size of react-select box I want:
height: 20,
width: 118.5
modified react-select for correct height and width
as you can see it throws off the placement of the input box, placeholder, and icons.
Here is the code for the above image:
import React from 'react'
import Select from 'react-select'
const options = [
{ value: 'item-1', label: 'item-1' },
{ value: 'item-2', label: 'item-2' },
{ value: 'item-3', label: 'item-3' },
{ value: 'item-4', label: 'item-4' }
]
const customStyles = {
control: base => ({
...base,
height: 20,
minHeight: 20,
width: 118.5,
}),
}
export default function Example(){
return (
<Select options={options}
styles={customStyles}
closeMenuOnSelect={true}
placeholder="Placeholder"
/>
)}
and this is how I have been trying to modify the component. This has gotten me somewhat close to the desired outcome but the input box sizing and icon placements are still off and sized weird:
import React from 'react'
import Select from 'react-select'
const options = [
{ value: 'item-1', label: 'item-1' },
{ value: 'item-2', label: 'item-2' },
{ value: 'item-3', label: 'item-3' },
{ value: 'item-4', label: 'item-4' }
]
const customStyles = {
control: base => ({
...base,
height: 20,
minHeight: 20,
width: 118.5,
}),
valueContainer: base => ({
...base,
height: 20,
minHeight: 20,
width:20,
alignItems: 'left',
}),
indicatorsContainer: base => ({
...base,
height: 20,
minHeight: 20,
alignItems: 'center',
}),
}
export default function Example(){
return (
<Select options={options}
styles={customStyles}
closeMenuOnSelect={true}
placeholder="Placeholder"
/>
)}
react-select what I have been able to achieve with the posted code image 1
react-select what I have been able to achieve with the posted code image 2
I have been at this for hours and I just cannot seem to get everything to fit nice and neat into the react-select box when I resize it. Any help would be greatly appreciated.

React material-ui datagrid editing Issue

I have created a Material UI DataGrid table and trying to make its fields editable. I am facing an issue while editing the fields using my custom logic. My custom editing logic works when I press enter however when I edit the value and then click outside of the column (somewhere else on the page) the internal value gets updated according to the logic however the displayed cell value doesn't match the updated value, it shows the user-edited value.
import React, { useEffect } from "react";
import { makeStyles, LinearProgress } from "#material-ui/core";
import {
DataGrid,
GridColDef,
GridOverlay,
GridCellEditCommitParams,
GridValueFormatterParams,
} from "#material-ui/data-grid";
const useStyles = makeStyles({
root: {
"& .super-app-theme--header": {
backgroundColor: "#f2f2f2",
},
},
muiGridRoot: {
maxHeight: "77px !important",
"& .MuiDataGrid-columnHeaderTitle": {
fontWeight: "600 !important" as any,
},
},
});
interface props {
coilId: string;
}
export default function TargetMechnicalPropsTable({
coilId,
}: props) {
const classes = useStyles();
const [rows, setRows] = React.useState<any>([
{
id: 1,
UpperLimitValue: 124.232,
lowerLimitValue: 24.232,
targetValue: 67.33,
element: "Yield Strength",
},
]);
const columns: GridColDef[] = [
{
field: "id",
hide: true,
headerClassName: "super-app-theme--header",
sortable: false,
flex: 1,
align: "center",
headerAlign: "center",
},
{
field: "element",
headerName: "Element",
headerClassName: "super-app-theme--header",
editable: false,
sortable: false,
flex: 1,
align: "center",
headerAlign: "center",
},
{
field: "targetValue",
headerName: "Target value",
headerClassName: "super-app-theme--header",
valueFormatter: (params: GridValueFormatterParams) => {
const valueFormatted = Number(params.value as number).toFixed(4);
return `${valueFormatted}`;
},
editable: true,
//type: "number",
sortable: false,
flex: 1,
align: "center",
headerAlign: "center",
},
{
field: "lowerLimitValue",
headerName: "Lower Limit",
headerClassName: "super-app-theme--header",
valueFormatter: (params: GridValueFormatterParams) => {
const valueFormatted = Number(params.value as number).toFixed(4);
return `${valueFormatted}`;
},
editable: true,
sortable: false,
flex: 1,
align: "center",
headerAlign: "center",
},
{
field: "UpperLimitValue",
headerName: "Upper Limit",
headerClassName: "super-app-theme--header",
sortable: false,
valueFormatter: (params: GridValueFormatterParams) => {
const valueFormatted = Number(params.value as number).toFixed(4);
return `${valueFormatted}`;
},
editable: true,
flex: 1,
align: "center",
headerAlign: "center",
},
];
const handleCellEditCommit = React.useCallback(
({ id, field, value }: GridCellEditCommitParams) => {
const updatedRows = rows.map((row: any) => {
if (row.id === id) {
switch (field) {
case "lowerLimitValue":
if (
Number(value) < Number(row.targetValue) &&
Number(value) < Number(row.UpperLimitValue)
) {
return { ...row, lowerLimitValue: Number(value) };
} else {
return {
...row,
lowerLimitValue: Number(row.lowerLimitValue),
};
}
case "UpperLimitValue":
if (
Number(value) > Number(row.targetValue) &&
Number(value) > Number(row.lowerLimitValue)
) {
return { ...row, UpperLimitValue: Number(value) };
} else {
return {
...row,
UpperLimitValue: Number(row.UpperLimitValue),
};
}
case "targetValue":
if (
Number(value) > Number(row.lowerLimitValue) &&
Number(value) < Number(row.UpperLimitValue)
) {
return { ...row, targetValue: Number(value) };
} else {
return {
...row,
targetValue: Number(row.targetValue),
};
}
}
}
return row;
});
setRows(updatedRows);
},
[rows]
);
return (
<div style={{ width: "100%" }} className={classes.root}>
<DataGrid
classes={{
root: classes.muiGridRoot,
}}
rows={rows}
columns={columns}
hideFooterPagination
hideFooter
disableColumnMenu
disableColumnFilter
disableColumnSelector
autoHeight
disableExtendRowFullWidth
density="compact"
onCellEditCommit={handleCellEditCommit}
/>
</div>
);
}
Please let me know what needs to be done for my custom logic to work when the user clicks outside of the column while editing it so that the user displayed value matches with the internal logic value.
Thank you!

trying to implement a text filter to a ag-grid in a react component

I can't figure out how to implement a simple search bar to the ag-grid i set. I would like to let my input filter the results in my grid based on every columns I couldn't figure out a good documentation with example for that. Here is my code. Feel free to redirect me to a proper example or another question similar.
import React from 'react';
import { AgGridReact } from 'ag-grid-react';
import axios from 'axios';
import 'ag-grid-community/dist/styles/ag-grid.css';
import 'ag-grid-community/dist/styles/ag-theme-alpine.css';
class ListTableClients extends React.Component {
constructor(props) {
super(props);
this.state = {
defaultColDef: {
flex: 1,
cellClass: 'cell-wrap-text',
autoHeight: true,
sortable: true,
resizable: true,
},
columnDefs: [
{ headerName: "id", field: "id", maxWidth: 100 },
{ headerName: "name", field: "name"},
{ headerName: "email", field: "email"}],
rowData: [
{ id: 1, name: 'maison du café', email: 'maisonducafe#gamil.com' },
{ id: 2, name: 'Warehouse', email: 'contact#warehouse.fr' },
{ id: 3, name: 'Maestro', email: 'maestro#gmail.com' }],
rowHeight: 275,
}
}
componentDidMount() {
console.log('test');
axios.get('http://localhost:8080/listClients').then((res) => {
this.setState({ rowData: res.data });
}).catch((error) => { console.log(error) });
}
render() {
return (
<div style={{width: '100%', paddingLeft: '50px', paddingRight: '50px', paddingTop: '50px'}} className="ag-theme-alpine">
<input type="text" placeholder="Filter..." onInput={this.onFilterTextBoxChanged}/>
<AgGridReact
domLayout='autoHeight'
columnDefs={this.state.columnDefs}
defaultColDef={this.state.defaultColDef}
getRowHeight={this.state.getRowHeight}
rowData={this.state.rowData}>
</AgGridReact>
</div>
);
}
}
export default ListTableClients;
Refer this demo
If the cell data in object format then you have to format it Ag-Grid Value Formatters

breaking big component into smaller one

I'm working on separating code from index.tsx into two different files viz: firstTab.tsx and secondTab.tsx. I haven't started working on secondTab.tsx yet.
I separated first tab related code into firstTab.tsx as shown in the following code editor: The full functional code with both tabs working are in index.tsx is pasted below:
import React, { Component } from "react";
import { render } from "react-dom";
import "jqwidgets-scripts/jqwidgets/styles/jqx.base.css";
import JqxButton from "jqwidgets-scripts/jqwidgets-react-tsx/jqxbuttons";
import * as ReactDOM from "react-dom";
import JqxWindow from "jqwidgets-scripts/jqwidgets-react-tsx/jqxwindow";
import JqxInput from "jqwidgets-scripts/jqwidgets-react-tsx/jqxinput";
import JqxChart, {
IChartProps
} from "jqwidgets-scripts/jqwidgets-react-tsx/jqxchart";
import JqxGrid, {
IGridProps,
jqx
} from "jqwidgets-scripts/jqwidgets-react-tsx/jqxgrid";
import JqxTabs from "jqwidgets-scripts/jqwidgets-react-tsx/jqxtabs";
import JqxDropDownList, {
IDropDownListProps
} from "jqwidgets-scripts/jqwidgets-react-tsx/jqxdropdownlist";
import firstTab from './firstTab';
interface AppProps {}
interface AppState {
name: string;
}
interface IProps extends IGridProps {
dropdownlistSource: IDropDownListProps["source"];
}
class App extends Component<{}, IProps> {
private myTabs = React.createRef<JqxTabs>();
private gridElement = React.createRef<HTMLDivElement>();
private myGrid = React.createRef<JqxGrid>();
private gridElementTwo = React.createRef<HTMLDivElement>();
private myGrid2 = React.createRef<JqxGrid>();
constructor(props: {}) {
super(props);
this.state = {
dropdownlistSource: [
{ value: 0, label: "Affogato" },
{ value: 1, label: "Americano" },
{ value: 2, label: "Bicerin" },
{ value: 3, label: "Breve" }
]
};
}
public render() {
return (
<JqxTabs
ref={this.myTabs}
// #ts-ignore
width={400}
height={560}
initTabContent={this.initWidgets}
>
<ul>
<li style={{ marginLeft: 30 }}>
<div style={{ height: 20, marginTop: 5 }}>
<div
style={{
marginLeft: 4,
verticalAlign: "middle",
textAlign: "center",
float: "left"
}}
>
US Indexes
</div>
</div>
</li>
<li>
<div style={{ height: 20, marginTop: 5 }}>
<div
style={{
marginLeft: 4,
verticalAlign: "middle",
textAlign: "center",
float: "left"
}}
>
NASDAQ compared to S&P 500
</div>
</div>
</li>
</ul>
<div style={{ overflow: "hidden" }}>
<div id="jqxGrid" ref={this.gridElement} />
<div style={{ marginTop: 10, height: "15%" }} />
</div>
<div style={{ overflow: "hidden" }}>
<div id="jqxGrid2" ref={this.gridElementTwo} />
<div style={{ marginTop: 10, height: "15%" }} />
</div>
</JqxTabs>
);
}
private initGrid = () => {
const source = {
datafields: [{ name: "Date" }, { name: "S&P 500" }, { name: "NASDAQ" }],
datatype: "csv",
localdata: `1/2/2014,1831.98,4143.07
1/3/2014,1831.37,4131.91
1/6/2014,1826.77,4113.68
1/7/2014,1837.88,4153.18
1/8/2014,1837.49,4165.61
1/9/2014,1838.13,4156.19
2/6/2014,1773.43,4057.12
2/7/2014,1797.02,4125.86`
};
const dataAdapter = new jqx.dataAdapter(source, {
async: false,
loadError: (xhr: any, status: any, error: any) => {
console.log(xhr, status, error);
}
});
const columns: IGridProps["columns"] = [
{ cellsformat: "d", datafield: "Date", text: "Date", width: 250 },
{ datafield: "S&P 500", text: "S&P 500", width: 150 },
{ datafield: "NASDAQ", text: "NASDAQ" }
];
const grid = (
<JqxGrid
ref={this.myGrid}
width={"100%"}
height={400}
source={dataAdapter}
columns={columns}
/>
);
render(grid, this.gridElement.current!);
};
private initGrid2 = () => {
const source = {
datafields: [{ name: "Date" }, { name: "S&P 500" }, { name: "NASDAQ" }],
datatype: "csv",
localdata: `1/2/2014,1831.98,4143.07
1/3/2014,1831.37,4131.91
1/6/2014,1826.77,4113.68
1/7/2014,1837.88,4153.18
1/8/2014,1837.49,4165.61
1/9/2014,1838.13,4156.19
1/10/2014,1842.37,4174.67
2/7/2014,1797.02,4125.86`
};
const dataAdapter = new jqx.dataAdapter(source, {
async: false,
loadError: (xhr: any, status: any, error: any) => {
console.log(xhr, status, error);
}
});
const columns: IGridProps["columns"] = [
{ cellsformat: "d", datafield: "Date", text: "Date", width: 250 },
{ datafield: "S&P 500", text: "S&P 500", width: 150 },
{ datafield: "NASDAQ", text: "NASDAQ" }
];
const grid = (
<JqxGrid
ref={this.myGrid2}
width={"100%"}
height={400}
source={dataAdapter}
columns={columns}
/>
);
render(grid, this.gridElementTwo.current!);
};
private initWidgets = (tab: any) => {
switch (tab) {
case 0:
this.initGrid();
break;
case 1:
this.initGrid2();
break;
}
};
}
render(<App />, document.getElementById("root"));
Question:
Since I've already moved private initGrid = () => { inside a separate file firstTab.tsx, in index.tsx where should I put {firstTab.tsx} to make sure both tabs in index.tsx works fine? I mean, even if I comment out private initGrid = () => { function from index.tsx both tabs should work fine.
Thanks
If I would refactor this I would consider the next approach:
Create Parent component Table (probably some more appropriate name)
Create a component for US Indexes
Create a component for NASDAQ compared to S&P 500
Based on the active tab render the proper component.
You could also create a separate file that contains only exports with your data.
If you then import that into your files with the functions you can use that there, keeps it cleaner.
And if you pass that data as a prop / param to your initGrid() functions, you don't have to repeat that code, can reuse it.

Resources