Iterating over a specific row of a react ag-grid - reactjs

I got an ag-grid with a button rendered in a dedicated column (meaning each row has a button on the side under that column). I've done it like this:
const columnDefinition = [
{headerName: '', cellRenderer: 'editButton'},
{headerName: "Key", field: "Key"},
{headerName: "Value", field: "Value"}];
const overlayParams = {
frameworkComponents: {
editButton: EditMagnifierButton, //EditMagnifierButton is a react functional component which renders a button
}
return (
<Ag-Grid-React
rowData={myRowData}
columnDefs={columnDefinition}
{...overlayParams} />
);
I want to know how to iterate over the row where the user clicked the button and get all the values in each column of the row so i can pass them as props to another component.
The EditMagnifierButton:
const EditMagnifier = (props) =>
{
return (
<IconButton iconSvg={search} />
)
}

As mentioned in ag-Grid docs, ag-Grid passes some default props to each cell-renderer and these props are in the format of ICellRendererParams,
interface ICellRendererParams {
value: any, // value to be rendered
valueFormatted: any, // value to be rendered formatted
getValue: () => any, // convenience function to get most recent up to date value
setValue: (value: any) => void, // convenience to set the value
formatValue: (value: any) => any, // convenience to format a value using the column's formatter
data: any, // the row's data
node: RowNode, // row node
colDef: ColDef, // the cell's column definition
column: Column, // the cell's column
rowIndex: number, // the current index of the row (this changes after filter and sort)
api: GridApi, // the grid API
eGridCell: HTMLElement, // the grid's cell, a DOM div element
eParentOfValue: HTMLElement, // the parent DOM item for the cell renderer, same as eGridCell unless using checkbox selection
columnApi: ColumnApi, // grid column API
context: any, // the grid's context
refreshCell: () => void // convenience function to refresh the cell
}
Detail can be found under,
https://www.ag-grid.com/javascript-grid-cell-rendering-components/#cell-renderer-component
So, there is one property called data which points to the rowData pointing to the index where the cell-renderer is present (in this case, the clicked one).
So your cell-renderer can use this prop directly as props.data,
/* Here the props will point to ICellRendererParams */
const EditMagnifier = (props) =>
{
const printRowData = (event) => {
/* This will give you the complete row data for the clicked row*/
console.log(props.data);
}
return (
<IconButton iconSvg={search} onClick={printRowData}/>
)
}

Related

Mui DataGrid > renderCell > useValue from renderCell

I have a field in the Datagrid with renderCell. The Value i have to display will be fetched inside the AlertIssues-Component as the original Data just provides the uuid to fetch the corresponding data (issue amount). So props.row._id is use in AlertIssues with a hook to retrieve the issues of the Alert in this row.
{
field: "issues",
type: "number",
headerClassName: "iconHeader",
// valueFormatter: params => {
// console.log("value formater",params )
// useGetIssueValue cannot be used here: (hook rules)
// let theValue = useGetIssueValue(params.id)
// return theValue
// },
// useGetIssueValue cannot be used here: (hook rules)
// valueGetter: params => useGetIssueValue(params.id)
renderCell: (props: GridRenderCellParams<Number>) => {
// useGetIssueValue is used inside AlertIssues
// and works to display the right amount
return(
<AlertIssues {...props} />
)},
},
export const AlertIssues = (props: GridRenderCellParams<Number>) => {
const { row } = props;
// i am getting my amount here without trouble.
// but it is just the displayed value ...
const alertIssueAmount = useGetIssueValue(row.id);
...
return <>alertIssueAmount</>
i tried to use "valueGetter" or "valueFormatter" to get the amount i need. but inside these functions i am not allowed to call my useData-hook, as they are functions and not React-Components or Hooks.
the row itself does not have the value i got inside of AlertIssues...
i am very lost here, how can i retrieve my issueAmount-value from the hook and use it in Datagrid? (e.g. for filter and sort)

How to know on which column the click event has happened in Antd Table?

I have an antd table in which I need to do some operations only when the click event happens on a specific column.
Currently, I am using the onRow prop in the table component as below
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
// some operations
},
};
}}
With this implementation, click is triggered for the entire row ( when clicked on any column )
I have tried to see the column dataIndex or key to return the click event only when the event has happened on a specific column. But args of onRow do not have that data.
Is there a way to achieve the required behavior?
If I understand correctly you want to create a table with editable row. I would suggest to create a new column (e.g. Actions) in which you will have a button that when you click it, it will let you edit the row you want. Check the following link, hope it's what you are looking for:
https://codesandbox.io/s/editable-rows-antd-4-20-6-forked-hvul4u?file=/demo.js
If you are looking to capture click events for a specific column, you can use the onCell property for column. (Codesandbox)
const columns = [
{
title: "Name",
dataIndex: "name",
render: (text, row, index) => <a>{text}</a>,
onCell: (record, rowIndex) => {
return {
onClick: () => {
console.log(record, rowIndex);
}
};
}
},
...
]

How to handle multiple checkboxes in React form?

I have a form that loads preset checkbox selections from the backend. I query the checkbox menu and iterate over it in JSX. Now I want to be able to select/deselect. To handle this, I start out by creating an array of objects matching the size of menu checkbox items like so:
useEffect(() => {
if (!profile) { // this checks if the reusable form is a create or update. If this is an update, I need to prefill an existing array of objects with added key/value pair of checked: true
setConcerns(Array(menuItems.length).fill({ checked: false }))
}
}, [menuItems]) // this happens first
// if it's an update form
useEffect(() => {
if (profile) {
const updatedConcerns = existingConcerns.map((c, i) => ({
...concerns,
c.id: c.id,
checked: true,
}))
}
}, [existingConcerns]) // this happens second
This sets up the concerns array for toggle.
In my JSX I have a Checkbox component:
{menuItems &&
menuItems.map((item: CheckboxProps, index: number) => (
<Checkbox
testID={item?.title}
label={item?.title}
checked={concerns && !!concerns[index]?.checked}
onValueChange={() => handleConcerns(index)}
/>
))}
And the handleConcerns method so far:
const handleConcerns = (index: number) => {
const concernsCopy = [...concerns]
concernsCopy[index].checked = !concernsCopy[index].checked
setConcerns(concernsCopy)
// the rest will determine how to add selected items to concerns
array for submit
}
This causes all of the checkboxes to toggle. This is just the start of pushing menu data into each index of concerns array but first need to get the checkboxes working and be able to have an array of chosen indices to submit to backend.

How to trigger a cell change from within a component to update the grid data? (AG Grid - React)

I have a dropdown component within an Ag Grid. But when I change the value, the client-side data object doesn't change.
I'm triggering a function within the component when the dropdown is changed - but how can I tell the "parent" AG Grid to update it's data for that cell? (AG Grid automatically updates it's data when you're just changing text directly in a cell, not using a custom component.)
It seems to have something to do with using getValue(), but I can't seem to find the proper call in the documentation.
Are you using a Cell Renderer or Cell Editor to build the dropdown component?
If using a Custom Cell Editor, you must implement the getValue method otherwise the grid will not insert the new value into the row after editing is done.
See this implemented here:
const CustomCellEditor = forwardRef((props, ref) => {
const [selectedValue, setSelectedValue] = useState('United States');
const values = ['United States', 'Russia', 'Canada'];
/* Component Editor Lifecycle methods */
useImperativeHandle(ref, () => {
return {
getValue() {
return selectedValue;
},
};
});
const onChangeHandler = (event) => {
setSelectedValue(event.target.value);
};
return (
<div>
<select value={selectedValue} onChange={onChangeHandler}>
{values.map((item) => (
<option>{item}</option>
))}
</select>
</div>
);
});
Plunkr example
Documentation on Custom Cell Editors

Antd: Is it possible to move the table row expander inside one of the cells?

I have an antd table where the data inside one of the columns can get pretty large. I am showing this data in full when the row is expanded but because the cell with a lot of data is on the right side of the screen and the expander icon is on the left side of the screen it is not very intuitive. What I would like to do is move the expander icon inside the actual cell so that the user knows they can click the + to see the rest of the data.
Thanks in advance.
Yes, you can and you have to dig a little deeper their docucmentation...
According to rc-table docs you can use expandIconColumnIndex for the index column you want to add the +, also you have to add expandIconAsCell={false} to make it render as part of the cell.
See Demo
This is how you can make any column expendable.
First add expandedRowKeys in your component state
state = {
expandedRowKeys: [],
};
Then you need to add these two functions onExpand and updateExpandedRowKeys
<Table
id="table-container"
rowKey={record => record.rowKey}
className={styles['quote-summary-table']}
pagination={false}
onExpand={this.onExpand}
expandedRowKeys={this.state.expandedRowKeys}
columns={columns({
updateExpandedRowKeys: this.updateExpandedRowKeys,
})
}
dataSource={this.data}
oldTable={false}
/>
This is how you need to define the function so
that in expandedRowKeys we will always have
updates values of expanded rowKeys
onExpand = (expanded, record) => {
this.updateExpandedRowKeys({ record });
};
updateExpandedRowKeys = ({ record }) => {
const rowKey = record.rowKey;
const isExpanded = this.state.expandedRowKeys.find(key => key === rowKey);
let expandedRowKeys = [];
if (isExpanded) {
expandedRowKeys = expandedRowKeys.reduce((acc, key) => {
if (key !== rowKey) acc.push(key);
return acc;
}, []);
} else {
expandedRowKeys.push(rowKey);
}
this.setState({
expandedRowKeys,
});
}
And finally, you need to call the function updateExpandedRowKeys
for whichever column you want to have the expand-collapse functionality available.
Even it can be implemented for multiple columns.
export const columns = ({
updateExpandedRowKeys,
}) => {
let columnArr = [
{
title: 'Product',
key: 'productDes',
dataIndex: 'productDes',
className: 'productDes',
render: (text, record) => (
<span onClick={rowKey => updateExpandedRowKeys({ record })}>
{text}
</span>
),
}, {
title: 'Product Cat',
key: 'productCat',
dataIndex: 'productCat',
className: 'product-Cat',
}]
}

Resources