I am new to Angular and am having an issue with a nested *ngFor and am hoping you can shed some light on the problem.
I have a main component (Portfolio), which has a nav component and detail component nested. The main component triggers a service to make an api call to a backend db, and uses the data to populate both the nav component and detail component (when a selection is made - default display otherwise.
PortfolioComponent.ts
export class PortfolioComponent implements AfterViewInit {
@Output() newChoiceEvent: EventEmitter<string> = new EventEmitter(true);
private _choice: string = '-1';
public get choice() {
return this._choice;
}
public set choice(val: string) {
this._choice = val;
this.newChoiceEvent.emit(this._choice);
}
constructor (private portfolioService: PortfolioService) {
}
ngAfterViewInit(): void {
this.portfolioService.getData().subscribe({
next: (data) => {
this.portfolioService.mechanisms = data as Mechanism[];
},
error: (error: ErrorEvent) => { console.log('Error: ', error)}
});
}
chooseAnother(choice: string) {
this.choice = choice;
}
}
PortfolioComponent.html
<div class="row">
<smccaffrey-portfolionav (choiceEvent)="chooseAnother($event)" class="col col-md-4"></smccaffrey-portfolionav>
<smccaffrey-projectdetail [choice]="choice" class="col col-md-8"></smccaffrey-projectdetail>
</div>
PortfolioNavComponent.ts
export class PortfolionavComponent implements OnInit {
@Output() choiceEvent = new EventEmitter<string>();
selections:ListOption[] = [];
constructor(private portfolioService: PortfolioService) {}
ngOnInit(): void {
setTimeout(() => {
this.selections = this.portfolioService.getSelections();
//console.log('PortfolioNav: ', this.selections);
}, 500);
}
chooseNew(id: string) {
this.choiceEvent.emit(id);
}
}
PortfolioNavComponent.html
<section class="flipped">
<ul>
<div *ngFor="let selection of selections" (click)="chooseNew(selection.id)">
<li>{{selection.name}}</li>
<ul>
<li *ngFor="let subselection of selection.parts" (click)="chooseNew(subselection.id)">{{subselection.name}}</li>
</ul>
</div>
</ul>
</section>
PortfolioDetailComponent.ts
export class ProjectdetailComponent implements OnChanges {
@Input() choice: string = '-1';
item!: Mechanism | Part;
constructor (private portfolioService:PortfolioService) {}
ngOnChanges(changes: SimpleChanges): void {
for (let prop in changes) {
let change = changes[prop];
if (prop === 'choice') {
if(change.currentValue != '-1') {
this.item = this.portfolioService.getSelectionDetail(change.currentValue);
console.log('Change Value: ' + change.currentValue);
console.log('Item: ' + this.item.name);
}
}
}
}
}
The problem I am encountering is that when I select the 'Mechanism' in the nav the detail changes as expected, but when I select a 'Part' the 'Mechanism is displayed.
The console shows that the part selection does register, but immediately reverts to the 'Mechanism' it belongs to. Console Output
The expectation is that the selection the user makes is displayed in the detail component, for both mechanisms and parts.
Upon further jiggery-pokery, I have come up with a 'solution' (quotes are because it feels kinda hacky to me).
Where I had the
<li>{{selection.name}}</li>
&&
<li>{{subSelection.name}}</li>
I added an anchor like this
<li><a [href]="">{{selection.name}}</a></li>
&&
<li><a [href]="">{{subSelection.name}}</a></li>
which has solved the issue of not displaying the Part.
I don't, however, know why this worked. Perhaps some of the more experienced dev's can weigh in and shed some light.