I'm making a simple helper app for one of my favorite games and learning Angular by the way. I have a component ("wing") that contains a list of buttons, that would uncover a sublist, which is represented by another sub-component. However, the way I have it now, when I click on a given "wing" button, it also uncovers the encounter sublist for every other wing as well. This is the code for my "wing" component:
wing.component.html:
<ul>
<li *ngFor="let wing of wings">
<button (click)="showEncounters = !showEncounters">{{ wing.getName() }}</button>
<app-encounter
*ngIf="showEncounters"
[encounters]="wing.getEncounters()">
</app-encounter>
</li>
</ul>
wing.component.ts:
@Component({
selector: 'app-wing',
templateUrl: './wing.component.html',
styleUrls: ['./wing.component.css']
})
export class WingComponent implements OnInit {
wings = WINGS;
showEncounters: boolean = false;
constructor() {
}
ngOnInit(): void {
}
}
wing.ts:
export class Wing {
private readonly name : string;
private readonly encounters: Encounter[] = [];
constructor(name: string, encounters: Encounter[]) {
this.name = name;
this.encounters = encounters;
}
public getName() {
return this.name;
}
public getEncounters() {
return this.encounters;
}
}
encounter.component.html:
<ul *ngFor="let encounter of encounters">
<li>{{encounter.getName()}}</li>
</ul>
encounter.component.ts:
@Component({
selector: 'app-encounter',
templateUrl: './encounter.component.html',
styleUrls: ['./encounter.component.css']
})
export class EncounterComponent implements OnInit {
@Input() encounters!: Encounter[];
constructor() {
}
ngOnInit(): void {
}
}
encounter.ts:
export class Encounter {
private readonly name?: string;
constructor(name: string){
this.name = name;
}
public getName() {
return this.name;
}
}
Visualization before clicking any button:
After clicking any button:
The issue seems to be easy to discover - when I click a button, the "showEncounters" boolean value changes for every other "wing", however I have no idea how to fix it. I was thinking about adding a "show" boolean to the wing.ts class, but I don't think it's a good idea to mix HTML DOM logic with object properties, so I abandoned this approach. What would be the correct way to show the encounters of the clicked wing only?
CodePudding user response:
You need to use a map of flags instead of single flag:
@Component({
selector: 'app-wing',
templateUrl: './wing.component.html',
styleUrls: ['./wing.component.css']
})
export class WingComponent implements OnInit {
wings = WINGS;
showEncounters: { [name: string]: boolean } = {};
constructor() {
}
ngOnInit(): void {
}
}
...
<ul>
<li *ngFor="let wing of wings">
<button (click)="showEncounters[wing.getName()] = !showEncounters[wing.getName()]">{{ wing.getName() }}</button>
<app-encounter
*ngIf="showEncounters[wing.getName()]"
[encounters]="wing.getEncounters()">
</app-encounter>
</li>
</ul>