16
votes

Is there any way in which I can expand a particular mat-expansion-panel by clicking an external button?

I have tried linking to the ID of the panel, but with no success...

<mat-expansion-panel id="panel1"> ... </>
...
<button (click)="document.getElementById('panel1').toggle()>Click me</button>

Here is my stackblitz code for example

My eventual plan is to use this method to open different panels within a list generated from an array: <mat-expansion-panel *ngFor="let d of data"> ...

7

7 Answers

23
votes

In your html file:

<mat-expansion-panel [expanded]="panelOpenState">

    <mat-expansion-panel-header>
        <mat-panel-title>
            TITLE
        </mat-panel-title>
    </mat-expansion-panel-header>

    <p>BODY</p>
</mat-expansion-panel>

<button mat-raised-button (click)="togglePanel">TOGGLE</button>

In your TS file:

panelOpenState: boolean = false;

togglePanel() {
    this.panelOpenState = !this.panelOpenState
}

If you use *ngFor to generate the expansion panels:

<mat-expansion-panel [expanded]="isOpen" *ngFor="let d of data">
    <mat-expansion-panel-header>
        {{ d.header }}
    </mat-expansion-panel-header>
    <p>{{ d.content }}</p>
</mat-expansion-panel>

<button mat-raised-button (click)="togglePanel">TOGGLE</button>

If you press the button all of the expanded panels opens simultaneously.

To open only one panel with one button, add a "expanded" property to the data array for each element like this:

  data = [
    {id:1, header:'HEADER 1', content:'CONTENT 1', expanded: false},
    {id:2, header:'HEADER 2', content:'CONTENT 2', expanded: false},
    {id:3, header:'HEADER 3', content:'CONTENT 3', expanded: false},
    {id:4, header:'HEADER 4', content:'CONTENT 4', expanded: false},
  ]

Then in your template:

<mat-expansion-panel [(ngModel)]="d.expanded" 
    [expanded]="d.expanded" *ngFor="let d of data" ngDefaultControl>

    <mat-expansion-panel-header>
        <button (click)="toggle(d.expanded)">TOGGLE</button>
        {{ d.header }}
    </mat-expansion-panel-header>
    <p>{{ d.content }}</p>

</mat-expansion-panel>

And the method raised by the button click:

  toggle(expanded) {
    expanded = !expanded;
  }
16
votes
<mat-expansion-panel [disabled]="true"
                     #mep="matExpansionPanel"
                     *ngFor="let foo of list">
  <mat-expansion-panel-header>
      <button (click)="mep.expanded = !mep.expanded">Toggle</button>
  </mat-expansion-panel-header>

  <p>Text</p>

</mat-expansion-panel>
5
votes

Use two-way binding on the expanded attribute of mat-expansion-panel. Here is an example live in StackBlitz:

https://stackblitz.com/edit/angular-gtsqg8

<button (click)='xpandStatus=xpandStatus?false:true'>Toggle it</button>
<p>
<mat-expansion-panel [(expanded)]="xpandStatus">
  <mat-expansion-panel-header>
    <mat-panel-title>This an expansion panel</mat-panel-title>
    <mat-panel-description>xpandStatus is {{xpandStatus}}</mat-panel-description>
  </mat-expansion-panel-header>
  Two-way binding on the expanded attribute gives us a way to store and manipulate the expansion status.
</mat-expansion-panel>
</p>
1
votes

You can use the method toggle().

First give the element an id.

<mat-expansion-panel #matExpansionPanel>

Next, access the element from javascript. Import necessary libraries (MatExpansionPanel, ViewChild)

@ViewChild(MatExpansionPanel, {static: true}) matExpansionPanelElement: MatExpansionPanel;

Lastly, call the toggle function

this.matExpansionPanelElement.toggle(); //open(), close()
0
votes
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<mat-accordion displayMode="flat" multi class="mat-table">
    <section matSort class="mat-elevation-z8 mat-header-row">
        <span class="mat-header-cell" mat-sort-header="vesselName"></span>
        <span class="mat-header-cell" mat-sort-header="vesselName">d</span>
    </section>

    <mat-expansion-panel [disabled]="true" #mep="matExpansionPanel"
                         *ngFor="let d of data">
        <mat-expansion-panel-header>
            <span class="mat-cell" (click)="mep.expanded = !mep.expanded">
                <mat-icon class="icon" *ngIf="!mep.expanded">expand_more</mat-icon>
                <mat-icon class="icon" *ngIf="mep.expanded">expand_less</mat-icon>
            </span>
            <span (click)="dClicked(d)" class="mat-cell">{{d.dataSet}}</span>
        </mat-expansion-panel-header>
        <div><pre>{{d | json}}</pre></div>
    </mat-expansion-panel>
    <div class="well" *ngIf="!d || d.length == 0">
        <p>There are no d for this.</p>
    </div>
</mat-accordion>
0
votes

html:

<mat-accordion >
    <mat-expansion-panel #first="matExpansionPanel">
        <mat-expansion-panel-header>
            <mat-panel-title>...</mat-panel-title>
        </mat-expansion-panel-header>
        ...
    </mat-expansion-panel>

    <mat-expansion-panel #second="matExpansionPanel" expanded="true">
        <mat-expansion-panel-header>
            <mat-panel-title>...</mat-panel-title>
        </mat-expansion-panel-header>
        ...
    </mat-expansion-panel>
</mat-accordion>

<button (click)="doSomething(first, second)">Click</button>

ts:

import { Component } from '@angular/core';
import { MatExpansionPanel } from '@angular/material';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html'
})
export class HomeComponent {

  doSomething(first: MatExpansionPanel, second: MatExpansionPanel) {
    if (first.expanded ) {  // check if first panel is expanded
      first.close(); // close first panel
      second.open(); // open second panel
      // ...
    }
  }
}

Read more

0
votes
<mat-nav-list>
  <mat-expansion-panel *ngFor="let row of rows" #mep="matExpansionPanel">
    <mat-expansion-panel-header>
      {{row}}
    </mat-expansion-panel-header>
   <h2>Test</h2>
    <button (click)="mep.toggle()">Toggle</button>
  </mat-expansion-panel>
</mat-nav-list>

Working Example: https://stackblitz.com/edit/mat-expansion-panel-vymjsq?file=app%2Fexpansion-overview-example.html