Skip to content

Commit 803f73f

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 0d8a5c1 commit 803f73f

File tree

6 files changed

+64
-22
lines changed

6 files changed

+64
-22
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: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,17 @@ <h1>matAccordion</h1>
5555
</div>
5656
</div>
5757
<br>
58-
<mat-accordion [displayMode]="displayMode" [multi]="multi"
59-
class="demo-expansion-width">
60-
<mat-expansion-panel #panel1 [hideToggle]="hideToggle">
58+
<mat-accordion [displayMode]="displayMode" [multi]="multi" [hideToggle]="hideToggle"
59+
class="demo-expansion-width">
60+
<mat-expansion-panel #panel1>
6161
<mat-expansion-panel-header>Section 1</mat-expansion-panel-header>
6262
<p>This is the content text that makes sense here.</p>
6363
</mat-expansion-panel>
64-
<mat-expansion-panel #panel2 [hideToggle]="hideToggle" [disabled]="disabled">
64+
<mat-expansion-panel #panel2 [disabled]="disabled">
6565
<mat-expansion-panel-header>Section 2</mat-expansion-panel-header>
6666
<p>This is the content text that makes sense here.</p>
6767
</mat-expansion-panel>
68-
<mat-expansion-panel #panel3 *ngIf="showPanel3" [hideToggle]="hideToggle">
68+
<mat-expansion-panel #panel3 *ngIf="showPanel3">
6969
<mat-expansion-panel-header>Section 3</mat-expansion-panel-header>
7070
<mat-checkbox #showButtons>Reveal Buttons Below</mat-checkbox>
7171
<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
@@ -74,7 +74,9 @@ export class MatExpansionPanel extends _CdkAccordionItem
7474
implements AfterContentInit, OnChanges, OnDestroy {
7575
/** Whether the toggle indicator should be hidden. */
7676
@Input()
77-
get hideToggle(): boolean { return this._hideToggle; }
77+
get hideToggle(): boolean {
78+
return this._hideToggle || (this.accordion && this.accordion.hideToggle);
79+
}
7880
set hideToggle(value: boolean) {
7981
this._hideToggle = coerceBooleanProperty(value);
8082
}
@@ -103,17 +105,12 @@ export class MatExpansionPanel extends _CdkAccordionItem
103105
this.accordion = accordion;
104106
}
105107

106-
/** Whether the expansion indicator should be hidden. */
107-
_getHideToggle(): boolean {
108-
if (this.accordion) {
109-
return this.accordion.hideToggle;
110-
}
111-
return this.hideToggle;
112-
}
113-
114108
/** Determines whether the expansion panel should have spacing between it and its siblings. */
115109
_hasSpacing(): boolean {
116110
if (this.accordion) {
111+
// We don't need to subscribe to the `stateChanges` of the parent accordion because each time
112+
// the [displayMode] input changes, the change detection will also cover the host bindings
113+
// of this expansion panel.
117114
return (this.expanded ? this.accordion.displayMode : this._getExpandedState()) === 'default';
118115
}
119116
return false;

0 commit comments

Comments
 (0)