Skip to content

Commit 9bf720a

Browse files
josephperrottmmalerba
authored andcommitted
fix: prevent nested expansion panels from registering to the same accordion (#11342)
1 parent e592615 commit 9bf720a

File tree

4 files changed

+63
-6
lines changed

4 files changed

+63
-6
lines changed

src/cdk/accordion/accordion-item.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
OnDestroy,
1515
Optional,
1616
ChangeDetectorRef,
17+
SkipSelf,
1718
} from '@angular/core';
1819
import {UniqueSelectionDispatcher} from '@angular/cdk/collections';
1920
import {CdkAccordion} from './accordion';
@@ -30,6 +31,11 @@ let nextId = 0;
3031
@Directive({
3132
selector: 'cdk-accordion-item, [cdkAccordionItem]',
3233
exportAs: 'cdkAccordionItem',
34+
providers: [
35+
// Provide CdkAccordion as undefined to prevent nested accordion items from registering
36+
// to the same accordion.
37+
{provide: CdkAccordion, useValue: undefined},
38+
],
3339
})
3440
export class CdkAccordionItem implements OnDestroy {
3541
/** Subscription to openAll/closeAll events. */
@@ -90,7 +96,7 @@ export class CdkAccordionItem implements OnDestroy {
9096
/** Unregister function for _expansionDispatcher. */
9197
private _removeUniqueSelectionListener: () => void = () => {};
9298

93-
constructor(@Optional() public accordion: CdkAccordion,
99+
constructor(@Optional() @SkipSelf() public accordion: CdkAccordion,
94100
private _changeDetectorRef: ChangeDetectorRef,
95101
protected _expansionDispatcher: UniqueSelectionDispatcher) {
96102
this._removeUniqueSelectionListener =

src/cdk/accordion/accordion.spec.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ describe('CdkAccordion', () => {
1212
CdkAccordionModule
1313
],
1414
declarations: [
15-
SetOfItems
15+
SetOfItems,
16+
NestedItems,
1617
],
1718
});
1819
TestBed.compileComponents();
@@ -53,6 +54,14 @@ describe('CdkAccordion', () => {
5354
expect(firstPanel.expanded).toBeTruthy();
5455
expect(secondPanel.expanded).toBeTruthy();
5556
});
57+
58+
it('should not register nested items to the same accordion', () => {
59+
const fixture = TestBed.createComponent(NestedItems);
60+
const innerItem = fixture.componentInstance.innerItem;
61+
const outerItem = fixture.componentInstance.outerItem;
62+
63+
expect(innerItem.accordion).not.toBe(outerItem.accordion);
64+
});
5665
});
5766

5867
@Component({template: `
@@ -65,3 +74,15 @@ class SetOfItems {
6574
@ViewChild('item2') item2;
6675
multi: boolean = false;
6776
}
77+
78+
79+
@Component({template: `
80+
<cdk-accordion>
81+
<cdk-accordion-item #outerItem="cdkAccordionItem">
82+
<cdk-accordion-item #innerItem="cdkAccordionItem"></cdk-accordion-item>
83+
</cdk-accordion-item>
84+
</cdk-accordion>`})
85+
class NestedItems {
86+
@ViewChild('outerItem') outerItem: CdkAccordionItem;
87+
@ViewChild('innerItem') innerItem: CdkAccordionItem;
88+
}

src/lib/expansion/accordion.spec.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,19 @@ import {async, TestBed} from '@angular/core/testing';
22
import {Component, ViewChild} from '@angular/core';
33
import {By} from '@angular/platform-browser';
44
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
5-
import {MatExpansionModule, MatAccordion} from './index';
5+
import {MatExpansionModule, MatAccordion, MatExpansionPanel} from './index';
66

77

8-
describe('CdkAccordion', () => {
8+
describe('MatAccordion', () => {
99
beforeEach(async(() => {
1010
TestBed.configureTestingModule({
1111
imports: [
1212
BrowserAnimationsModule,
1313
MatExpansionModule
1414
],
1515
declarations: [
16-
SetOfItems
16+
NestedPanel,
17+
SetOfItems,
1718
],
1819
});
1920
TestBed.compileComponents();
@@ -84,6 +85,14 @@ describe('CdkAccordion', () => {
8485
expect(panels[0].classes['mat-expanded']).toBeFalsy();
8586
expect(panels[1].classes['mat-expanded']).toBeFalsy();
8687
});
88+
89+
it('should not register nested panels to the same accordion', () => {
90+
const fixture = TestBed.createComponent(NestedPanel);
91+
const innerPanel = fixture.componentInstance.innerPanel;
92+
const outerPanel = fixture.componentInstance.outerPanel;
93+
94+
expect(innerPanel.accordion).not.toBe(outerPanel.accordion);
95+
});
8796
});
8897

8998

@@ -106,3 +115,18 @@ class SetOfItems {
106115
secondPanelExpanded: boolean = false;
107116
secondPanelDisabled: boolean = false;
108117
}
118+
119+
@Component({template: `
120+
<mat-accordion>
121+
<mat-expansion-panel #outerPanel="matExpansionPanel">
122+
<mat-expansion-panel-header>Outer Panel</mat-expansion-panel-header>
123+
<mat-expansion-panel #innerPanel="matExpansionPanel">
124+
<mat-expansion-panel-header>Inner Panel</mat-expansion-panel-header>
125+
<p>Content</p>
126+
</mat-expansion-panel>
127+
</mat-expansion-panel>
128+
</mat-accordion>`})
129+
class NestedPanel {
130+
@ViewChild('outerPanel') outerPanel: MatExpansionPanel;
131+
@ViewChild('innerPanel') innerPanel: MatExpansionPanel;
132+
}

src/lib/expansion/expansion-panel.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
OnDestroy,
2424
Optional,
2525
SimpleChanges,
26+
SkipSelf,
2627
ViewContainerRef,
2728
ViewEncapsulation,
2829
} from '@angular/core';
@@ -56,6 +57,11 @@ let uniqueId = 0;
5657
inputs: ['disabled', 'expanded'],
5758
outputs: ['opened', 'closed', 'expandedChange'],
5859
animations: [matExpansionAnimations.bodyExpansion],
60+
providers: [
61+
// Provide MatAccordion as undefined to prevent nested expansion panels from registering
62+
// to the same accordion.
63+
{provide: MatAccordion, useValue: undefined},
64+
],
5965
host: {
6066
'class': 'mat-expansion-panel',
6167
'[class.mat-expanded]': 'expanded',
@@ -87,7 +93,7 @@ export class MatExpansionPanel extends CdkAccordionItem
8793
/** ID for the associated header element. Used for a11y labelling. */
8894
_headerId = `mat-expansion-panel-header-${uniqueId++}`;
8995

90-
constructor(@Optional() accordion: MatAccordion,
96+
constructor(@Optional() @SkipSelf() accordion: MatAccordion,
9197
_changeDetectorRef: ChangeDetectorRef,
9298
_uniqueSelectionDispatcher: UniqueSelectionDispatcher,
9399
private _viewContainerRef: ViewContainerRef) {

0 commit comments

Comments
 (0)