Dear, when I update a record in my grid, I get strange behaviour. The record is still in edit mode, while the update call is done when I try to click out, and the grid is not refreshed.
import { Component, OnInit, ViewChild } from '@angular/core';
import { TranslationService } from '@arcelormittal-platform/core';
import {
ProcessesGridService,
WcmPillarsService,
StrategicalAxisesService,
} from '@masterdata/services';
import {
LoadingIndicator,
PageSettingsModel,
EditSettingsModel,
GridComponent,
RecordDoubleClickEventArgs,
} from '@syncfusion/ej2-angular-grids';
import { DataManager } from '@syncfusion/ej2-data';
import { FormArray, FormBuilder, Validators } from '@angular/forms';
import { FieldSettingsModel } from '@syncfusion/ej2-angular-dropdowns';
import { StrategicalAxisDropdownItem, WcmPillarDropdownItem } from '@masterdata/models';
import { Observable } from 'rxjs';
@Component({
selector: 'am-processes',
templateUrl: './processes.component.html',
styleUrls: ['./processes.component.scss'],
})
export class ProcessesComponent implements OnInit {
@ViewChild('grid') grid: GridComponent | undefined;
public dataManager: DataManager;
public loadingIndicator: Partial<LoadingIndicator>;
public pageSettings: PageSettingsModel;
public editSettings: EditSettingsModel;
public currentNameFormArray: FormArray | undefined;
public nameDialogVisible = false;
public currentDescriptionFormArray: FormArray | undefined;
public descriptionDialogVisible = false;
public wcmPillars$: Observable<WcmPillarDropdownItem[]> | undefined;
public selectedWcmPillarIds: number[] | undefined;
public wcmPillarFields: FieldSettingsModel;
public strategicalAxises$: Observable<StrategicalAxisDropdownItem[]> | undefined;
public selectedStrategicalAxisIds: number[] | undefined;
public strategicalAxisFields: FieldSettingsModel;
private currentRowData: any | undefined;
private currentColumnName: string | undefined;
constructor(
private readonly processesService: ProcessesGridService,
private readonly translationService: TranslationService,
private readonly fb: FormBuilder,
private readonly wcmPillarsService: WcmPillarsService,
private readonly strategicalAxisesService: StrategicalAxisesService
) {}
get nameField(): string {
return `name${this.translationService.getCurrentLanguage().toUpperCase()}`;
}
get descriptionField(): string {
return `description${this.translationService.getCurrentLanguage().toUpperCase()}`;
}
public ngOnInit(): void {
this.loadingIndicator = { indicatorType: 'Shimmer' };
this.dataManager = this.processesService.getGridDataManager();
this.pageSettings = { pageSize: 20 };
this.editSettings = {
allowEditing: true,
allowAdding: true,
allowDeleting: true,
mode: 'Normal',
};
this.setupWcmPillars();
this.setupStrategicalAxises();
}
public recordDoubleClick(args: RecordDoubleClickEventArgs) {
this.currentColumnName = args.column.field;
this.currentRowData = args.rowData;
this.currentNameFormArray = this.buildFormArray(args, 'name');
this.currentDescriptionFormArray = this.buildFormArray(args, 'description');
}
public actionBegin(args: any) {
const requestType = args.requestType;
if (requestType === 'beginEdit') {
if (this.currentColumnName.startsWith('name')) {
args.cancel = true;
this.nameDialogVisible = true;
}
if (this.currentColumnName.startsWith('description')) {
args.cancel = true;
this.descriptionDialogVisible = true;
}
this.setCurrentWcmPillarValues(args.rowData);
this.setCurrentStrategicalAxises(args.rowData);
}
if (requestType === 'save') {
args.data.attachedWcmPillars = this.selectedWcmPillarIds;
args.data.attachedStrategicalAxises = this.selectedStrategicalAxisIds;
const nameTranslationsAsLocalizedText = this.currentNameFormArray.value.map(
(translation) => ({
code: translation.code,
text: translation.text,
})
);
args.data.names = nameTranslationsAsLocalizedText;
const descriptionTranslationsAsLocalizedText = this.currentDescriptionFormArray.value.map(
(translation) => ({
code: translation.code,
text: translation.text,
})
);
args.data.descriptions = descriptionTranslationsAsLocalizedText;
}
}
public hideNameDialog() {
this.nameDialogVisible = false;
}
public hideDescriptionDialog() {
this.descriptionDialogVisible = false;
}
public saveNameTranslations() {
this.saveTranslations(this.currentNameFormArray);
}
public saveDescriptionTranslations() {
this.saveTranslations(this.currentDescriptionFormArray);
}
private setCurrentWcmPillarValues(data: any) {
this.selectedWcmPillarIds = data.wcmPillars.map((x) => x.id);
}
private setupWcmPillars() {
this.wcmPillars$ = this.wcmPillarsService.GetDropdownItems();
this.wcmPillarFields = { value: 'id', text: 'name' };
}
private setCurrentStrategicalAxises(data: any) {
this.selectedStrategicalAxisIds = data.strategicalAxises.map((x) => x.id);
}
private setupStrategicalAxises() {
this.strategicalAxises$ = this.strategicalAxisesService.getDropdownItems();
this.strategicalAxisFields = { value: 'id', text: 'name' };
}
private buildFormArray(args: RecordDoubleClickEventArgs, fieldPrefix: string): FormArray {
const newFormArray = new FormArray([]);
Object.keys(args.rowData)
.filter((key) => key.startsWith(fieldPrefix) && key !== fieldPrefix && !!args.rowData[key])
.forEach((key) => {
newFormArray.push(
this.fb.group({
code: this.fb.control(key.slice(-2), Validators.required),
text: this.fb.control(args.rowData[key], Validators.required),
})
);
});
return newFormArray;
}
private saveTranslations(formArray: FormArray | undefined): void {
if (!formArray || !this.currentRowData) return;
const translations = formArray?.value;
const initialValues = JSON.parse(JSON.stringify(this.currentRowData));
const columnName = this.currentColumnName.slice(0, -2);
translations.forEach((translation) => {
const field = `${columnName}${translation.code.toUpperCase()}`;
this.currentRowData[field] = translation.text;
});
this.currentRowData['names'] = Object.keys(this.currentRowData)
.filter((key) => key.startsWith('name') && key !== 'name' && !!this.currentRowData[key])
.map((key) => ({ code: key.slice(-2), text: this.currentRowData[key] }));
this.currentRowData['descriptions'] = Object.keys(this.currentRowData)
.filter(
(key) =>
key.startsWith('description') && key !== 'description' && !!this.currentRowData[key]
)
.map((key) => ({ code: key.slice(-2), text: this.currentRowData[key] }));
this.currentRowData['attachedWcmPillars'] = this.selectedWcmPillarIds;
this.currentRowData['attachedStrategicalAxises'] = this.selectedStrategicalAxisIds;
const allHaveValues = translations.every((translation) => translation.text);
if (JSON.stringify(initialValues) !== JSON.stringify(this.currentRowData) && allHaveValues) {
const rowIndex = this.grid.getRowIndexByPrimaryKey(this.currentRowData.id);
this.grid.updateRowValue(rowIndex, this.currentRowData);
}
this.nameDialogVisible = false;
this.descriptionDialogVisible = false;
}
}
<mat-card>
<div class="header">
<mat-icon class="header-icon">developer_board</mat-icon>
<div class="title">
<h3>{{ 'Processes.SubTitle' | translate }}</h3>
<h2>{{ 'Processes.Title' | translate }}</h2>
</div>
</div>
<ejs-grid
#grid
[dataSource]="dataManager"
[loadingIndicator]="loadingIndicator"
[pageSettings]="pageSettings"
[allowPaging]="true"
[editSettings]="editSettings"
(recordDoubleClick)="recordDoubleClick($event)"
(actionBegin)="actionBegin($event)"
>
<e-columns>
<e-column
field="id"
[isPrimaryKey]="true"
[visible]="false"
[allowEditing]="false"
></e-column>
<e-column
[field]="nameField"
[headerText]="'Processes.Headers.Name' | translate"
[allowEditing]="false"
></e-column>
<e-column
field="code"
[headerText]="'Processes.Headers.Code' | translate"
width="120"
></e-column>
<e-column
[field]="descriptionField"
[headerText]="'Processes.Headers.Description' | translate"
[allowEditing]="false"
></e-column>
<e-column field="wcmPillarNames" [headerText]="'Processes.Headers.WcmPillars' | translate">
<ng-template #editTemplate>
<ejs-multiselect
[dataSource]="wcmPillars$ | async"
[fields]="wcmPillarFields"
[(value)]="selectedWcmPillarIds"
></ejs-multiselect>
</ng-template>
</e-column>
<e-column
field="strategicalAxisNames"
[headerText]="'Processes.Headers.StrategicalAxis' | translate"
>
<ng-template #editTemplate>
<ejs-multiselect
[dataSource]="strategicalAxises$ | async"
[fields]="strategicalAxisFields"
[(value)]="selectedStrategicalAxisIds"
></ejs-multiselect>
</ng-template>
</e-column>
<e-column
[headerText]="'Processes.Headers.IsActive' | translate"
width="70"
textAlign="Right"
[allowEditing]="false"
>
<ng-template #template let-data>
<mat-slide-toggle [checked]="data.isActive"></mat-slide-toggle>
</ng-template>
</e-column>
</e-columns>
</ejs-grid>
</mat-card>
<ejs-dialog
#nameDialog
isModal="true"
showCloseIcon="true"
[(visible)]="nameDialogVisible"
[width]="500"
>
<ng-template #header>
<mat-icon>badge</mat-icon>
<div class="title">
<h2>{{ 'Processes.Popups.Name.Title' | translate }}</h2>
<h3>{{ 'Processes.Popups.Name.SubTitle' | translate }}</h3>
</div>
</ng-template>
<ng-template #content>
<am-translations-form
*ngIf="currentNameFormArray"
[translations]="currentNameFormArray"
[label]="'Roles.Details.Name'"
></am-translations-form>
</ng-template>
<ng-template #footerTemplate>
<button mat-button (click)="hideNameDialog()">{{ 'Common.Cancel' | translate }}</button>
<button mat-raised-button color="accent" (click)="saveNameTranslations()">
{{ 'Common.Save' | translate }}
</button>
</ng-template>
</ejs-dialog>
<ejs-dialog
#descriptionDialog
isModal="true"
showCloseIcon="true"
[(visible)]="descriptionDialogVisible"
[width]="500"
>
<ng-template #header>
<mat-icon>badge</mat-icon>
<div class="title">
<h2>{{ 'Processes.Popups.Description.Title' | translate }}</h2>
<h3>{{ 'Processes.Popups.Description.SubTitle' | translate }}</h3>
</div>
</ng-template>
<ng-template #content>
<am-translations-form
*ngIf="currentDescriptionFormArray"
[translations]="currentDescriptionFormArray"
[label]="'Roles.Details.Description'"
></am-translations-form>
</ng-template>
<ng-template #footerTemplate>
<button mat-button (click)="hideDescriptionDialog()">{{ 'Common.Cancel' | translate }}</button>
<button mat-raised-button color="accent" (click)="saveDescriptionTranslations()">
{{ 'Common.Save' | translate }}
</button>
</ng-template>
</ejs-dialog>