New to Kendo UI for AngularStart a free 30-day trial

Angular TreeList Inline Editing

Updated on Jun 11, 2026

The inline editing mode in the Angular TreeList allows users to click an Edit command button to switch an entire row into edit mode. This type of editing is suitable when you want to edit all cells of a given row in a single transaction.

The TreeList offers flexible options for implementing inline editing—from quick setup with built-in directives that handle the operations automatically, to manual implementation for scenarios requiring complete control over the editing process.

The following example demonstrates the quick setup for implementing inline editing using Reactive Forms.

Change Theme
Theme
Loading ...

Quick Setup

The TreeList's built-in editing directives provide the fastest and most straightforward way to implement inline editing. These directives handle all the necessary TreeList events automatically, reducing boilerplate code and providing a clean, maintainable solution that integrates seamlessly with Angular Forms.

Based on your preferred Angular Forms methodology, you can choose from the following built-in approaches:

Using Reactive Forms

The kendoTreeListReactiveEditing directive simplifies the setup when implementing an editable TreeList with Reactive Forms. This directive handles all the necessary TreeList events internally, reducing repetitive code and providing a cleaner, more maintainable solution.

To configure the TreeList with the ReactiveEditingDirective:

  1. Provide a callback which returns the FormGroup for the edited item.

    html
    <kendo-treelist [kendoTreeListReactiveEditing]="createFormGroup">
        ...
    </kendo-treelist>
  2. In the custom createFormGroup callback, create and return the FormGroup for the row model. For the newly added rows, create a new instance of the model.

    ts
    public formGroup: FormGroup;
    
    constructor() {
        this.createFormGroup = this.createFormGroup.bind(this);
    }
    
    public createFormGroup({ isNew, dataItem }: CreateFormGroupArgs): FormGroup {
        const item = isNew ? {} : dataItem;
    
        this.formGroup = new FormGroup({
            id: new FormControl(item.id),
            parentId: new FormControl(item.parentId),
            name: new FormControl(item.name, Validators.required),
            role: new FormControl(item.role),
        });
    
        return this.formGroup;
    }
  3. Use the built-in command directives to create buttons that automatically perform the desired CRUD operations. For more details, refer to the Editing Action Buttons section.

Using Template-Driven Forms

The kendoTreeListTemplateEditing directive simplifies the setup when implementing an editable TreeList with Template-Driven Forms. Like the reactive editing directive, it handles the necessary TreeList events internally and reduces boilerplate code.

The following example demonstrates the kendoTreeListTemplateEditing directive in action.

Change Theme
Theme
Loading ...

To configure the TreeList with the TemplateEditingDirective:

  1. Use the EditTemplateDirective of the TreeList to display any custom control when the row is in edit mode. Bind the ngModel directive of the custom control to the corresponding value by using the dataItem field provided by the template context.

    html
    <kendo-treelist-column [expandable]="true" field="name" title="Name">
        <ng-template kendoTreeListEditTemplate let-dataItem="dataItem">
            <kendo-textbox [(ngModel)]="dataItem.name" name="name" required></kendo-textbox>
        </ng-template>
    </kendo-treelist-column>
  2. Provide a function that creates a new instance of the edited model.

    html
    <form novalidate #myForm="ngForm">
        <kendo-treelist [kendoTreeListTemplateEditing]="createNewItem">
            ...
        </kendo-treelist>
    </form>
  3. Use the built-in command directives to create buttons that automatically perform the desired CRUD operations. For more details, refer to the Editing Action Buttons section.

Manual Setup

For scenarios requiring full control over the editing behavior, you can manually handle the editing operations. This approach gives you complete flexibility but requires more code to implement.

Built-In Directives vs. Manual Setup

The TreeList provides built-in editing directives that significantly reduce the amount of boilerplate code required for implementing inline editing. Consider using the Reactive Editing Directive or Template Editing Directive before implementing the manual setup.

The manual implementation uses either Angular Reactive Forms or Template-Driven Forms. This gives you the choice between two approaches:

Using Reactive Forms

The following example demonstrates how to manually implement inline editing with Reactive Forms.

Change Theme
Theme
Loading ...

To enable the editing mode of the TreeList with Reactive Forms:

  1. Configure the type of the column editor. The default editor created by the TreeList is the text editor. To change this behavior, set the editor property.

    html
    <!-- setting numeric editor -->
    <kendo-treelist-column field="Extension" title="Extension" editor="numeric">
    </kendo-treelist-column>
  2. Configure the command column by defining the command buttons inside the command column template.

    html
    <kendo-treelist-command-column width="140">
        <ng-template kendoTreeListCellTemplate let-isNew="isNew" let-cellContext="cellContext">
            <button [kendoTreeListAddCommand]="cellContext" [svgIcon]="addExpressionIcon" title="Add Child"></button>
            <button [kendoTreeListEditCommand]="cellContext" [svgIcon]="pencilIcon" title="Edit" [primary]="true"></button>
            <button [kendoTreeListRemoveCommand]="cellContext" [svgIcon]="trashIcon" title="Remove"></button>
            <button [kendoTreeListSaveCommand]="cellContext" [disabled]="formGroup?.invalid" [svgIcon]="saveIcon" title="{{ isNew ? 'Add' : 'Update' }}"></button>
            <button [kendoTreeListCancelCommand]="cellContext" [svgIcon]="cancelIcon" title="{{ isNew ? 'Discard changes' : 'Cancel' }}"></button>
        </ng-template>
    </kendo-treelist-command-column>
  3. Attach handlers for the CRUD data operations. When a command button is clicked, the TreeList emits the corresponding event.

    html
    <kendo-treelist
        [data]="view | async"
        (add)="addHandler($event)"
        (edit)="editHandler($event)"
        (remove)="removeHandler($event)"
        (save)="saveHandler($event)"
        (cancel)="cancelHandler($event)"
    >
    </kendo-treelist>

Adding Records

The add event fires when kendoTreeListAddCommand is clicked. Inside the event handler, show the new row editor by calling addRow with a FormGroup configuration.

ts
public addHandler({ sender, parent }: AddEvent): void {
    this.closeEditor(sender);

    if (parent) {
        sender.expand(parent);
    }

    this.formGroup = new FormGroup({
        'ReportsTo': new FormControl(parent ? parent.EmployeeId : null),
        'FirstName': new FormControl('', Validators.required),
        'LastName': new FormControl('', Validators.required),
        'Position': new FormControl(''),
        'Extension': new FormControl('', Validators.compose([Validators.required, Validators.min(0)]))
    });

    sender.addRow(this.formGroup, parent);
}

Editing Records

The edit event fires when kendoTreeListEditCommand is clicked. Inside the event handler, put the row in edit mode by calling editRow with a FormGroup configuration.

ts
public editHandler({ sender, dataItem }: EditEvent): void {
    this.closeEditor(sender, dataItem);

    this.formGroup = new FormGroup({
        'EmployeeId': new FormControl(dataItem.EmployeeId),
        'ReportsTo': new FormControl(dataItem.ReportsTo),
        'FirstName': new FormControl(dataItem.FirstName, Validators.required),
        'LastName': new FormControl(dataItem.LastName, Validators.required),
        'Position': new FormControl(dataItem.Position),
        'Extension': new FormControl(dataItem.Extension, Validators.compose([Validators.required, Validators.min(0)]))
    });

    this.editedItem = dataItem;
    sender.editRow(dataItem, this.formGroup);
}

Removing Records

The remove event fires when kendoTreeListRemoveCommand is clicked. Inside the event handler, issue a request to remove the data item and invoke reload to reflect the changes.

ts
public removeHandler({ sender, dataItem, parent }: RemoveEvent): void {
    this.editService.remove(dataItem, parent).pipe(take(1)).subscribe(() => {
        if (parent) {
            sender.reload(parent);
        }
    });
}

Saving Records

The save event fires when kendoTreeListSaveCommand is clicked. Update the data source and call closeRow to return the row to view mode.

ts
public saveHandler({ sender, dataItem, parent, formGroup, isNew }: SaveEvent): void {
    const employee = formGroup.value;

    if (!isNew) {
        Object.assign(dataItem, employee);
    }

    this.editService.save(employee, parent, isNew).pipe(take(1)).subscribe(() => {
        if (parent) {
            sender.reload(parent);
        }
    });

    sender.closeRow(dataItem, isNew);
}

Cancelling Editing

The cancel event fires when kendoTreeListCancelCommand is clicked. Switch the row back to view mode by calling closeRow.

ts
public cancelHandler({ sender, dataItem, isNew }: CancelEvent): void {
    this.closeEditor(sender, dataItem, isNew);
}

private closeEditor(treelist: TreeListComponent, dataItem: any = this.editedItem, isNew: boolean = false): void {
    treelist.closeRow(dataItem, isNew);
    this.editedItem = undefined;
    this.formGroup = undefined;
}

Using Template-Driven Forms

The TreeList provides an option for editing its data by using the Angular Template-Driven Forms. This type of editing relies on binding all editable fields with a form control using two-way ngModel binding.

The following example demonstrates how to manually implement inline editing using Template-Driven Forms.

Change Theme
Theme
Loading ...

To enable the editing mode of the TreeList with Template-Driven Forms:

  1. Wrap the component in a form tag.

    html
    <form novalidate #myForm="ngForm">
        <kendo-treelist>
            <!-- the rest of TreeList configuration goes here -->
        </kendo-treelist>
    </form>
  2. Configure the columns editor template. Verify that each column of the TreeList has a defined EditTemplateDirective.

    html
    <kendo-treelist-column [expandable]="true" field="FirstName" title="First Name">
        <ng-template kendoTreeListEditTemplate let-dataItem="dataItem">
            <kendo-textbox [(ngModel)]="dataItem.FirstName" name="FirstName" required></kendo-textbox>
        </ng-template>
    </kendo-treelist-column>
  3. Configure the command column and attach handlers for CRUD data operations.

    html
    <kendo-treelist
        [data]="rootData | async"
        idField="EmployeeId"
        [fetchChildren]="fetchChildren"
        [hasChildren]="hasChildren"
        (add)="addHandler($event, myForm)"
        (edit)="editHandler($event)"
        (remove)="removeHandler($event)"
        (save)="saveHandler($event)"
        (cancel)="cancelHandler($event)"
    >
    </kendo-treelist>

Adding Records

The add event fires when kendoTreeListAddCommand is clicked. Inside the event handler, show the new row editor by calling addRow.

ts
public addHandler({ sender, parent }: AddEvent, form: NgForm): void {
    this.closeEditor(sender);

    if (parent) {
        sender.expand(parent);
    }

    const employee = {
        ReportsTo: parent ? parent.EmployeeId : null
    };

    sender.addRow(employee, parent);
}

Editing Records

The edit event fires when kendoTreeListEditCommand is clicked. Inside the event handler, put the row in edit mode by calling editRow.

ts
public editHandler({ sender, dataItem }: EditEvent): void {
    this.closeEditor(sender, dataItem);

    this.editedItem = dataItem;
    this.originalValues = { ...dataItem };

    sender.editRow(dataItem);
}

Removing Records

The remove event fires when kendoTreeListRemoveCommand is clicked. Issue a request to remove the data item and invoke reload to reflect the changes.

ts
public removeHandler({ sender, dataItem, parent }: RemoveEvent): void {
    this.editService.remove(dataItem, parent).pipe(take(1)).subscribe(() => {
        if (parent) {
            sender.reload(parent);
        }
    });
}

Saving Records

The save event fires when kendoTreeListSaveCommand is clicked. Validate the form, persist the changes, and call closeRow to return the row to view mode.

ts
public saveHandler({ sender, dataItem, parent, isNew }: SaveEvent, form: NgForm): void {
    if (!form.valid) {
        return;
    }

    this.editService.save(dataItem, parent, isNew).pipe(take(1)).subscribe(() => {
        if (parent) {
            sender.reload(parent);
        }
    });

    sender.closeRow(dataItem, isNew);
}

Cancelling Editing

The cancel event fires when kendoTreeListCancelCommand is clicked. Switch the row back to view mode by calling closeRow.

ts
public cancelHandler({ sender, dataItem, isNew }: CancelEvent): void {
    this.closeEditor(sender, dataItem, isNew);
}

private closeEditor(treelist: TreeListComponent, dataItem: any = this.editedItem, isNew: boolean = false): void {
    treelist.closeRow(dataItem, isNew);

    if (this.editedItem) {
        Object.assign(this.editedItem, this.originalValues);
    }

    this.editedItem = undefined;
    this.originalValues = undefined;
}

See Also