Skip to content

fix(material/expansion): picking up lazy content from child component #14477

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/material/expansion/expansion-panel-base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {InjectionToken} from '@angular/core';
import {CdkAccordionItem} from '@angular/cdk/accordion';

/**
* Base interface for a `MatExpansionPanel`.
* @docs-private
*/
export interface MatExpansionPanelBase extends CdkAccordionItem {
/** Whether the toggle indicator should be hidden. */
hideToggle: boolean;
}

/**
* Token used to provide a `MatExpansionPanel` to `MatExpansionPanelContent`.
* Used to avoid circular imports between `MatExpansionPanel` and `MatExpansionPanelContent`.
*/
export const MAT_EXPANSION_PANEL = new InjectionToken<MatExpansionPanelBase>('MAT_EXPANSION_PANEL');
8 changes: 6 additions & 2 deletions src/material/expansion/expansion-panel-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Directive, TemplateRef} from '@angular/core';
import {Directive, TemplateRef, Inject, Optional} from '@angular/core';
import {MAT_EXPANSION_PANEL, MatExpansionPanelBase} from './expansion-panel-base';

/**
* Expansion panel content that will be rendered lazily
Expand All @@ -16,5 +17,8 @@ import {Directive, TemplateRef} from '@angular/core';
selector: 'ng-template[matExpansionPanelContent]',
})
export class MatExpansionPanelContent {
constructor(public _template: TemplateRef<any>) {}
constructor(
public _template: TemplateRef<any>,
@Inject(MAT_EXPANSION_PANEL) @Optional() public _expansionPanel?: MatExpansionPanelBase,
) {}
}
4 changes: 3 additions & 1 deletion src/material/expansion/expansion-panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {Subject} from 'rxjs';
import {distinctUntilChanged, filter, startWith, take} from 'rxjs/operators';
import {MatAccordionBase, MatAccordionTogglePosition, MAT_ACCORDION} from './accordion-base';
import {matExpansionAnimations} from './expansion-animations';
import {MAT_EXPANSION_PANEL} from './expansion-panel-base';
import {MatExpansionPanelContent} from './expansion-panel-content';

/** MatExpansionPanel's states. */
Expand Down Expand Up @@ -87,6 +88,7 @@ export const MAT_EXPANSION_PANEL_DEFAULT_OPTIONS =
// Provide MatAccordion as undefined to prevent nested expansion panels from registering
// to the same accordion.
{provide: MAT_ACCORDION, useValue: undefined},
{provide: MAT_EXPANSION_PANEL, useExisting: MatExpansionPanel},
],
host: {
'class': 'mat-expansion-panel',
Expand Down Expand Up @@ -215,7 +217,7 @@ export class MatExpansionPanel
}

ngAfterContentInit() {
if (this._lazyContent) {
if (this._lazyContent && this._lazyContent._expansionPanel === this) {
// Render the content as soon as the panel becomes open.
this.opened
.pipe(
Expand Down
47 changes: 47 additions & 0 deletions src/material/expansion/expansion.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ describe('MatExpansionPanel', () => {
LazyPanelOpenOnLoad,
PanelWithTwoWayBinding,
PanelWithHeaderTabindex,
NestedLazyPanelWithContent,
],
});
TestBed.compileComponents();
Expand Down Expand Up @@ -91,6 +92,36 @@ describe('MatExpansionPanel', () => {
.toContain('Some content');
}));

it('should not render lazy content from a child panel inside the parent', fakeAsync(() => {
const fixture = TestBed.createComponent(NestedLazyPanelWithContent);
fixture.componentInstance.parentExpanded = true;
fixture.detectChanges();

const parentContent: HTMLElement = fixture.nativeElement.querySelector(
'.parent-panel .mat-expansion-panel-content',
);
const childContent: HTMLElement = fixture.nativeElement.querySelector(
'.child-panel .mat-expansion-panel-content',
);

expect(parentContent.textContent!.trim()).toBe(
'Parent content',
'Expected only parent content to be rendered.',
);
expect(childContent.textContent!.trim()).toBe(
'',
'Expected child content element to be empty.',
);

fixture.componentInstance.childExpanded = true;
fixture.detectChanges();

expect(childContent.textContent!.trim()).toBe(
'Child content',
'Expected child content element to be rendered.',
);
}));

it('emit correct events for change in panel expanded state', () => {
const fixture = TestBed.createComponent(PanelWithContent);
fixture.componentInstance.expanded = true;
Expand Down Expand Up @@ -621,3 +652,19 @@ class PanelWithTwoWayBinding {
</mat-expansion-panel>`,
})
class PanelWithHeaderTabindex {}

@Component({
template: `
<mat-expansion-panel class="parent-panel" [expanded]="parentExpanded">
Parent content

<mat-expansion-panel class="child-panel" [expanded]="childExpanded">
<ng-template matExpansionPanelContent>Child content</ng-template>
</mat-expansion-panel>
</mat-expansion-panel>
`,
})
class NestedLazyPanelWithContent {
parentExpanded = false;
childExpanded = false;
}
1 change: 1 addition & 0 deletions src/material/expansion/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export * from './expansion-panel';
export * from './expansion-panel-header';
export * from './expansion-panel-content';
export * from './expansion-animations';
export {MAT_EXPANSION_PANEL} from './expansion-panel-base';
9 changes: 7 additions & 2 deletions tools/public_api_guard/material/expansion.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export const EXPANSION_PANEL_ANIMATION_TIMING = "225ms cubic-bezier(0.4,0.0,0.2,
// @public
export const MAT_ACCORDION: InjectionToken<MatAccordionBase>;

// @public
export const MAT_EXPANSION_PANEL: InjectionToken<MatExpansionPanelBase>;

// @public
export const MAT_EXPANSION_PANEL_DEFAULT_OPTIONS: InjectionToken<MatExpansionPanelDefaultOptions>;

Expand Down Expand Up @@ -142,13 +145,15 @@ export class MatExpansionPanelActionRow {

// @public
export class MatExpansionPanelContent {
constructor(_template: TemplateRef<any>);
constructor(_template: TemplateRef<any>, _expansionPanel?: MatExpansionPanelBase | undefined);
// (undocumented)
_expansionPanel?: MatExpansionPanelBase | undefined;
// (undocumented)
_template: TemplateRef<any>;
// (undocumented)
static ɵdir: i0.ɵɵDirectiveDeclaration<MatExpansionPanelContent, "ng-template[matExpansionPanelContent]", never, {}, {}, never>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<MatExpansionPanelContent, never>;
static ɵfac: i0.ɵɵFactoryDeclaration<MatExpansionPanelContent, [null, { optional: true; }]>;
}

// @public
Expand Down