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 date cell editor component using Angular.
  • Use Angular Material's date picker component.

Before we create the component, let's look at the ICellEditorAngularComp interface that establishes the code contract between our custom component and AG Grid.

interface ICellEditorAngularComp {
  agInit(params: T): void;
  getValue(): any;
  isPopup?(): boolean;
}

Let's review each method:

  • agInit - invoked when the cell editor is created by AG Grid with the ICellEditorParams object.
  • getValue() - invoked once after editing is complete to provide the value to the grid.
  • isPopup() - optional to control the appearance of the editor as either inline or a popup.

Ok, let's create a custom cell editor using the Material date picker.

export class DateEditorComponent<T = any>
  implements ICellEditorAngularComp, AfterViewInit
{
  /** The form control for the datepicker input. */
  dateControl = new FormControl('');

  /** The Material datepicker component. */
  @ViewChild(MatDatepicker, { static: true })
  datepicker: MatDatepicker<Date>;

  /** The cell editor parameters. */
  private params: ICellEditorParams<T>;

  /** RxJS Subscription. */
  private subscription: Subscription;

  /** The datepicker value. */
  private value: Date;

  agInit(params: ICellEditorParams<T>): void {
    this.params = params;
    this.value = params.value;
    this.dateControl.setValue(params.value, { emitEvent: false });
  }

  ngOnInit(): void {
    this.subscription = this.dateControl.valueChanges.subscribe({
      error: console.error,
      next: (value) => {
        this.value = new Date(value);
        this.params.stopEditing();
      },
    });
  }

  ngAfterViewInit(): void {
    this.datepicker.open();
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }

  getValue(): any {
    return this.value;
  }
}

See example on Stackblitz

Let's review the class properties first:

  • dateControl - a FormControl for the date picker input.
  • datePicker - a reference to the MatDatePicker in the template. We'll use this to immediately open the date picker when the component is rendered.
  • params - a reference to the ICellEditorParams object.
  • subscription - a reference to an RxJS subscription.
  • value - the current Date value of the cell.

Now, let's review the class methods:

  • agInit - invoked by AG Grid when the cell editor is initialized with the provided ICellEditorParams object. We'll store a reference to the params and value, and also invoke the setValue() method on the FormControl instance.
  • ngOnInit - subscribe to the valueChanges Observable. We store the value and invoke the provided stopEditir() method using the Grid API to close the editor when a next notification is emitted
  • ngAfterviewInit - immediately open the date picker.
  • ngOnDestroy - unsubscribe from the RxJS subscription.
  • getValue - returns the value when editing is complete.

Registering the component

There are two choices for registering components.

  1. Provide the Class 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 class GridComponent {
  columnDefs = [
    {
      headerName: 'Date of Order',
      field: 'dateOfOrder',
      filter: 'agDateColumnFilter',
      editable: true,
      cellEditor: DateEditorComponent,
    },
  ] as ColDef<RowData>[];
}

Exercise

  1. Open the exercise on Stackblitz.
  2. Implement the agOnInit method, storing a reference to the params and setting the checked property based on the value provided.
  3. The onChange() method is invoked with the slide toggle value changes. In this method, set the checked property from the provided MatSlideToggleChange object. Use the provided stopEditing() Grid API method to stop the editing.
  4. Implement the getValue method.

Solution

@Component({
  standalone: true,
  imports: [AgGridModule, CommonModule, MatSlideToggleModule],
  template: `
    <mat-slide-toggle
      [checked]="checked"
      (change)="onChange($event)"
    ></mat-slide-toggle>
  `,
})
export class SlideToggleEditorComponent<T = any>
  implements ICellEditorAngularComp
{
  /** Boolean indicating if the slide toggle is on/off. */
  checked: boolean;

  /** The cell editor parameters. */
  private params: ICellEditorParams<T>;

  agInit(params: ICellEditorParams<T>): void {
    this.params = params;
    this.checked = params.value;
  }

  onChange(matSlideToggleChange: MatSlideToggleChange): void {
    this.checked = matSlideToggleChange.checked;
    this.params.stopEditing();
  }

  getValue(): any {
    return this.checked;
  }
}

See solution on Stackblitz