Home > Net >  Angular component list within another component
Angular component list within another component

Time:09-22

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:

before

After clicking any button:

after

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>
  • Related