Mohit Harshan
Mohit Harshan

Reputation: 1986

close expansion panels using output and input events for dynamically added components

Im pushing dynamically added componnets to an array "elements"

 this.elements.push({ view, component });

Each of the components has a mat-expansion-panel like:

 <mat-expansion-panel fxFlex="100" [expanded]="!closed" (opened)="emitOpened()" >

Inside each of these components there is an Input() closed and an event emitter panelOpened emitted when the panel is opened:

  emitOpened() {
    this.panelOpened.emit();
  }

When one of these component's expansion panel is opened , the panels of all other components should get closed .

  closeOtherQuestions() {
    this.elements
      .map((el) => el.component)
      .forEach((c) => {
        c.panelOpened.subscribe((open) => {
          this.elements
            .map((el) => el.component)
            .filter((item) => item !== c)
            .forEach((item) => (item.closed = true));
        });
      });
  }

Im trying to pass in closed after subscribing to the output event of each of these components .Right now its not working correctly . Im seeing that the subscription is triggering multiple times as it is placed inside a forEach loop.

Upvotes: 1

Views: 452

Answers (1)

MoxxiManagarm
MoxxiManagarm

Reputation: 9124

You could use combineLatest in combination with pairWise to find the element in the array which should become closed. For this approach you would need to change panelOpened event to a expansionChanged event which holds the current state as a boolean.

emitOpened() {
    this.expansionChanged.emit(true);
  }

emitClosed() {
    this.expansionChanged.emit(false);
  }

Now you can do

combineLatest(this.elements.map(el => el.component.expansionChanged)).pipe(
  pairWise(),
  map(([prev, curr]) => curr.findIndex((el, i) => el && prev[i])),
).subscribe(
  index => this.elements[index].component.closed = true;
);

Upvotes: 1

Related Questions