I'm using latest Angular/Infragistics (12.0.3).
I'm getting an error that gives me nothing useful for tracing:
main.js:19079 ERROR TypeError: Cannot read property 'isHeader' of undefined at IgxComboComponent_igx_combo_item_22_Template (main.js:61907) at executeTemplate (main.js:22182) at refreshView (main.js:22048) at refreshEmbeddedViews (main.js:23173) at refreshView (main.js:22072) at refreshComponent (main.js:23219) at refreshChildComponents (main.js:21845) at refreshView (main.js:22098) at refreshEmbeddedViews (main.js:23173) at refreshView (main.js:22072)
There's nothing in the stack trace that goes back to a useful naming of anything I'm doing. I will describe as best I can what's going on and perhaps you can reason out why I'm getting the error (or we can create a sample together that reproduces it).
I am running a comparison between 2 scenarios (with a lot of data). I am using dropdowns, similar to dropdown-sample-4. When the 2 scenario dropdowns match, there's no issue (it produces the comparison correctly). When they do not match, however, I get the error listed above. They are implemented in pretty much exactly the same way, with appropriately different labels/variables/etc. to distinguish them properly. Here is their implementation:
<div *ngIf="scenario1List !== undefined && scenario1List.length > 1"> <igx-input-group #scenario1Group [igxToggleAction]="scenario1Dd" displayDensity="compact"> <igx-prefix style="width: 150px;"> Scenario 1 Name: </igx-prefix> <input #scenario1Input style="width: 250px;" type="text" igxInput [igxDropDownItemNavigation]="scenario1Dd" readonly="true" placeholder="Pick a Scenario (1)" [value]="scenario1Dd.selectedItem?.value" (keydown.ArrowDown)="openDropDown('scenario1')" /> <igx-suffix igxButton="icon" class="dropdownToggleButton" igxRipple> <igx-icon>arrow_drop{{ scenario1Dd.collapsed ? '_down' : '_up' }}</igx-icon> </igx-suffix> </igx-input-group> <igx-drop-down #scenario1Dd displayDensity="compact" (onSelection)="setScenario($event, 1)"> <div class="scrollable"> <igx-drop-down-item [selected]="true" [value]="">Choose a Scenario</igx-drop-down-item> <igx-drop-down-item *ngFor="let scen of scenario1List" [value]="scen.name">{{scen.name}}</igx-drop-down-item> </div> </igx-drop-down> </div> <div *ngIf="scenario2List !== undefined && scenario2List.length > 1"> <igx-input-group #scenario2Group [igxToggleAction]="scenario2Dd" displayDensity="compact"> <igx-prefix style="width: 150px;"> Scenario 2 Name: </igx-prefix> <input #scenario2Input style="width: 250px;" type="text" igxInput [igxDropDownItemNavigation]="scenario2Dd" readonly="true" placeholder="Pick a Scenario (2)" [value]="scenario2Dd.selectedItem?.value" (keydown.ArrowDown)="openDropDown('scenario2')" /> <igx-suffix igxButton="icon" class="dropdownToggleButton" igxRipple> <igx-icon>arrow_drop{{ scenario2Dd.collapsed ? '_down' : '_up' }}</igx-icon> </igx-suffix> </igx-input-group> <igx-drop-down #scenario2Dd (onSelection)="setScenario($event, 2)" displayDensity="compact"> <div class="scrollable"> <igx-drop-down-item [selected]="true" [value]="">Choose a Scenario</igx-drop-down-item> <igx-drop-down-item *ngFor="let scen of scenario2List" [value]="scen.name">{{scen.name}}</igx-drop-down-item> </div> </igx-drop-down> </div>
They are gated by a similarly implemented Scenario Type dropdown (each), which I have no issue with. There are other controls for filtering the horizon, type of products, and facilities produced, none of which have issues until 2 scenarios which don't match are selected. In fact, every dropdown (and combobox for facilities) throws the above error when the scenarios chosen do not match.
setScenario is implemented like this:
setScenario(e:any, scen:number) { if (e.oldSelection == null || e.oldSelection.value !== e.newSelection.value) { if (scen == 1) { this.scenario1 = this.scenario1List.filter(s => s.name == e.newSelection.value)[0]; } else if (scen == 2) { this.scenario2 = this.scenario1List.filter(s => s.name == e.newSelection.value)[0]; } } if (this.scenario1 !== undefined && this.scenario2 !== undefined) { this.getFacilities(); this.getWorkweeks(); this.getCompareData(); } };
getFacilities filters down to the unique set of facilities represented in both scenarios, and works perfectly.
getWorkweeks gives the full horizon represented by the 2 scenarios (earliest WW of the 2 through the latest WW of the 2), and works perfectly.
getCompareData parses the return from the back-end and puts it into a good form for all the filters, chosen horizon, and selected rollup (WW, month, quarter), and all of these work perfectly, when the scenarios match.
There is a Calculate button which sends the data to be filtered and rolled-up, which also works perfectly when the 2 scenarios match.
I figured it out, but I'm annoyed with the result.
I was previously using a combination of functions to filter duplicate facilities from the concatenated list between scenario 1 and scenario 2. Unfortunately, using ```delete array[index];" doesn't fully remove that index from the array in TypeScript. I am forced to build a unique list by iterating through both of the returned lists, unless one of you has a better idea.
Here is my current functionality:
async getFacilities() { this.facilities = [], this.selectedFacilities = []; let a:idName[] = await this.scenarioService.getFacilities(this.scenario1.id).toPromise(), b:idName[] = await this.scenarioService.getFacilities(this.scenario2.id).toPromise(), c:idName[] = []; if (this.scenario1.name == this.scenario2.name) { this.facilities = a; } else { a.forEach(f => c.push(f)); b.forEach(f => { if (c.findIndex(d => d.name == f.name) < 0) { c.push(f); } }); } this.facilities = c, this.selectedFacilities = c; };
For conciseness, I would prefer to have something more like the below, without the array returned having empty indices:
async getFacilities() { this.facilities = [], this.selectedFacilities = []; let a = await this.scenarioService.getFacilities(this.scenario1.id).toPromise(), b = await this.scenarioService.getFacilities(this.scenario2.id).toPromise(); this.facilities = a.concat(b); if (this.scenario1.name == this.scenario2.name) { this.facilities = a; } else { for (let i = this.facilities.length - 1; i >= 0; i--) { if (this.facilities.findIndex(f => this.facilities[i].name == f.name) < i) { delete this.facilities[i]}; } } this.selectedFacilities = this.facilities; };
If you have a suggestion, that would be appreciated. Here is the implementation of Facilities combo for reference:
<div *ngIf="facilities !== undefined && facilities !== [] && selectedFacilities !== undefined && selectedFacilities !== []"> <igx-combo id="facFilter" [width]="'200'" displayDensity="compact" [(ngModel)]="selectedFacilities" [displayKey]="'name'" [data]="facilities" [igxFocus]="true" width="150px" placeholder="ALL (click to filter)" (onSelectionChange)="updateSelectedFacilities($event)"></igx-combo> </div>
Hello Chris,
I am glad that you managed to find the root cause of the issue.
Looking further into the provided information, as you have already determined, this is the default way that the delete function works. This behavior can be considered beyond the scope of Infragistics support. However, I believe that you could find the following discussion in StackOverflow helpful.
Please let me know if I could be of any further assistance.
Best Regards, Martin Evtimov Associate Software Developer Infragistics, Inc.