I'm facing an issue while keeping a row focused/selected in AG Grid. I'm expecting it to be highlighted/selected even after I do certain actions like API calls, Does anyone know what is the fix?
This is my AGGridComponent
<CustomAgGrid
ref={gridRef}
animateRows={false}
filter={false}
className="ag-theme-balham charity-grid"
columnDefs={[
{
field: 'num',
headerName: 'Num',
width: 58, //53 + 17
},
{
field: 'campaignName',
headerName: 'Campaign Name',
width: 151,
},
{
field: 'description',
headerName: 'Description',
width: 140,
},
{
field: 'isActive',
headerName: 'Status',
width: 110, //53 + 17
cellRenderer: 'StatusIndicator',
},
]}
detailCellRenderer=""
frameworkComponents={{
exceptionMessage: function noRefCheck() {},
StatusIndicator: StatusIndicator,
}}
masterDetail={false}
noRowsOverlayComponent=""
noRowsOverlayComponentParams={{
messageHeader: '',
messageInfo: ['No data to display'],
messageType: 'info',
}}
rowData={campaignDataClone}
context={{ gridApi }}
rowSelection="single"
onGridReady={onGridReady}
onSelectionChanged={onSelectionChanged}
onFirstDataRendered={onFirstDataRendered}
/>
These are grid event handler
const onGridReady = params => {
params.api.sizeColumnsToFit();
window.addEventListener('resize', function() {
setTimeout(function() {
params.api.sizeColumnsToFit();
});
});
gridRef.current.api.sizeColumnsToFit();
setGridApi(params.api);
};
const onFirstDataRendered = () => {
const rows = gridRef.current.api.clientSideRowModel.rowsToDisplay;
if(rows?.length){
rows[0].setSelected(true);
setGridLoaded(true)
}
};
This is how i dispatch actions to perform an API request
buttons={[
{
buttonLabel: 'No - Go Back',
className: `btn-secondary btn-lg btn-block`,
onClick: () => {
toggleCampaignStatusConfirm(false);
const selectedRows = gridRef.current.api.getSelectedRows();
toggleCampaignEnable(selectedRows[0]?.isActive ? 'first_toggle' : 'second_toggle');
},
},
{
buttonLabel: `${isActive ? 'Yes - Disable' : 'Yes - Enable'}`,
className: `${isActive ? 'btn-danger' : 'btn-success'} btn-lg btn-block`,
onClick: () => {
toggleCampaignStatusConfirm(false);
dispatch(changeCampaignStatus(selectedCampaign?.campaignId, !isActive));
},
},
]}
Once the API requests are done it just updates the redux and the component will be rendered. Here I'm expecting it to maintain the focus and the row should be selected. Can anyone please help me with how to achieve/fix this?
Related
Im trying to update the value of the status or role of the user through the datagrid mui and save the changes by the save button, the id is passed, but the values of the status and role fields are passed as undefined. What am I doing wrong?
data grid columns with onClick function
const columns = [
{ field: "id", headerName: "No", width: 100 },
{ field: "name", headerName: "Name", width: 200 },
{ field: "email", headerName: "Email", width: 200 },
{ field: "createdAt", headerName: "Created At", width: 200 },
{ field: "updatedAt", headerName: "Updated At", width: 200 },
{ field: "role", headerName: "Role", width: 130, type: "singleSelect", valueOptions: ["user", "admin"], editable: true },
{ field: "status", headerName: "Status", width: 130, type: "boolean", editable: true },
{
headerName: "Action",
field: "action",
width: 100,
renderCell: (rowData) => (
<Button variant="contained" color="primary" onClick={() => updateStatusAndRole(rowData.id, rowData.status, rowData.role)}>
Save
</Button>
),
},
];
function
const updateStatusAndRole = async (id, newStatus, newRole) => {
try {
const response = await axios.put(`http://localhost:5000/users/${id}/updateStatusAndRole`, {
role: newRole,
status: newStatus,
});
getUsers();
return response.data;
} catch (error) {
throw error;
}
};
The renderCell function doesn't get the row data as a parameter but a ### object. To access the row data, use its row property, like this:
renderCell: (params) => (
<Button variant="contained" color="primary" onClick={() => updateStatusAndRole(params.row.id, params.row.status, params.row.role)}>
Save
</Button>
)
I am using CoreUI React Smart Table, I cannot seem to figure out how to put the filter on certain columns only.
I want it to look like this:
Screenshot
The documentation is here, but it does not really seem to show how:
https://coreui.io/react/docs/components/smart-table/
Any help would be really appreciated.
Here is my code:
import React, { useState } from 'react'
import { CCardBody, CButton, CSmartTable } from '#coreui/react-pro'
import data from './_data.js'
const SmartTableDownloadableExample = () => {
const [currentItems, setCurrentItems] = useState(data)
const csvContent = currentItems.map((item) => Object.values(item).join(',')).join('\n')
const csvCode = 'data:text/csv;charset=utf-8,SEP=,%0A' + encodeURIComponent(csvContent)
return (
<CCardBody>
<CButton
color="primary"
className="mb-2"
href={csvCode}
download="coreui-table-data.csv"
target="_blank"
>
Download current items (.csv)
</CButton>
<CSmartTable
columnFilter={{ column: 'id' }}
columnSorter
items={data}
itemsPerPage={5}
onFilteredItemsChange={setCurrentItems}
pagination
/>
</CCardBody>
)
}
export default SmartTableDownloadableExample
I figured it out:
You need to add an columns object:
const columns = [
{
key: 'name',
_style: { width: '40%' },
_props: { color: 'primary', className: 'fw-semibold' },
},
'registered',
{ key: 'role', filter: false, sorter: false, _style: { width: '20%' } },
{ key: 'status', _style: { width: '20%' } },
{
key: 'show_details',
label: '',
_style: { width: '1%' },
filter: false,
sorter: false,
_props: { color: 'primary', className: 'fw-semibold' },
},
]
Then in the CSmartTable:
<CSmartTable
**columns={columns}**
columnFilter
columnSorter
items={data}
itemsPerPage={5}
onFilteredItemsChange={setCurrentItems}
pagination
/>
As per:
https://coreui.io/react/docs/components/smart-table/
I created table with ant design ProTable Component and its Edit function is not working. It showing error like this. ("Cannot read properties of undefined (reading 'toString')"). I tried many ways to solve this problem and cannot found a solution yet.
I want get table data from CSV file upload. That function is already working and data retrieved to the table.
const columns = [
{
title: 'First Name',
valueType: 'string',
typeof:'string',
dataIndex: 'fName',
formItemProps: () => {
return {
rules: [{ required: true, message: '' }],
};
},
},
{
title: 'Last Name',
valueType: 'string',
typeof:'string',
dataIndex: 'lName',
formItemProps: () => {
return {
rules: [{ required: true, message: '' }],
};
},
},
{
title: 'Email',
valueType: 'string',
typeof:'string',
dataIndex: 'email',
formItemProps: () => {
return {
rules: [{ required: true, message: '' }],
};
},
},
{
title: 'Position',
valueType: 'string',
typeof:'string',
dataIndex: 'position',
formItemProps: () => {
return {
rules: [{ required: true, message: '' }],
};
},
},
{
title: 'Actions',
valueType: 'option',
width: 200,
render: (text, record, _, action) => [
<a
key="delete"
onClick={() => {
setData(data.filter((item) => item.id !== record.id));
}}
>
Delete
</a>,
<a
key="editable"
onClick={() => {
var _a;
(_a = action === null || action === void 0 ? void 0 : action.startEditable) === null ||
_a === void 0
? void 0
: _a.call(action, record.id);
}}
>
Edit
</a>,
],
},
];
EditableProTable
rowKey="id"
actionRef={actionRef}
headerTitle=""
maxLength={5}
recordCreatorProps={false}
columns={columns}
request={async () => ({
data: data,
total: 3,
success: true,
})}
value={csvArray}
onChange={setCsvArray}
editable={{
type: 'multiple',
editableKeys,
onSave: async (rowKey, data, row) => {
await waitTime(2000);
},
onChange: setEditableRowKeys,
actionRender: (row, config, defaultDom) => [
defaultDom.save,
defaultDom.delete || defaultDom.cancel,
],
}}
/>[![enter image description here][1]][1]
The editableKeys array contains rows that are in the editing state
const [editableKeys, setEditableRowKeys] = useState(() => csvArray.map((item) => item.index)); // or .map((item=) => item.key));
Hi i'm new to ReactJS and i'm using it with ReactDataGrid, and i can't understand how can i change only the real dom value of a cell.
I have the following table:
And i want to change the price, instead of "3000000000" to "300M".
I have the JS function to perform this, but i can't apply it to the directly to ReactObject otherwise i will not be able to sort or filter, so i think the only way would be to only edit the RealDOM.
Following the documentation on the ReactDataGrid, i can access the ReactNode by using renderRow. But i don't know how to change the real dom in order to display the formated number.
Code:
const columns = [
//{ name: 'shop_vid', header: 'shop_vid', minWidth: 1, defaultFlex: 2 },
{ name: 'name', header: 'Name', minWidth: 10, defaultFlex: 2 },
{ name: 'price', header: 'Price', minWidth: 10, defaultFlex: 2 },
]
const filterValue = [
{ name: 'name', operator: 'contains', type: 'string', value: '' },
{ name: 'price', operator: 'gte', type: 'number', value: 0 },
];
const gridStyle = { minHeight: 550 }
const renderRow = ({ data, style }) => {
const { price } = data
//formatNumber(price)
}
class ItemsTable extends Component {
render() {
return (
<ReactDataGrid
idProperty="shop_vid"
pagination
defaultFilterValue={filterValue}
columns={columns}
dataSource={this.state.items}
style={gridStyle}
renderRow={renderRow}
defaultLimit={10}
/>
);
}
}
export default ItemsTable;
Thanks in Advance.
After diging more i found a solution.
ReactDataGrid allows to apply a render function on the columns list. So i just changed the props of the price column.
const columns = [
{ name: 'name', header: 'Name', minWidth: 10, defaultFlex: 2 },
{
name: 'price',
header: 'Price',
minWidth: 10,
type: 'number',
defaultFlex: 2,
render: ({ value }) => {
return convertValue(value);
}
}
]
Where value is the value of the cell and "convertValue" returns the formated number.
Currently I have created a component that wraps BootstrapTable. I have to define a constant that represents the columns of data. But, the way I have it right now seems to really clutter up my render method. I'd like to move it to its own file, but I'm not sure the best way to do this, because it requires callbacks that are defined in the class (notably the onUpdateClicked method).
If the way I have it is a fine way of doing things, that would be good to know. But, assuming I did want to move it to another file regardless, suggestions would be appreciated for my own edification. Thanks!
class MyTable extends Component {
onUpdateClicked() {
//do stuff
}
render() {
let {data} = {...this.props}
let columns = [
{
dataField: 'badge',
text: 'Badge',
sort: true
}, {
dataField: 'firstName',
text: 'First',
sort: true
}, {
dataField: 'lastName',
text: 'Last',
sort: true
}, {
dataField: 'email',
text: 'Email',
sort: true
}, {
dataField: 'loggedIn',
text: 'Logged In',
sort: true,
formatter: (cell, row) => {
if (row.loggedIn) {
return (<FontAwesomeIcon icon="check"/>)
}
}
}, {
dataField: 'update',
text: 'Update',
formatter: () => {
return (<Button onClick={this.onUpdateClicked} color="primary">Update</Button>)
}
},
];
return (
<div>
<BootstrapTable Bootstrap4 keyField='badge' data={data} columns={columns}/>
</div>
)
}
}
you can put the columns in a seperate file, but export a function that takes a function as a parameter to be used for the onClick
Columns.js
const columnsFn = someFunc => ([ // pass the function as a param.
{
dataField: 'badge',
text: 'Badge',
sort: true
}, {
dataField: 'firstName',
text: 'First',
sort: true
}, {
dataField: 'lastName',
text: 'Last',
sort: true
}, {
dataField: 'email',
text: 'Email',
sort: true
}, {
dataField: 'loggedIn',
text: 'Logged In',
sort: true,
formatter: (cell, row) => {
if (row.loggedIn) {
return (<FontAwesomeIcon icon="check"/>)
}
}
}, {
dataField: 'update',
text: 'Update',
formatter: () => {
return (<Button onClick={someFunc} color="primary">Update</Button>) // use it here
}
},
]);
export default columnsFn;
YourFile.js
import columnsFn from './columns';
class MyTable extends Component {
onUpdateClicked() {
//do stuff
}
render() {
const {data} = {...this.props}
const myColumns = columnsFn(this.onUpdateClicked); // pass the function here
return (
<div>
<BootstrapTable Bootstrap4 keyField='badge' data={data} columns={myColumns}/>
</div>
)
}
}