Cell Editor Component
Custom Cell Editor Component
- The provided cell editors are adequate
- But, we can build custom cell editors to meet the user requirements of our applications
- We can leverage a framework such as React, Angular, or Vue.
Goals:
- Build a custom color cell editor component using React.
- Use the browser's built-in color input.
Before we create the component, let's look at the imperative API interface that establishes the code contract between our custom component and AG Grid.
interface ICellEditor {
getValue(): any;
}
The getValue()
method is invoked once after editing is complete to provide the value to the grid.
Establishing communication with Ag Grid requires us to setup an imperative handler from the ref forwarded by Ag Grid:
const ColorEditor = forwardRef<ICellEditor, ICellEditorParams>((props, ref) => {
const [value, setValue] = useState(props.value);
useImperativeHandle(ref, () => ({
getValue: () => value,
}));
return (
<input
type="color"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
});
Ok, let's create a custom cell editor using the browser's color picker:
const ColorEditor = forwardRef<ICellEditor, ICellEditorParams>((props, ref) => {
const [value, setValue] = useState(props.value);
const inputRef = useRef<HTMLInputElement>(null);
useImperativeHandle(ref, () => ({
getValue: () => value,
}));
useEffect(() => {
if (inputRef.current) inputRef.current.focus();
}, []);
return (
<input
ref={inputRef}
type="color"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
});
Let's review the what each hook is doing:
useState
- Contains the value of our cell editor.useRef
- Set up a ref to the color input so that we can focus the input when the cell editor is opened.useImperativeHandler
- Sets up callback functions to communicate with Ag Grid. ImplementinggetValue
is required to send the value back to Ag Grid after the editor has been closed.useEffect
- Focus the input when the cell editor is opened.
Registering the component
There are two choices for registering components.
- Provide the component reference in the column definition
- Register the component using a string constant. This provides the benefit of serialization of the column definition.
Finally, let's register and use the custom DateEditorComponent
.
export default function Grid() {
const [columnDefs] = useState<ColDef<RowData>[]>([
{
headerName: 'Color',
field: 'color',
cellRenderer: ColorRenderer,
editable: true,
cellEditor: ColorEditor,
},
]);
}
Exercise
- Open the exercise on Stackblitz.
- Implement the
useState
hook to capture the initial value from the props - Implement the
getValue()
method in the imperative handle to return the value captured by theuseState
hook - Update the column definition for the Color field to be editable, using the ColorEditor as the column editor
Solution
const ColorEditor = forwardRef<ICellEditor, ICellEditorParams>((props, ref) => {
const [value, setValue] = useState(props.value);
const inputRef = useRef<HTMLInputElement>(null);
useImperativeHandle(ref, () => ({
getValue: () => value,
}));
useEffect(() => {
if (inputRef.current) inputRef.current.focus();
}, []);
return (
<input
ref={inputRef}
type="color"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
});