LiveLoveApp logo

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)}
    />
  );
});

See example on Stackblitz

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. Implementing getValue 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.

  1. Provide the component reference in the column definition
  2. 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

  1. Open the exercise on Stackblitz.
  2. Implement the useState hook to capture the initial value from the props
  3. Implement the getValue() method in the imperative handle to return the value captured by the useState hook
  4. 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)}
    />
  );
});

See solution on Stackblitz