Template editing in Angular Treegrid component
17 Nov 202224 minutes to read
Reactive forms
Reactive
Forms is a model-driven approach to create and manipulate the form controls. You can use reactive form to add and update treegrid records. To use reactive forms for editing operation, you can take leverage of the template support of dialog or inline edit mode. Setting the editSettings.mode
as Row/Dialog
and editSettingsTemplate
as template variable of NgTemplate to define the treegrid editors.
In the below sample, We have created the FormGroup
with FormControls
for each columns, in the actionBegin
event. While saving, we have validated the formgroup and updated the treegrid with the edited data from the FormGroup object.
import { NgModule,ViewChild } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { TreeGridModule } from '@syncfusion/ej2-angular-treegrid';
import { PageService, SortService, FilterService,EditService,ToolbarService } from '@syncfusion/ej2-angular-treegrid';
import { AppComponent } from './app.component';
import {ButtonModule} from '@syncfusion/ej2-angular-buttons';
import { DropDownListAllModule } from '@syncfusion/ej2-angular-dropdowns';
import { ReactiveFormsModule , FormsModule} from '@angular/forms';
import { NumericTextBoxAllModule } from '@syncfusion/ej2-angular-inputs';
import { DatePickerModule, DatePickerAllModule } from '@syncfusion/ej2-angular-calendars';
/**
* Module
*/
@NgModule({
imports: [
BrowserModule,
TreeGridModule,
ButtonModule,
DropDownListAllModule,
ReactiveFormsModule,
FormsModule,
NumericTextBoxAllModule,
DatePickerAllModule
],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [PageService,
SortService,
FilterService,
EditService,
ToolbarService]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';
enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);
Template-driven forms
Template-driven
forms is a template-driven approach to create and manipulate the form controls. You can use template-driven form to add and update treegrid records. To use template-driven forms for editing operation, you can take leverage of the template support of dialog or inline edit mode. Setting the editSettings.mode
as Row/Dialog
and editSettingsTemplate
as template variable of NgTemplate to define the treegrid editors.
In some cases, you need to add the new field editors in the dialog which are not present in the column model. In that situation, the dialog template will help you to customize the default edit dialog.
You can check this video to learn about how to customize the edit dialog of TreeGrid using template driven forms.
In the following sample, treegrid enabled with dialog template editing.
import { Component, OnInit, ViewChild } from '@angular/core';
import { sampleData } from './datasource';
import { DataUtil } from '@syncfusion/ej2-data';
import { DialogEditEventArgs, SaveEventArgs } from '@syncfusion/ej2-angular-grids';
import { EditService, ToolbarService, PageService } from '@syncfusion/ej2-angular-treegrid';
import { FormGroup } from '@angular/forms';
@Component({
selector: 'app-container',
template: `<ejs-treegrid [dataSource]='data' height='225' childMapping='subtasks' [treeColumnIndex]='1'allowPaging='true' [pageSettings]='pageSettings' [editSettings]='editSettings' [toolbar]='toolbar' (actionBegin)="actionBegin($event)" (actionComplete)="actionComplete($event)">
<e-columns>
<e-column field='taskID' headerText='Task ID' width='120' textAlign='Right' isPrimaryKey='true' ></e-column>
<e-column field='taskName' headerText='Task Name' width='225' ></e-column>
<e-column field='startDate' headerText='Start Date' width='150' format="yMd" ></e-column>
<e-column field='approved' headerText='Approved' type='boolean' editType='booleanedit' [displayAsCheckBox]='true' width='90' textAlign='Right' ></e-column>
</e-columns>
<ng-template #editSettingsTemplate let-data>
<div ngForm #taskForm="ngForm">
<div class="form-row">
<div class="form-group col-md-6">
<div class="e-float-input e-control-wrapper" [ngClass]="{'e-error': taskID.invalid && (taskID.dirty || taskID.touched)}">
<input [(ngModel)]="taskData.taskID" required id="taskID" name="taskID" type="text" [attr.disabled]="!data.isAdd ? '' : null" #taskID="ngModel">
<span class="e-float-line"></span>
<label class="e-float-text e-label-top" for="taskID"> Task ID</label>
</div>
<div id="taskIDError" *ngIf='taskID.invalid && (taskID.dirty || taskID.touched)'>
<label class="e-error" id="taskID-info" style="display: block;">*Task ID is required</label>
</div>
</div>
<div class="form-group col-md-6">
<div class="e-float-input e-control-wrapper" [ngClass]="{'e-error': taskName.invalid && (taskName.dirty || taskName.touched)}">
<input [(ngModel)]="taskData.taskName" required id="taskName" name="taskName" type="text" #taskName="ngModel">
<span class="e-float-line"></span>
<label class="e-float-text e-label-top" for="taskName">Task Name</label>
</div>
<div id="taskNameError" *ngIf='taskName.invalid && (taskName.dirty || taskName.touched)'>
<label class="e-error" id="taskName-info" style="display: block;">*Task Name is required</label>
</div>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<ejs-numerictextbox [(ngModel)]="taskData.progress" name="progress" id="progress" placeholder="Progress" floatLabelType='Always'></ejs-numerictextbox>
</div>
<div class="form-group col-md-6">
<ejs-datepicker id="startDate" name="startDate" required [(ngModel)]="taskData.startDate" placeholder="Start Date" floatLabelType='Always'></ejs-datepicker>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<ejs-numerictextbox [(ngModel)]="taskData.duration" name="duration" id="duration" placeholder="Duration" floatLabelType='Always'></ejs-numerictextbox>
</div>
<div class="form-group col-md-3">
<ejs-checkbox #approved label='Approved' [(ngModel)]="taskData.approved" [ngModelOptions]="{standalone: true}" [checked]="taskData.approved"></ejs-checkbox>
</div>
</div>
</div>
</ng-template>
</ejs-treegrid>`,
})
export class AppComponent implements OnInit {
public data: Object[] = [];
public editSettings: Object;
public toolbar: string[];
public pageSettings: Object;
public taskData: ITaskModel;
@ViewChild('taskForm')
public taskForm: FormGroup;
public progressDistinctData: Object;
public priorityDistinctData: Object;
ngOnInit(): void {
this.data = sampleData;
this.editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true , mode: 'Dialog' ,newRowPosition: 'Below'};
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
this.pageSettings = { pageCount: 5 };
this.progressDistinctData = DataUtil.distinct(sampleData, 'progress', true);
this.priorityDistinctData = DataUtil.distinct(sampleData, 'priority', true );
}
actionBegin(args: SaveEventArgs): void {
if (args.requestType === 'beginEdit' || args.requestType === 'add') {
this.taskData = Object.assign({}, args.rowData);
}
if (args.requestType === 'save') {
if (this.taskForm.valid) {
args.data = this.taskData;
} else {
args.cancel = true;
}
}
}
actionComplete(args: DialogEditEventArgs): void {
if (args.requestType === 'beginEdit' || args.requestType === 'add') {
// Disable the Validation Rules
args.form.ej2_instances[0].rules = {};
// Set initial Focus
if (args.requestType === 'beginEdit') {
(args.form.elements.namedItem('taskName') as HTMLInputElement).focus();
} else if (args.requestType === 'add') {
(args.form.elements.namedItem('taskID') as HTMLInputElement).focus();
}
}
}
public focusIn(target: HTMLElement): void {
target.parentElement.classList.add('e-input-focus');
}
public focusOut(target: HTMLElement): void {
target.parentElement.classList.remove('e-input-focus');
}
}
export interface ITaskModel {
taskID?: number;
taskName?: string;
startDate?: Date;
duration?: number;
progress?: number;
priority?: string;
approved?: boolean;
}
import { NgModule,ViewChild } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { TreeGridModule } from '@syncfusion/ej2-angular-treegrid';
import { PageService, FilterService,EditService,ToolbarService } from '@syncfusion/ej2-angular-treegrid';
import { AppComponent } from './app.component';
import {ButtonModule, CheckBoxAllModule} from '@syncfusion/ej2-angular-buttons';
import { DropDownListAllModule } from '@syncfusion/ej2-angular-dropdowns';
import { ReactiveFormsModule , FormsModule} from '@angular/forms';
import { NumericTextBoxAllModule } from '@syncfusion/ej2-angular-inputs';
import { DatePickerAllModule } from '@syncfusion/ej2-angular-calendars';
/**
* Module
*/
@NgModule({
imports: [
BrowserModule,
TreeGridModule,
ButtonModule,
DropDownListAllModule,
ReactiveFormsModule,
FormsModule,
NumericTextBoxAllModule,
CheckBoxAllModule,
DatePickerAllModule
],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [PageService,
FilterService,
EditService,
ToolbarService]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';
enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);
The template form editors should have name attribute.
Template context
The Essential JS2 packages has a built-in template engine. Using the template engine, you can access the row information inside the HTML element and bind the attributes, values, or elements based on this row information.
The following properties will be available at the time of template execution.
Property Name | Usage |
---|---|
isAdd | A Boolean property; it defines whether the current row should be a new record or not. |
In the following code example, the taskID
textbox has been disabled by using the isAdd
property.
// The disabled attributes will be added based on the isAdd property.
<input formControlName="taskID" id="taskID" name="taskID" type="text" [attr.disabled]="!data.isAdd ? '' : null">
The following code example illustrates rendering the taskID
textbox, when a new record is added.
<div class="form-group col-md-6" *ngIf='data.isAdd'>
<div class="e-float-input e-control-wrapper">
<input formControlName="taskID" id="taskID" name="taskID" type="text" [attr.disabled]="!data.isAdd ? '' : null">
<span class="e-float-line"></span>
<label class="e-float-text e-label-top" for="taskID">Task ID</label>
</div>
</div>
Set focus to editor
By default, the first input element in the dialog will be focused while opening the dialog.
If the first input element is in disabled or hidden state, focus the valid input element in the actionComplete
event based on requestType
as beginEdit
.
actionComplete: (args: DialogEditEventArgs) => {
// Set initial Focus
if (args.requestType === 'beginEdit') {
(args.form.elements.namedItem('taskName')as HTMLInputElement).focus();
}
}
Disable form validation
If you have interested to use angular form validation
then you need to disable the default validation rules in the actionComplete
event.
actionComplete(args: DialogEditEventArgs) {
if ((args.requestType === 'beginEdit' || args.requestType === 'add')) {
// Disable the Validation Rules
args.form.ej2_instances[0].rules = {};
}
}
Adding validation rules for custom editors
If you have used additional fields that are not present in the column model, then add the validation rules to the actionComplete
event.
actionComplete: (args: DialogEditEventArgs) => {
if ((args.requestType === 'beginEdit' || args.requestType === 'add')) {
// Add Validation Rules
args.form.ej2_instances[0].addRules('progress', {max: 100});
}
}