I am introducing a custom cell editor that can wrap around itself. However I once i introduce this component it does not call:
the valueSetter
the onCellValueChanged event listenre
and the onKeyDown inside the custom cell editor is also not registering the Enter
key.
Here are the components. Could somebody help? I tried many different methods from the props built in methods to even chat gpt a solution.
// src/components/FlashcardTable/FlashcardTable.js
import React, { useRef, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useParams } from 'react-router-dom';
import { AgGridReact } from 'ag-grid-react';
import { addRow, updateContent, selectCell } from 'src/store/features/decks/deckSlice';
import CustomTextEditor from 'src/components/FlashcardTable/CustomTextEditor';
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';
const FlashcardTable = React.forwardRef(({ deckId }, ref) => {
const dispatch = useDispatch();
const { id } = useParams();
const gridApi = useRef(null);
const columnApi = useRef(null);
const rowData = useSelector((state) => {
const deck = state.decks[id];
return deck ? deck.rows : [];
});
const columnDefs = [
{ headerName: '#', field: 'index', valueGetter: 'node.rowIndex + 1', width: 50, editable: false },
{
headerName: 'Question',
flex: 2,
field: 'question',
editable: true,
cellEditor: CustomTextEditor,
valueSetter: (params) => {
dispatch(updateContent({ id: deckId, rowIndex: params.node.rowIndex, field: 'question', content: params.newValue }));
return true;
}
},
{
headerName: 'Answer',
flex: 2,
field: 'answer',
editable: true,
cellEditor: CustomTextEditor,
valueSetter: (params) => {
dispatch(updateContent({ id: deckId, rowIndex: params.node.rowIndex, field: 'answer', content: params.newValue }));
return true;
}
},
];
const onCellValueChanged = async (event) => {
console.log('onCellValueChanged', event.rowIndex, event.column.getId());
const lastRow = rowData[rowData.length - 1];
if (lastRow && (lastRow.question.length > 0 || lastRow.answer.length > 0 || lastRow.topic)) {
await dispatch(addRow({ id: deckId, row: { question: '', answer: '', topic: '' } }));
}
// Focus on the selected cell
const { rowIndex, column } = event;
const colIndex = columnApi.current.getAllGridColumns().findIndex(col => col.getColId() === column.getColId());
let nextRowIndex = rowIndex;
let nextColIndex = colIndex + 1;
if (nextColIndex >= columnDefs.length) {
nextRowIndex = rowIndex + 1;
nextColIndex = 0;
}
const nextColumn = columnApi.current.getAllGridColumns()[nextColIndex];
setTimeout(() => {
gridApi.current.setFocusedCell(nextRowIndex, nextColumn.getColId());
gridApi.current.startEditingCell({ rowIndex: nextRowIndex, colKey: nextColumn.getColId() });
});
};
const onCellClicked = (event) => {
console.log('onCellClicked', event.rowIndex, event.column.getId())
if (event.colDef.editable) {
const { rowIndex, column } = event;
dispatch(selectCell({ id: deckId, rowIndex, colId: column.getId() }));
}
};
const onGridReady = (params) => {
gridApi.current = params.api;
columnApi.current = params.columnApi;
};
const defaultColDef = {
flex: 1,
editable: true,
cellDataType: false,
sortable: false,
autoHeight: true,
wrapText: true,
};
return (
<div className="ag-theme-alpine" style={{ height: 400, width: '100%' }}>
<AgGridReact
ref={ref}
rowData={rowData}
columnDefs={columnDefs}
onGridReady={onGridReady}
onCellValueChanged={onCellValueChanged}
onCellClicked={onCellClicked}
domLayout="autoHeight"
defaultColDef={defaultColDef}
rowSelection="single"
/>
</div>
);
});
export default FlashcardTable;
import React, { useRef, useEffect } from 'react';
const CustomTextEditor = (props) => {
console.log('props', props)
const inputRef = useRef(null);
const minHeight = 40;
useEffect(() => {
if (inputRef.current) {
inputRef.current.focus();
inputRef.current.value = props.value;
updateRowHeight();
console.log('Initial value:', inputRef.current.value);
}
}, [props.value]);
const updateRowHeight = () => {
if (inputRef.current) {
const rowHeight = Math.max(inputRef.current.scrollHeight, minHeight);
props.api.rowModel.getRow(props.rowIndex).setRowHeight(rowHeight);
props.api.onRowHeightChanged();
}
};
const handleKeyDown = (event) => {
if (event.key === 'Enter') {
event.stopPropagation();
props.stopEditing();
console.log('Final value on Enter:', inputRef.current.value);
}
};
const handleInputChange = () => {
updateRowHeight();
props.colDef.valueSetter()
};
return (
<textarea
ref={inputRef}
className="ag-input-field-input ag-text-field-input"
style={{ width: '100%', height: '100%', whiteSpace: 'pre-wrap', overflow: 'hidden', resize: 'none', minHeight: `${minHeight}px` }}
onKeyDown={handleKeyDown}
onChange={handleInputChange}
onBlur={() => props.stopEditing()}
/>
);
};
export default CustomTextEditor;
I tried the built in methods of the props inside the cellEditor custom components but no luck there. I tried to add event listeners and add cellEditorParams but also no luck there.