Grid Cascading Cell Editors

Grid for Angular

Angular standalone version of this topic (compatible with Angular 17+). Import both the Smart UI component and module in the standalone component.

What this topic covers: practical setup, the framework-specific API access pattern, and copy-adapt guidance for the examples in this page.

import { Component, ViewChild, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { GridComponent, GridModule } from 'smart-webcomponents-angular/grid';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, GridModule, RouterOutlet],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  encapsulation: ViewEncapsulation.None
})
export class AppComponent {
  @ViewChild('grid', { read: GridComponent, static: false }) grid!: GridComponent;
}
<!-- app.component.html -->
<smart-grid #grid></smart-grid>

Use this.grid for API methods in this topic.

Cascading Cell Editors in Grid

Cascading Cell Editors can be implemented in Smart.Grid in order to make the available options for cell values in one column dependent on the already selected cell value of another column on the same row.

In this help topic, we will set up a Grid with two columns - "Country" and "City". When a country is selected from a drop down list of available options, the available cities in the second column's drop down change accordingly, thus creating a cascading effect. To achieve cascading editing, both columns have to have custom editors implemented.

Below you can find the TypeScript source code that sets up the Grid and implements cascading editing. We will look at each major part of it in detail afterwards.

componentProps = {
            // STEP (1)
            dataSource: new window.Smart.DataAdapter(
                {
                    dataSource: data,
                    dataFields:
                        [
                            'Country: string',
                            'City: string'
                        ]
                }),
            // STEP (1)
            editing: {
                enabled: true,
                mode: 'cell'
            },
            columns: [
                // STEP (2)
                {
                    label: 'Country', dataField: 'Country', editor: {
                        template: '<smart-drop-down-list></smart-drop-down-list>',
                        onInit(row: number, column: string, editor: HTMLElement) {
                            const dropDownList = (editor.firstElementChild as DropDownList);

                            dropDownList.dataSource = ['Belgium', 'France', 'USA', 'Lebanon'];
                            dropDownList.dropDownAppendTo = 'body';
                            dropDownList.selectedValues = [grid.rows![row].cells![0].value];

                            dropDownList.addEventListener('change', function () {
                                change = true;
                            });
                        },
                        onRender(row: number, column: string, editor: HTMLElement) {
                            (editor.firstElementChild as DropDownList).selectedValues = [grid.rows![row].cells![0].value];
                        },
                        getValue() {
                            return ((this as any).firstElementChild as DropDownList).selectedValues![0];
                        }
                    }
                },
                // STEP (3)
                {
                    label: 'City', dataField: 'City', editor: {
                        template: '<smart-drop-down-list></smart-drop-down-list>',
                        onInit(row: number, column: string, editor: HTMLElement) {
                            const dropDownList = (editor.firstElementChild as DropDownList);

                            dropDownList.dropDownAppendTo = 'body';
                            dropDownList.placeholder = 'Select a city...';
                        },
                        onRender(row: number, column: string, editor: HTMLElement) {
                            const countryValue: string = grid.rows![row].cells![0].value,
                                citiesSource: string[] = cities[countryValue],
                                dropDownList = (editor.firstElementChild as DropDownList);

                            dropDownList.dataSource = citiesSource;
                            dropDownList.selectedValues = [grid.rows![row].cells![1].value];
                        },
                        getValue() {
                            return ((this as any).firstElementChild as DropDownList).selectedValues![0] || 'Select a city...';
                        }
                    }
                }
            ]
        };

// app.component.html
// <smart-grid #grid [dataSource]="componentProps.dataSource" [columns]="componentProps.columns"></smart-grid>

Step (1)

The Grid is bound to a static data source (data), that comprises the initial view, by setting the dataSource property. Cell editing is enabled by setting editing enabled to true and mode to 'cell'.

Step (2)

The first column in the columns array ("Country") has a custom cell editor with the following fields:

  • template - denotes that the editor to be used is the Smart custom element DropDownList (smart-drop-down-list).
  • onInit - called the first time a cell from the column is edited and the editor is initialized. Here, we set the available countries as data source of the drop down list and select the initial value. We also denote that the drop down is appended to the document's body (dropDownList.dropDownAppendTo = 'body'). Finally, we bind to the editor's change event in order to set a flag when an actual change to the selected country occurs (to be used in Step (4)).
  • onRender - called each time a cell is edited. Here, the current cell value is selected in the editor when an edit operation begins.
  • getValue - called when the edit operation ends. In this callback function, the editor's selected value is applied as a cell value of the Grid.

Step (3)

The second column in the columns array ("City") also has a custom cell editor with the same fields:

  • template - denotes that the editor to be used is the Smart custom element DropDownList (smart-drop-down-list).
  • onInit - called the first time a cell from the column is edited and the editor is initialized. Here, we denote that the drop down is appended to the document's body (dropDownList.dropDownAppendTo = 'body') and set the placeholder of the drop down list to "Select a city..." - it will be displayed when a country is changed and a respective city has to be selected.
  • onRender - called each time a cell is edited. Here, a data source with cities based on the country selected in the first column is applied. If the cell value is an applicable city, it is also selected in the drop down list.
  • getValue - called when the edit operation ends. In this callback function, the editor's selected value is applied as a cell value of the Grid. If a city has not been chosen yet, the cell value is "Select a city...".

Step (4)

We bind to the Grid's endEdit event and when a change to the "Country" column has occurred and reset the value of the respective "City" cell to "Select a city..." in order to prompt the user to select a city from the newly chosen country.

Result

A live version of the code presented in this tutorial can be found in the demo Grid Cascading Cell Editors. Here is what the application looks like when launched.

For AI tooling

Developer Quick Reference

Topic: grid-cascading-cell-editors   Component: Grid   Framework: Angular

Main methods: (none detected)

Common config keys: dataSource, editing, columns

Implementation Notes

Compatibility: Angular 17+ (standalone)   API access pattern: @ViewChild(...) + this.component.method()

Lifecycle guidance: Bind inputs declaratively and call imperative API through @ViewChild in/after ngAfterViewInit.

Common pitfalls:

  • Using @ViewChild API too early (before view init).
  • Omitting standalone imports for Smart modules in @Component.imports.
  • Type mismatches between configuration fields and template bindings.

Validation checklist:

  • Ensure module import exists in standalone component imports array.
  • Use typed @ViewChild(..., { read: ComponentType }).
  • Call imperative methods after view initialization.