I am using json binding for datasource. I am getting list of user in json format from server and I bind it to the datasource.
@ViewChild('grid')
public grid!: GridComponent;
userForm = new User();
actionInProgress!: string;
rolesMap = new Map<number, IRole>();
users: IUser[] | undefined;
organizations: IOrganization[] | undefined;
roleData: IRole[] | undefined;
// usersData!: { result: IUser[] | undefined, count: number | undefined };
usersData!: IUser[] | undefined;
editSettings!: EditSettingsModel;
toolbar!: ToolbarItems[];
filterOption: FilterSettingsModel = {
ignoreAccent: true,
type : "Excel"
}
serverError!: string;
testServerError = "TestError";
rowOddEvenCounter = 1;
public fields: Object = {text: 'name', value: 'id'};
editParams = {params: {popupHeight: '300px', allowFiltering: true}};
selectedOrg!: number;
showPassword = false;
selectedRoles!: number[];
usernameValidationRules = {required: true, minLength: 3};
ngOnInit(): void {
this.editSettings = {allowEditing: true, allowAdding: true, mode: "Dialog"};
this.toolbar = ["Add", "Edit", "ColumnChooser", "PdfExport", "ExcelExport", "CsvExport", "Search"];
this._userService.getUsers$.subscribe(response => {
if(response.error) {
this.errorHandling(response.error);
} else {
this.users = response.serverData?.dataList;
this.usersData = this.users;
this._loggingService.debug("Users received from server:" + this.users?.length);
}
});
this._orgService.getOrgs$.subscribe(response => {
if(response.error) {
this.errorHandling(response.error);
} else {
this.organizations = response.serverData?.dataList;
this._loggingService.debug("Organisations received from server:" + this.organizations?.length);
}
});
this._roleService.getRoles$.subscribe(response => {
if(response.error) {
this.errorHandling(response.error);
} else {
this.roleData = response.serverData?.dataList;
if(this.roleData !== undefined) {
this.prepareRoleMap(this.roleData);
}
this._loggingService.debug("Roles received from server:" + this.roleData?.length);
}
});
}
trying to save data:
async actionBegin($event: any) {
console.log($event);
if($event.request === "add") {
this._loggingService.debug("Adding User start")
this.actionInProgress = "add";
}
if($event.requestType === "beginEdit") {
this._loggingService.debug("Editing User start")
this.actionInProgress = "beginEdit";
}
if($event.requestType === "save") {
this._loggingService.debug("Saving User start")
this.prepareUserForSave();
let serverResponse$ = this._userService.addUse$(this.userForm)
let serverResponse = await lastValueFrom(serverResponse$);
let responseUser!: IUser;
if(serverResponse.error) {
this.errorHandling(serverResponse.error);
} else {
if(serverResponse.serverData?.data !== undefined) {
responseUser = serverResponse.serverData?.data;
}
}
this.usersData?.push(responseUser)
this.grid.refresh();
}
}
This is my html file
<app-nav-bar>
<div *ngIf = "serverError" error-div
class = "relative left-1/4 right-1/4 top-0 p-4 mb-4 text-sm text-red-700 bg-red-100 rounded-lg dark:bg-red-200 dark:text-red-800 text-center w-1/2"
role = "alert">
<span class = "font-medium">Error !</span> {{serverError}}
</div>
<div main-div class = "w-[97%]">
<ejs-grid #grid
[dataSource] = "usersData"
[allowSorting] = "true"
[allowFiltering] = "true"
[allowGrouping] = "true"
[editSettings] = "editSettings"
[toolbar] = "toolbar"
[enableStickyHeader] = "true"
[showColumnChooser] = "true"
[allowResizing] = "true"
[filterSettings] = "filterOption"
[allowPdfExport] = "true"
[allowExcelExport] = "true"
[allowMultiSorting] = "true"
(rowDataBound) = "customiseRow($event)"
(queryCellInfo) = "customiseCell($event)"
(toolbarClick) = "toolbarClick($event)"
(rowSelected) = "rowSelected($event)"
(actionBegin) = "actionBegin($event)"
(actionComplete)="actionComplete($event)"
clipMode = "EllipsisWithTooltip"
width = "100%">
<e-columns>
<e-column field = "id" [visible] = "false"
[showInColumnChooser] = "false"></e-column>
<e-column headerText = "Username" [isPrimaryKey] = "true" [allowResizing] = "true"
field = "username"
width = "150" [validationRules] = "usernameValidationRules"></e-column>
<e-column headerText = "Email" [allowResizing] = "true" field = "email"
width = "150"></e-column>
<e-column headerText = "Salutation" [allowResizing] = "true"
field = "salutation" width = "150"></e-column>
<e-column headerText = "First Name" [allowResizing] = "true" field = "firstName"
width = "150"></e-column>
<e-column headerText = "Middle Name" [allowResizing] = "true"
field = "middleName" width = "150"></e-column>
<e-column headerText = "Last Name" [allowResizing] = "true" field = "lastName"
width = "150"></e-column>
<e-column headerText = "Organization" [allowResizing] = "true"
editType = "dropdownedit" [edit] = "editParams"
field = "organization.name" width = "150">
</e-column>
<e-column headerText = "Contact Info" [allowResizing] = "true"
field = "contactInfo" width = "150"></e-column>
<e-column headerText = "IsSysAdmin" [allowResizing] = "true" field = "sysAdminRole"
displayAsCheckBox = "true" editType = "booleanedit"
width = "150"></e-column>
<e-column headerText = "IsSiteAdmin" [allowResizing] = "true"
field = "siteAdminRole"
displayAsCheckBox = "true" editType = "booleanedit"
width = "150"></e-column>
<e-column headerText = "IsOrgAdmin" [allowResizing] = "true" field = "orgAdminRole"
displayAsCheckBox = "true" editType = "booleanedit"
width = "150"></e-column>
<e-column headerText = "IsOwner" [allowResizing] = "true" field = "ownerRole"
displayAsCheckBox = "true" editType = "booleanedit"
width = "150"></e-column>
<e-column headerText = "IsOperator" [allowResizing] = "true" field = "operatorRole"
displayAsCheckBox = "true" editType = "booleanedit"
width = "150"></e-column>
<e-column headerText = "IsWorker" [allowResizing] = "true" field = "workerRole"
displayAsCheckBox = "true" editType = "booleanedit"
width = "150"></e-column>
<e-column headerText = "Locked" [allowResizing] = "true" field = "locked"
displayAsCheckBox = "true" editType = "booleanedit"
width = "150"></e-column>
<e-column headerText = "Expired" [allowResizing] = "true" field = "expired"
displayAsCheckBox = "true" editType = "booleanedit"
width = "150"></e-column>
<e-column headerText = "Logged-In" [allowResizing] = "true" field = "enabled"
displayAsCheckBox = "true" editType = "booleanedit"
width = "150"></e-column>
</e-columns>
<ng-template #editSettingsTemplate let-data>
<div ngForm #userEditForm = "ngForm"
class = "w-[500px] sm:w-[300px] ml-10 ml-auto mr-auto">
<input *ngIf = "actionInProgress ==='add'"
type = "text"
class = "block border border-grey-light w-full p-3 rounded mb-4"
autocomplete = "username"
required
minlength = "3"
name = "username"
placeholder = "Username*"
[ngClass] = "!username.valid && username.touched?'box-shadow bg-red-200':''"
[(ngModel)] = "userForm.username"
#username = "ngModel" />
<input
type = "text"
class = "block border border-grey-light w-full p-3 rounded mb-4"
name = "salutation"
placeholder = "Salutation"
[(ngModel)] = "userForm.salutation"
#salutation = "ngModel" />
<input
type = "text"
class = "block border border-grey-light w-full p-3 rounded mb-4"
name = "firstname"
placeholder = "First Name*"
required
[ngClass] = "firstName.invalid && firstName.touched?'box-shadow bg-red-200':''"
[(ngModel)] = "userForm.firstName"
#firstName = "ngModel" />
<input
type = "text"
class = "block border border-grey-light w-full p-3 rounded mb-4"
name = "middleName"
placeholder = "Middle Name"
[(ngModel)] = "userForm.middleName"
#middleName = "ngModel" />
<input
type = "text"
class = "block border border-grey-light w-full p-3 rounded mb-4"
name = "lastname"
placeholder = "Last Name"
[(ngModel)] = "userForm.lastName"
#lastName = "ngModel" />
<input
type = "text"
class = "block border border-grey-light w-full p-3 rounded mb-4"
name = "email"
placeholder = "Email*"
required
[ngClass] = "email.invalid && email.touched?'box-shadow bg-red-200':''"
[(ngModel)] = "userForm.email"
#email = "ngModel" />
<input
type = "text"
class = "block border border-grey-light w-full p-3 rounded mb-4"
name = "contactInfo"
placeholder = "Contact Info"
[(ngModel)] = "userForm.contactInfo" />
<div class = "block border border-grey-light w-full p-3 rounded my-4"
[ngClass] = "roles.invalid && roles.touched?'box-shadow bg-red-200':''">
<ejs-multiselect id = "addUserRole" [dataSource] = "roleData"
[(value)] = "selectedRoles" type = "Box"
[fields] = "fields"
name = "roles"
placeholder = "Select Roles*"
required
#roles = "ngModel"
[(ngModel)] = "selectedRoles">
</ejs-multiselect>
</div>
<div class = "block border border-grey-light w-full p-3 rounded my-4"
[ngClass] = "organization.invalid && organization.touched?'box-shadow bg-red-200':''">
<ejs-dropdownlist id = "addUserOrg" [dataSource] = "organizations"
[(value)] = "selectedOrg"
[fields] = "fields"
name = "organization"
required
placeholder = "Select Organisation*"
#organization = "ngModel"
[(ngModel)] = "selectedOrg">
</ejs-dropdownlist>
</div>
<div *ngIf = "actionInProgress === 'add'" class = "flex relative items-center">
<input
[type] = "showPassword?'text':'password'"
autocomplete = "current-password"
required
minlength = "3"
class = "block border border-grey-light w-full p-3 rounded mb-4"
name = "password"
placeholder = "Password*"
[ngClass] = "userPassword.invalid && userPassword.touched?'box-shadow bg-red-200':''"
[(ngModel)] = "userForm.password"
#userPassword = "ngModel" />
<div class = "absolute right-2 top-3 w-[20px] h-[20px]">
<svg *ngIf = "!showPassword" (click) = "togglePassword()"
xmlns = "http://www.w3.org/2000/svg"
viewBox = "0 0 640 512">
<path d = "M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z" />
</svg>
<svg *ngIf = "showPassword" (click) = "togglePassword()"
xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 576 512">
<path d = "M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z" />
</svg>
</div>
</div>
<div class = "flex items-center mb-4 justify-between">
<div class = "flex items-center">
<input id = "locked" type = "checkbox"
class = "w-4 h-4 text-blue-600 bg-gray-100 rounded border-gray-300 focus:ring-blue-500 focus:ring-2"
name = "locked"
[(ngModel)] = "userForm.locked">
<label for = "locked" class = "ml-2">Locked</label>
</div>
<div class = "flex items-center">
<input id = "expired" type = "checkbox" value = ""
class = "w-4 h-4 text-blue-600 bg-gray-100 rounded border-gray-300 focus:ring-blue-500 focus:ring-2"
name = "expired"
[(ngModel)] = "userForm.expired">
<label for = "expired" class = "ml-2">Expired</label>
</div>
<div class = "flex items-center">
<input id = "enabled" type = "checkbox" value = ""
class = "w-4 h-4 text-blue-600 bg-gray-100 rounded border-gray-300 focus:ring-blue-500 focus:ring-2"
name = "enabled"
[(ngModel)] = "userForm.enabled">
<label for = "enabled" class = "ml-2">Enabled</label>
</div>
</div>
</div>
</ng-template>
</ejs-grid>
</div>
</app-nav-bar>
There are multiple problems while adding new record:
1- New added Row not showing all the fields(value in cells), I have updated the dataSource in TS file by adding the record in usersData array which is bind to grid datasource and then refresh the grid, but updated record not showing in the grid. If I refresh the page then it works fine as data is saving on server as expected.
2- I want to stay on save/edit dialog if the server send error, is it possible with this type of datasource binding.
3- How to disable the save button until form is valid
4- Is there a way where I can prevent showing the edit/add dialog and redirect to another page.
5- Is there any way to prevent the newly added record showing in the grid.
Looking forward for your response, thanks !
More info:
I observe that record has added twice.
The record with all data shows on Grid refresh. I used grid refresh as a workaround to insert row in grid only after the
successful response.
Hi Surabhi Gangwar,
Thanks for contacting Syncfusion support.
Query#1: New added Row not showing all the fields(value in cells), I have updated the dataSource in TS file by adding the record in usersData array which is bind to grid datasource and then refresh the grid, but updated record not showing in the grid. If I refresh the page then it works fine as data is saving on server as expected.
We have noticed that you are calling the “grid.refresh” method inside the “actionBegin” event when saving the data which is the cause of the reported scenario. If you want to modify the dataSource programmatically with the added values in the dialog, then you can cancel the default add action and call the “closeEdit” method which cancels the edited state. Then you can modify the dataSource and call the grid refresh method. Please refer to the below code example for more information.
|
async actionBegin($event: any) { console.log($event); if ($event.requestType === 'save' && $event.action === 'add') { $event.cancel = true; this.usersData.push($event.data); this.grid.closeEdit(); this.grid.refresh(); } }
|
https://ej2.syncfusion.com/angular/documentation/api/grid/#closeedit
Query#2: I want to stay on save/edit dialog if the server send error, is it possible with this type of datasource binding.
Our EJ2 Grid has only the client-side validation. If you want to perform the validation on server side, you can achieve your requirement by using actionBegin event (requestType as save) of Grid.
In that event, we prevent the save action by setting args.cancel as true and save the data only when the server side validation becomes true.
|
public isValid: boolean = false;
function actionBegin(args) { if (args.requestType == "save" && args.action == "edit") { if (!this.isValid) { args.cancel = true; // prevent the save action to validate the value // perform server side validation for edit action here let ajax = new Ajax({ url: "xxx/EditValidation", contentType: "application/json; charset=utf-8", data: JSON.stringify(args.data), // send the edited data to the server type: "POST" }); ajax.send(); ajax.onSuccess = function (result) { if (JSON.parse(result).validationResult) { this.isValid = true; // make the flag variable as true once the validation becomes true this.grid.endEdit();// save the data
} else { alert(JSON.parse(result).errorMsg); // show the error message } } } else { this.isValid = false; } } } |
Query#3: How to disable the save button until form is valid
By default, we don’t have any option to disable the save button until some condition is satisfied. As a workaround, you can disable the button inside the actionComplete event and add the “validationComplete” event to the grid edit form. This event will be triggered when the validation is done after hitting the “Enter” action. Inside this event handler, you can check your conditions and enable the button again. Please refer to the below code example for more information.
|
actionComplete(args: DialogEditEventArgs): void { if(args.requestType === 'beginEdit' || args.requestType === 'add') { args.dialog.btnObj[0].disabled = true; args.form.ej2_instances[0].validationComplete = (e) => { // check your condition here args.dialog.btnObj[0].disabled = false; }; } }
|
https://ej2.syncfusion.com/documentation/api/button#disabled
https://ej2.syncfusion.com/documentation/api/form-validator#validationcomplete
Query#4: Is there a way where I can prevent showing the edit/add dialog and redirect to another page.
There is no default support for page redirection while editing/adding. However, You can cancel the default edit/add actions inside the “actionBegin” event using the “args.cancel” property and add your implementation for redirection.
|
function actionBegin(args): void { if (args.requestType === 'beginEdit' || args.requestType === 'add') { args.cancel = true; // here you can do your requirement } }
|
Query#5: Is there any way to prevent the newly added record showing in the grid.
No, the newly added rows will be reflected in the Grid. This is the default behavior and use case of the Grid “Add” action.
Query#6: I observe that record has added twice.
Since you are adding the data through the default add action and also push the dataSource and refresh the Grid inside the “actionBegin” event, the data is added twice. So Please add the solution provided for “Query#1” to overcome the issue.
Regards,
Pavithra S
Hi Pavithra,
You guys are awesome, thanks for the replies.
You replies are very helpful and solve most of my problems.
Hi Surabhi,
We are glad to hear it from you. Please get back to us if you have any other queries in future. We are always happy to help you.
Regards,
Suganya Gopinath.