20

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"> ...

8 Answers 8

29

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;
  }
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for your update Juan - Is there any simple way of opening a specific panel? Imagine that the button is within the header of the panel itself
@juan , hello. I am using multiple panel with *ngFor. But the problem is my trigger button is outside the panel-header. I can't bind the the "expanded" value to the button. Can you help me please ??
@AnzilkhaN I made an StackBlitz stackblitz.com/edit/angular-hyfoc1 where you can see the solution. I used a button outside the scope of the <mat-expansion-panel> and a text field to point to the desired panel by index (remember that the index starts in 0).
In the first part of your example, if the panel doesn't close for you, try adding parenthesis to the variable in the HTML... <mat-expansion-panel [(expanded)]="panelOpenState"> ...worked for me.
24
<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>

3 Comments

It works perfectly, but how?.. Can you please explain it.
@Ash The way it works: #mep means, assign the expansion panel instance to a variable on your component. This means the (click) event handler can now use mep to interact with the panel. The default value for expanded is false, so to toggle the expansion panel, you reassign the inverse (using "!") to the expanded property on that expansion panel.
using disabled greys out the entire panel. probably not desired.
6

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>

3 Comments

The link content surely contain the answer but it's always better to put the relevant part of the content in the post and leave the link only as reference.
Hi, DaFois. I added the html to the answer post text.
@CarlSorenson, what about if i have multiple panel ?? Now it will collapse all the other panel. Can you please help ??
1

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()

Comments

1
<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

Comments

0
<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>

Comments

0

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

Comments

0

Another way is to prevent the click event from propagating.

<mat-accordion class="example-headers-align" multi>
  <mat-expansion-panel>
    <mat-expansion-panel-header>
      <div class="my-panel"  (click)="$event.stopPropagation();">
        <h3>Panel Header</h3>
 <button mat-stroked-button (click)="myButton()">my button</button>
      </div>
    </mat-expansion-panel-header>

    <div>My panel content!</div>
  </mat-expansion-panel>
</mat-accordion>

Reference: Expand Panel Only On Icon Click Angular Material

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.