Using latest releases of Angular and Ignite UI (12.0.3):
I have a pair of Dropdowns using the igx-input-group model. One of them determines the filtered data set of the second. I am using the (onSelection) attribute to filter the second, but I am also getting an error NG0100: ExpressionChangedAfterItHasBeenCheckedError.
The functionality isn't broken, but it's throwing an error like it is. If I didn't have tech savvy users who will complain, I wouldn't bother asking how to fix it.
A previous question suggested using markForCheck on the igx-grid component. Is there something similar for this setup I should be using, either on the dropdown or the input-group? This is in a dialog modal, if that makes any difference.
Hello Chris,
Thank you for contacting Infragistics Community!
In pursuit of reproducing the described behavior on my side I have created a small sample where the items of the second igxDropDown Component are assigned within the onSelection event hook of the first one and no exceptions are thrown.
In order to be able to assist you further could you please try to modify the provided sample so that it replicates the issue you are facing and send it back to me. Having a sample, which I can debug on my side, will be highly appreciated and extremely helpful for providing you with solution as soon as possible.
Looking forward to hearing from you.
Best Regards, Martin Evtimov Associate Software Developer Infragistics, Inc.
Martin,
There are a few possibilities for the cause here:
Here is a basic example of the data being presented for both lists:
public designs:{name:string, facilities:string, id:number}[] = []; //filled with back-end process public facilities:{name:string, id:number}[] = []; //filled with back-end process public filteredFacilities:{name:string, id:number}[] = []; //filled with filterFacilities below public newDf:{design:string, facility:string}; // built initially from designs[0], filteredFacilities[0]; filterFacilities(design:string) { 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; };
The [(ngModel)] for the dropdowns is the newDf (design for the design dropdown; facility for facility dropdown) and as mentioned, initial values are design[0] and filteredFacilities[0]. As design changes, filteredFacilities changes, but the first entry is always the initially selected value. This is because 90% of the time, the user will go with the first value in filteredFacilities.
The error happens when a Design is chosen that does not contain the previously selected value of the Facility dropdown.
Another issue I'm facing is that I am unable to concatenate for the initial display value of another dropdown that displays the list of available Design + Facility mappings:
public dfMappings: {design:string, facility:string, id:number}[] = []; //initialized by back-end process public fromMapping: {design:string, facility:string, id:number}; //initialized as dfMappings[0]
I have tried the below in initializing the input's view (note, once dropdown is opened, all dfMappings show as "<design> for <facility>":
I put the above as values for [value], using the (dropdown id) fromMap.selectedItem?.value notation for fromMapping and directly using fromMapping.
[(ngModel)]="fromMapping" and value passed to the input from the dropdown is a mapping of the same structure.
Thank you for getting back to me!
Following your description I have updated the provided sample so that:
As you can observe no exceptions are thrown when changing the selectedItem of both igxDropDown components. Please keep in mind that as I have already mentioned in my previous reply without being able to replicate the described issue and to debug it on my side it will be really difficult to provide you with solution. Having this in mind providing me with small isolated sample will be highly appreciated and extremely helpful.
PS. You have mentioned that you have used [(ngModel)]. After further investigation I can verify that the igxDropDown component class doesn’t inheritance the ControlValueAccessor interface meaning that the ngModel directive cannot be used together with it.
I see you are using observables/subscriptions rather than promises here. Does it matter if the source of data is consistent (from a back-end I wrote and know is stable)?
I also notice you're still only using 2 dropdowns and lists that directly match and easily filter as 1:1 between the dropdowns. Here is a logical example of what I'm attempting to achieve:
Consider an aid society (like Red Cross, Salvation Army, etc.) that has relief supplies in many regions (different states, provinces, cities within multiple countries). Let us say there is a master list of regions they operate in and regularly house supplies in, and within those regions there are several divisions (smaller locations that make up the region). Naming will usually be similar for divisions between regions. When a disaster happens, they decide which region(s) and divisions should be receiving extra supplies and from which region(s) and division(s) they should come from.
If supplies are going to a different division within the same region, they shouldn't be able to select the source (division source dropdown.selectedValue) from the destination division dropdown. Since supplies may come from the same region, the list of regions is the same for both source and destination.
I have modified your example to match the situation. It appears broken for what I'm attempting to do. I hope this helps to see my vision.
After investigating the provided sample I noticed some exceptions which I have addressed in the following one. On my side everything seems to work as expected. Could you please test it on your side and if you still face any issues let me know the exact steps of reproducing them.
I have altered a bit more in the sample, but for some reason, when changing the TO region, then changing the FROM region to match, the selected FROM division is still in the list of TO divisions.
Also, I'm still curious about whether it will be necessary to switch my code from PROMISE to OBSERVABLE in order retain effectiveness. I asked in the previous reply, but you didn't address it.
I’m glad that you have managed to achieve your requirements.
Thank you for using Infragistics Components!
That works, slightly differently than implemented (I used e.newValue !== undefined) to process new values.
Please note that currently, by design, the onSelection event is emitted when the selectedItem of the igxDropDown Component has been changed through user interaction or via the selectItem API method.
My suggestion would be to log this behavior in our GitHub repository here. This will give you the opportunity do directly communicate with our development team regarding the issue and get notifications whenever a new information is available.
Additionally another possible approach could be to use a conditional flag within the different lifecycle hooks in order to determinate whether the event has been emitted because of the preselection. Please keep in mind that initially the oldSelection filed of the onSelection event args is null. You can refer to the following sample I have prepared for you.
Please let me know if you need any further information!
Ok, so I've rooted out another issue related to dropdowns. The (onSelection) is firing when it's being created because it is being pre-populated with a value. Is there a way to prevent the onSelection action during render?
I have a grid that waits for user input to populate, but one of the dropdowns fires on render and on occasion, the grid populates without interaction, and without any useful data. I'm hoping to prevent this for improved user experience.
I’m glad that you find the provided information helpful.
Best Regards,Martin EvtimovAssociate Software DeveloperInfragistics, Inc.