2
votes

See this Stackblitz.

Angular Material mat-expansion-panel allows lazy rendering,

<mat-expansion-panel>
  <mat-expansion-panel-header>
    This is the expansion title
  </mat-expansion-panel-header>

  <ng-template matExpansionPanelContent>
    Some deferred content
  </ng-template>
</mat-expansion-panel>

When rendered inside a hidden component, for example, a closed mat-sidenav, the mat-expansion-panel renders incorrectly (Stackblitz example):

enter image description here

This is a mess in many ways, not least because I define mat-expansion-panel to be collapsed (expanded="false"):

        <mat-expansion-panel expanded="false">

            <mat-expansion-panel-header>
                <mat-panel-title>
                    <span>First</span>
                </mat-panel-title>
            </mat-expansion-panel-header>

            <ng-template matExpansionPanelContent>
                <!-- Deferred initialization until the panel is open. -->
                <span>You shouldn't see me yet!</span></ng-template>

            <mat-action-row>
                <button mat-button>Click me</button>
            </mat-action-row>

        </mat-expansion-panel>

Clicking the expansion-panel's header expands the panel (as it should) and renders the content correctly:

enter image description here

Interestingly, collapsing the panel shows how the panel should have rendered initially:

enter image description here

Both my Stackblitz example and the screenshots in this question show two expansion panels within a mat-accordion:

<mat-tab-group>
    <mat-tab label="Empty">
        <p>This is an empty tab</p>
    </mat-tab>
    <mat-tab label="Accordion">
        <div class="mat-typography">
            <mat-accordion>
                <mat-expansion-panel expanded="true">
                    <mat-expansion-panel-header>
                        <mat-panel-title>
                            <span>First</span>
                        </mat-panel-title>
                    </mat-expansion-panel-header>
                    <ng-template matExpansionPanelContent>
                        <!-- Deferred initialization until the panel is open. -->
                        <span>You shouldn't see me yet!</span></ng-template>
                    <mat-action-row>
                        <button mat-button>Click me</button>
                    </mat-action-row>
                </mat-expansion-panel>
                <mat-expansion-panel expanded="false">
                    <mat-expansion-panel-header>
                        <mat-panel-title>
                            <span>Second</span>
                        </mat-panel-title>
                    </mat-expansion-panel-header>
                    <ng-template matExpansionPanelContent>
                        <!-- Deferred initialization until the panel is open. -->
                        <span>Shouldn't see me either!</span></ng-template>
                    <mat-action-row>
                        <button mat-button>Click me</button>
                    </mat-action-row>
                </mat-expansion-panel>
            </mat-accordion>
        </div>
    </mat-tab>
</mat-tab-group>

The CSS just adds some colour for debugging:

mat-expansion-panel {
  background-color: grey;
}

mat-expansion-panel:first-child mat-expansion-panel-header {
  background-color:red;
}
mat-expansion-panel:last-child  mat-expansion-panel-header {
  background-color:blue;
}

mat-expansion-panel button {
  background-color: yellow;
}

The mat-sidenav is about as bare-bones as it's possible to get:

<mat-sidenav-container>
    <mat-sidenav #snav class="mat-elevation-z8">
        <app-side-menu></app-side-menu>
    </mat-sidenav>
    <mat-sidenav-content>
        <div>
            <button mat-icon-button (click)="snav.toggle()">
        <mat-icon>menu</mat-icon>
      </button>
        </div>
    </mat-sidenav-content>
</mat-sidenav-container>

Update

A lengthy discussion on this has taken place on GitHub, issues/5269. While the issue remains open, it is being reported that the issue was fixed in angular/material v7.

3

3 Answers

2
votes

The problem is all about *ngIf. First time its not able to make it true. that's why I am setting it true using setTimeout().

If you still have issue do let me know. I will try to help.

Working link

https://stackblitz.com/edit/deferred-expansion-panel-broken-b2vurz?file=app%2Fside-menu%2Fside-menu.component.ts

0
votes

This is definitely problem with 5.x version, this should work out of the box.

Nothing worked if I had expansion panel [expanded] property set in html or initialised during constructor or component life cycle events.

Even working example from stackblitz is not working locally inside dynamic component! https://stackblitz.com/angular/bbjxooxpqmy?file=app%2Fexpansion-overview-example.html

However if structural directives are used with async data / Observables that are emitting after component is initialised and rendered it will work...

Using interval or timeouts works, but its not good solution because load and render times differ greatly on different devices such as desktop and mobile!

0
votes

Just a note on this, that it might be because you need to wrap the expanded property in square brackets, otherwise you are passing in a string of "false", which will evaluate to true.

It should be:

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