I am currently on Angular/Infragistics 12.0.3.
I have a data grid as below:
<igx-grid #designFacilities displayDensity="compact" [data]="dfMappings" [paging]="true" [perPage]="25" [allowFiltering]="true" [allowAdvancedFiltering]="true" [primaryKey]="'id'" width="695px" height="{{height}}px" [rowEditable]="globals.user.isContributor" (rowEditDone)="rowEditedDone($event)" [filterMode]="'excelStyleFilter'" style="margin: 0 auto;"> <igx-grid-toolbar class="bg-primary"> <igx-grid-toolbar-title class="text-white"><b>Design Facility Mappings</b></igx-grid-toolbar-title> </igx-grid-toolbar> <igx-column field="facility" header="Facility" [dataType]="'string'" [resizable]="true" width="97px" [editable]="false" [sortable]="true"></igx-column> <igx-column field="design" header="Design" [dataType]="'string'" [resizable]="true" width="109px" [editable]="false" [sortable]="true"></igx-column> <igx-column field="isVisible" header="Visible" [dataType]="'boolean'" [resizable]="true" width="94px"></igx-column> <igx-column field="isPrivate" header="Private" [dataType]="'boolean'" [resizable]="true" width="96px"></igx-column> <igx-column field="isTd" header="TD" [dataType]="'boolean'" [resizable]="true" width="71px"></igx-column> <igx-column header="Actions" [filterable]="false" [editable]="false" width="210px" [resizable]="true" [sortable]="false"> <ng-template igxCell let-cell="cell" let-val> <button [hidden]="scenario.scenarioType == 'Actual' || !globals.user.isContributor" igxButton (click)="deleteMapping(cell.rowData)">Delete</button> <button [hidden]="scenario.scenarioType == 'Actual' || !globals.user.isContributor" igxButton (click)="setStartData(cell.rowData); copyYield.open()">Copy Yield</button> </ng-template> </igx-column> </igx-grid>
I use a modal to add new rows as below:
<igx-dialog #addDfMapping [closeOnOutsideSelect]="true"> <igx-dialog-title> <div class="dialog-title">Add Design-Facility Mapping</div> </igx-dialog-title> <div *ngIf="designs !== undefined && designs.length > 50 && newDf !== undefined && newDf.design !== undefined"> <igx-input-group #designGroup [igxToggleAction]="design" displayDensity="compact"> <igx-prefix>Design: </igx-prefix> <input #designInput type="text" igxInput [igxDropDownItemNavigation]="design" readonly="true" [(ngModel)]="newDf.design" [value]="design.selectedItem?.value" (keydown.ArrowDown)="openDropDown('design')" /> <igx-suffix igxButton="icon" class="dropdownToggleButton" igxRipple> <igx-icon>arrow_drop{{ design.collapsed ? '_down' : '_up' }}</igx-icon> </igx-suffix> </igx-input-group> <igx-drop-down #design (onSelection)="filterFacilities($event.newSelection.value)" displayDensity="compact"> <div class="scrollable"> <igx-drop-down-item *ngFor="let des of designs" [selected]="des.name == newDf.design" [value]="des.name">{{des.name}}</igx-drop-down-item> </div> </igx-drop-down> </div> <div *ngIf="facilities !== [] && filteredFacilities !== [] && newDf !== undefined && newDf.facility !== undefined"> <igx-input-group #facilityGroup [igxToggleAction]="facility" displayDensity="compact"> <igx-prefix>Facility: </igx-prefix> <input #facilityInput type="text" igxInput [igxDropDownItemNavigation]="facility" readonly="true" [(ngModel)]="newDf.facility" [value]="facility.selectedItem?.value" (keydown.ArrowDown)="openDropDown('facility')" /> <igx-suffix igxButton="icon" class="dropdownToggleButton" igxRipple> <igx-icon>arrow_drop{{ facility.collapsed ? '_down' : '_up' }}</igx-icon> </igx-suffix> </igx-input-group> <igx-drop-down #facility (onSelection)="updateSelectedFacility($event.newSelection.value)" displayDensity="compact"> <div class="scrollable"> <igx-drop-down-item *ngFor="let fac of filteredFacilities" [selected]="fac.name == newDf.facility" [value]="fac.name">{{fac.name}}</igx-drop-down-item> </div> </igx-drop-down> </div> <br> <div style="display: inline-block;"> <igx-checkbox *ngIf="newDf !== undefined && newDf.isVisible !== undefined" [(ngModel)]="newDf.isVisible" labelPosition="before">Visible: </igx-checkbox> <igx-checkbox *ngIf="newDf !== undefined && newDf.isPrivate !== undefined" [(ngModel)]="newDf.isPrivate" labelPosition="before">Private: </igx-checkbox> <igx-checkbox *ngIf="newDf !== undefined && newDf.isTD !== undefined" [(ngModel)]="newDf.isTD" labelPosition="before">TD: </igx-checkbox> </div> <br><br> <button igxButton="outlined" (click)="addDfMapping.close(); createDesignFacilityMapping()"><igx-icon family="material">check</igx-icon><span>Add DF Mapping</span></button> <button igxButton="outlined" (click)="addDfMapping.close()"><igx-icon family="material">cancel</igx-icon><span>Cancel</span></button> </igx-dialog>
Adding a single mapping seems to work just fine. Here are relatable functions:
@ViewChild('designFacilities', { static: false, read: IgxGridComponent }) public dfMappingsList: IgxGridComponent; @ViewChild('design', { static: false, read: IgxDropDownComponent }) public designDd: IgxDropDownComponent; @ViewChild('designGroup', { static: false, read: IgxInputGroupComponent }) public designGroup: IgxInputGroupComponent; @ViewChild('facility', { static: false, read: IgxDropDownComponent }) public facilityDd: IgxDropDownComponent; @ViewChild('facilityGroup', { static: false, read: IgxInputGroupComponent }) public facilityGroup: IgxInputGroupComponent; public openDropDown(dd:string) { if (dd == 'design') { if (this.designDd.collapsed) { this.designDd.open({ target: this.designGroup.element.nativeElement, modal: false, positionStrategy: new ConnectedPositioningStrategy() }); } } else if (dd == 'facility') { if (this.facilityDd.collapsed) { this.facilityDd.open({ target: this.facilityGroup.element.nativeElement, modal: false, positionStrategy: new ConnectedPositioningStrategy() }); } } } filterFacilities(design:string) { this.filteredFacilities = []; this.newDf.design = design, this.newDf.designId = this.designs.filter(d => d.name == design)[0].id; this.filteredFacilities = this.facilities.filter(a => this.designs.filter(d => d.name == design)[0].facilities.indexOf(a.name) > -1); this.newDf.facility = this.filteredFacilities[0].name, this.newDf.facilityId = this.filteredFacilities[0].id; }; updateSelectedFacility(name:string) { this.newDf.facility = name; this.newDf.facilityId = this.facilities.filter(f => f.name == name)[0].id; }; async createDesignFacilityMapping() { let response:any = await this.scenarioService.createDesignFacilityMapping(this.newDf).toPromise(); if (response.statusCode == 200) { console.log(`Mapping ${this.newDf.design} for ${this.newDf.facility} successfully created!`); this.dfMappings.push(this.newDf); this.dfMappings.sort((a, b) => a.design < b.design ? -1 : a.design > b.design ? 1 : 0); this.dfMappingsList.markForCheck(); this.reportChanges.emit('mapping created'); } else { console.log(`Failed to create mapping ${this.newDf.design} for ${this.newDf.facility}: `, response); } };
When I add another mapping, however, the facility name in the grid for the first mapping that was added reverts back to the first facility in the appropriately filtered facilities for that design.
This change happens for all added mappings, as I add more to the grid.
When updated (loc.reload() or F5, for instance), the data is as it was added, rather than the changed values that propagated in the grid.
Users will get confused when adding multiple mappings, so obviously this behavior must be curbed.
Thanks in advance for your assistance.
Hello Chris,
Thank you for contacting Infragistics Community!
I have investigated the provided code snippets and I have tried to reproduce the described behavior on my side. However, it seems that a significant portion of your code is missing, for example: the rowEditDone event handler, the type of the data source, the scenarioService, the validation functions, the entire data along with its structure and etc. All these details may be crucial for finding the root cause of the behavior.
I have prepared the following simple sample for you in order to demonstrate how adding a new row through a modal window could be achieved. As you can observe everything is working as expected.
What I can suggest is providing an isolated working sample which reproduces the described behavior and which I will be able to run on my side. Having such a sample will allow me to debug it on my side and to determine the root cause of the issue you are facing.
Looking forward to hearing from you.
Best Regards, Martin Evtimov Associate Software Developer Infragistics, Inc.
rowEditDone:
rowEditedDone(e:any) { this.updateDesignFacilityMapping(e.newValue); };
Type of data source is SQL Server -> .NET CORE class matching the interface:
export interface scenarioDesignFacility { id:string, scenarioId:string, designId: string, design:string, facilityId:string, facility:string, isVisible:boolean, isPrivate:boolean, isTD:boolean }
ScenarioService strictly passes data between API and UI using the above interface (other than delete, which only passes the id:string).
The only validation that is happening is when facilities are filtered, a function which I already provided.
My assumption now is that the error may be propagating within the rowEditDone function, which I will test shortly. Thank you for the direction and pointing out something that was right in front of me.
Thank you for getting back to me!
Please take your time to test the rowEditDone function and let me know about your findings. Another possible reason for this behavior could be duplication of row primary keys.
In case that there isn’t any duplication of primary keys and that the rowEditDone function works as expected I will suggest providing me with a working sample reproducing the described behavior which I can debug on my side in order to provide you with solution as soon as possible.
I think as a normal course of making updates and refining code this has been resolved, although I cannot say for sure exactly how. For informational purposes, I will show the flow here:
Facility change in dropdown is recorded in newDf:
updateSelectedFacility(name:string) { this.newDf.facility = name; this.newDf.facilityId = this.facilities.filter(f => f.name == name)[0].id; };
When user clicks "add", newDf is sent to back-end for addition and the list is updated/re-sorted (mapping ID is updated only after user refreshes):
async createDesignFacilityMapping() { let response:any = await this.scenarioService.createDesignFacilityMapping(this.newDf).toPromise(); if (response.statusCode == 200) { console.log(`Mapping ${this.newDf.design} for ${this.newDf.facility} successfully created!`); this.newDf.id = `${this.newDf.design} for ${this.newDf.facility}`; this.dfMappings.push(this.newDf); this.dfMappings.sort((a, b) => { if (a.facility !== b.facility) { return a.facility.replace('2', '02') < b.facility.replace('2', '02') ? -1 : a.facility.replace('2', '02') > b.facility.replace('2', '02') ? 1 : 0; } else { return a.design < b.design ? -1 : a.design > b.design ? 1 : 0; } }); this.dfMappingsList.markForCheck(); this.reportChanges.emit('mapping created'); } else { console.log(`Failed to create mapping ${this.newDf.design} for ${this.newDf.facility}: `, response); } };
The format of the Facilities dropdown could be a possible reason as well. Take your time to prepare the working sample and provide it within this forum thread. As soon as I get it I will start debugging it and let you know regarding my findings.
In case you find an additional issue please do not hesitate to create a new forum thread regarding it.
I have confirmed it is not an issue with RowEditDone (as it's not touched during row adding via the Modal Dialog) and, although it looked like a good potential cause, the Unique Primary Key (potential issue) is also not the root cause here. I am working on reproducing it in a StackBlitz for you.
I suspect the issue may reside with the format of the Facilities dropdown, which is filtered based on the existing Design-Facility mappings and the design to be added. I also suspect this will be another ticket raised with Ignite UI as a result of my work.