Skip to content

Commit 9c184ea

Browse files
devversionjelbourn
authored andcommitted
fix(expansion): respect parent accordion hideToggle binding (#12725)
* Fixes that the expansion panels no longer respect the bindings of a parent `<mat-accordion>`. (this has been accidentally changes in #6529) * Fixes that the expansion panel does not re-render if the `[hideToggle]` binding is set on the accordion. * Removes the unused `_getHideToggle` method. This method is no longer used because the panel header directly accesses the panel through DI.
1 parent 9e3f093 commit 9c184ea

File tree

6 files changed

+63
-21
lines changed

6 files changed

+63
-21
lines changed

src/cdk/accordion/accordion.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Directive, Input} from '@angular/core';
109
import {coerceBooleanProperty} from '@angular/cdk/coercion';
10+
import {Directive, Input, OnChanges, OnDestroy, SimpleChanges} from '@angular/core';
1111
import {Subject} from 'rxjs';
1212

1313
/** Used to generate unique ID for each accordion. */
@@ -20,7 +20,10 @@ let nextId = 0;
2020
selector: 'cdk-accordion, [cdkAccordion]',
2121
exportAs: 'cdkAccordion',
2222
})
23-
export class CdkAccordion {
23+
export class CdkAccordion implements OnDestroy, OnChanges {
24+
/** Emits when the state of the accordion changes */
25+
readonly _stateChanges = new Subject<SimpleChanges>();
26+
2427
/** Stream that emits true/false when openAll/closeAll is triggered. */
2528
readonly _openCloseAllActions: Subject<boolean> = new Subject<boolean>();
2629

@@ -43,6 +46,14 @@ export class CdkAccordion {
4346
this._openCloseAll(false);
4447
}
4548

49+
ngOnChanges(changes: SimpleChanges) {
50+
this._stateChanges.next(changes);
51+
}
52+
53+
ngOnDestroy() {
54+
this._stateChanges.complete();
55+
}
56+
4657
private _openCloseAll(expanded: boolean): void {
4758
if (this.multi) {
4859
this._openCloseAllActions.next(expanded);

src/demo-app/expansion/expansion-demo.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,17 @@ <h1>matAccordion</h1>
6262
</div>
6363
</div>
6464
<br>
65-
<mat-accordion [displayMode]="displayMode" [multi]="multi"
65+
<mat-accordion [displayMode]="displayMode" [multi]="multi" [hideToggle]="hideToggle"
6666
class="demo-expansion-width">
67-
<mat-expansion-panel #panel1 [hideToggle]="hideToggle">
67+
<mat-expansion-panel #panel1>
6868
<mat-expansion-panel-header>Section 1</mat-expansion-panel-header>
6969
<p>This is the content text that makes sense here.</p>
7070
</mat-expansion-panel>
71-
<mat-expansion-panel #panel2 [hideToggle]="hideToggle" [disabled]="disabled">
71+
<mat-expansion-panel #panel2 [disabled]="disabled">
7272
<mat-expansion-panel-header>Section 2</mat-expansion-panel-header>
7373
<p>This is the content text that makes sense here.</p>
7474
</mat-expansion-panel>
75-
<mat-expansion-panel #panel3 *ngIf="showPanel3" [hideToggle]="hideToggle">
75+
<mat-expansion-panel #panel3 *ngIf="showPanel3">
7676
<mat-expansion-panel-header>Section 3</mat-expansion-panel-header>
7777
<mat-checkbox #showButtons>Reveal Buttons Below</mat-checkbox>
7878
<mat-action-row *ngIf="showButtons.checked">

src/lib/expansion/accordion.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ describe('MatAccordion', () => {
1313
MatExpansionModule
1414
],
1515
declarations: [
16+
AccordionWithHideToggle,
1617
NestedPanel,
1718
SetOfItems,
1819
],
@@ -93,6 +94,22 @@ describe('MatAccordion', () => {
9394

9495
expect(innerPanel.accordion).not.toBe(outerPanel.accordion);
9596
});
97+
98+
it('should update the expansion panel if hideToggle changed', () => {
99+
const fixture = TestBed.createComponent(AccordionWithHideToggle);
100+
const panel = fixture.debugElement.query(By.directive(MatExpansionPanel));
101+
102+
fixture.detectChanges();
103+
104+
expect(panel.nativeElement.querySelector('.mat-expansion-indicator'))
105+
.toBeTruthy('Expected the expansion indicator to be present.');
106+
107+
fixture.componentInstance.hideToggle = true;
108+
fixture.detectChanges();
109+
110+
expect(panel.nativeElement.querySelector('.mat-expansion-indicator'))
111+
.toBeFalsy('Expected the expansion indicator to be removed.');
112+
});
96113
});
97114

98115

@@ -130,3 +147,15 @@ class NestedPanel {
130147
@ViewChild('outerPanel') outerPanel: MatExpansionPanel;
131148
@ViewChild('innerPanel') innerPanel: MatExpansionPanel;
132149
}
150+
151+
@Component({template: `
152+
<mat-accordion [hideToggle]="hideToggle">
153+
<mat-expansion-panel>
154+
<mat-expansion-panel-header>Header</mat-expansion-panel-header>
155+
<p>Content</p>
156+
</mat-expansion-panel>
157+
</mat-accordion>`
158+
})
159+
class AccordionWithHideToggle {
160+
hideToggle = false;
161+
}

src/lib/expansion/accordion.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export type MatAccordionDisplayMode = 'default' | 'flat';
1919
@Directive({
2020
selector: 'mat-accordion',
2121
exportAs: 'matAccordion',
22+
inputs: ['multi'],
2223
host: {
2324
class: 'mat-accordion'
2425
}

src/lib/expansion/expansion-panel-header.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
OnDestroy,
2020
ViewEncapsulation,
2121
} from '@angular/core';
22-
import {merge, Subscription} from 'rxjs';
22+
import {merge, Subscription, EMPTY} from 'rxjs';
2323
import {filter} from 'rxjs/operators';
2424
import {matExpansionAnimations} from './expansion-animations';
2525
import {MatExpansionPanel} from './expansion-panel';
@@ -65,16 +65,20 @@ export class MatExpansionPanelHeader implements OnDestroy {
6565
private _parentChangeSubscription = Subscription.EMPTY;
6666

6767
constructor(
68-
@Host() public panel: MatExpansionPanel,
69-
private _element: ElementRef,
70-
private _focusMonitor: FocusMonitor,
71-
private _changeDetectorRef: ChangeDetectorRef) {
68+
@Host() public panel: MatExpansionPanel,
69+
private _element: ElementRef,
70+
private _focusMonitor: FocusMonitor,
71+
private _changeDetectorRef: ChangeDetectorRef) {
72+
73+
const accordionHideToggleChange = panel.accordion ?
74+
panel.accordion._stateChanges.pipe(filter(changes => !!changes.hideToggle)) : EMPTY;
7275

7376
// Since the toggle state depends on an @Input on the panel, we
74-
// need to subscribe and trigger change detection manually.
77+
// need to subscribe and trigger change detection manually.
7578
this._parentChangeSubscription = merge(
7679
panel.opened,
7780
panel.closed,
81+
accordionHideToggleChange,
7882
panel._inputChanges.pipe(filter(changes => !!(changes.hideToggle || changes.disabled)))
7983
)
8084
.subscribe(() => this._changeDetectorRef.markForCheck());

src/lib/expansion/expansion-panel.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ export class MatExpansionPanel extends _CdkAccordionItem
7676
implements AfterContentInit, OnChanges, OnDestroy {
7777
/** Whether the toggle indicator should be hidden. */
7878
@Input()
79-
get hideToggle(): boolean { return this._hideToggle; }
79+
get hideToggle(): boolean {
80+
return this._hideToggle || (this.accordion && this.accordion.hideToggle);
81+
}
8082
set hideToggle(value: boolean) {
8183
this._hideToggle = coerceBooleanProperty(value);
8284
}
@@ -111,17 +113,12 @@ export class MatExpansionPanel extends _CdkAccordionItem
111113
this.accordion = accordion;
112114
}
113115

114-
/** Whether the expansion indicator should be hidden. */
115-
_getHideToggle(): boolean {
116-
if (this.accordion) {
117-
return this.accordion.hideToggle;
118-
}
119-
return this.hideToggle;
120-
}
121-
122116
/** Determines whether the expansion panel should have spacing between it and its siblings. */
123117
_hasSpacing(): boolean {
124118
if (this.accordion) {
119+
// We don't need to subscribe to the `stateChanges` of the parent accordion because each time
120+
// the [displayMode] input changes, the change detection will also cover the host bindings
121+
// of this expansion panel.
125122
return (this.expanded ? this.accordion.displayMode : this._getExpandedState()) === 'default';
126123
}
127124
return false;

0 commit comments

Comments
 (0)