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.
This commit is contained in:
Paul Gschwendtner
2018-08-21 20:38:17 +02:00
committed by Jeremy Elbourn
parent 9e3f093538
commit 9c184eae6f
6 changed files with 63 additions and 21 deletions
+13 -2
View File
@@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, Input} from '@angular/core';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {Directive, Input, OnChanges, OnDestroy, SimpleChanges} from '@angular/core';
import {Subject} from 'rxjs';
/** Used to generate unique ID for each accordion. */
@@ -20,7 +20,10 @@ let nextId = 0;
selector: 'cdk-accordion, [cdkAccordion]',
exportAs: 'cdkAccordion',
})
export class CdkAccordion {
export class CdkAccordion implements OnDestroy, OnChanges {
/** Emits when the state of the accordion changes */
readonly _stateChanges = new Subject<SimpleChanges>();
/** Stream that emits true/false when openAll/closeAll is triggered. */
readonly _openCloseAllActions: Subject<boolean> = new Subject<boolean>();
@@ -43,6 +46,14 @@ export class CdkAccordion {
this._openCloseAll(false);
}
ngOnChanges(changes: SimpleChanges) {
this._stateChanges.next(changes);
}
ngOnDestroy() {
this._stateChanges.complete();
}
private _openCloseAll(expanded: boolean): void {
if (this.multi) {
this._openCloseAllActions.next(expanded);
+4 -4
View File
@@ -62,17 +62,17 @@
</div>
</div>
<br>
<mat-accordion [displayMode]="displayMode" [multi]="multi"
<mat-accordion [displayMode]="displayMode" [multi]="multi" [hideToggle]="hideToggle"
class="demo-expansion-width">
<mat-expansion-panel #panel1 [hideToggle]="hideToggle">
<mat-expansion-panel #panel1>
<mat-expansion-panel-header>Section 1</mat-expansion-panel-header>
<p>This is the content text that makes sense here.</p>
</mat-expansion-panel>
<mat-expansion-panel #panel2 [hideToggle]="hideToggle" [disabled]="disabled">
<mat-expansion-panel #panel2 [disabled]="disabled">
<mat-expansion-panel-header>Section 2</mat-expansion-panel-header>
<p>This is the content text that makes sense here.</p>
</mat-expansion-panel>
<mat-expansion-panel #panel3 *ngIf="showPanel3" [hideToggle]="hideToggle">
<mat-expansion-panel #panel3 *ngIf="showPanel3">
<mat-expansion-panel-header>Section 3</mat-expansion-panel-header>
<mat-checkbox #showButtons>Reveal Buttons Below</mat-checkbox>
<mat-action-row *ngIf="showButtons.checked">
+29
View File
@@ -13,6 +13,7 @@ describe('MatAccordion', () => {
MatExpansionModule
],
declarations: [
AccordionWithHideToggle,
NestedPanel,
SetOfItems,
],
@@ -93,6 +94,22 @@ describe('MatAccordion', () => {
expect(innerPanel.accordion).not.toBe(outerPanel.accordion);
});
it('should update the expansion panel if hideToggle changed', () => {
const fixture = TestBed.createComponent(AccordionWithHideToggle);
const panel = fixture.debugElement.query(By.directive(MatExpansionPanel));
fixture.detectChanges();
expect(panel.nativeElement.querySelector('.mat-expansion-indicator'))
.toBeTruthy('Expected the expansion indicator to be present.');
fixture.componentInstance.hideToggle = true;
fixture.detectChanges();
expect(panel.nativeElement.querySelector('.mat-expansion-indicator'))
.toBeFalsy('Expected the expansion indicator to be removed.');
});
});
@@ -130,3 +147,15 @@ class NestedPanel {
@ViewChild('outerPanel') outerPanel: MatExpansionPanel;
@ViewChild('innerPanel') innerPanel: MatExpansionPanel;
}
@Component({template: `
<mat-accordion [hideToggle]="hideToggle">
<mat-expansion-panel>
<mat-expansion-panel-header>Header</mat-expansion-panel-header>
<p>Content</p>
</mat-expansion-panel>
</mat-accordion>`
})
class AccordionWithHideToggle {
hideToggle = false;
}
+1
View File
@@ -19,6 +19,7 @@ export type MatAccordionDisplayMode = 'default' | 'flat';
@Directive({
selector: 'mat-accordion',
exportAs: 'matAccordion',
inputs: ['multi'],
host: {
class: 'mat-accordion'
}
+10 -6
View File
@@ -19,7 +19,7 @@ import {
OnDestroy,
ViewEncapsulation,
} from '@angular/core';
import {merge, Subscription} from 'rxjs';
import {merge, Subscription, EMPTY} from 'rxjs';
import {filter} from 'rxjs/operators';
import {matExpansionAnimations} from './expansion-animations';
import {MatExpansionPanel} from './expansion-panel';
@@ -65,16 +65,20 @@ export class MatExpansionPanelHeader implements OnDestroy {
private _parentChangeSubscription = Subscription.EMPTY;
constructor(
@Host() public panel: MatExpansionPanel,
private _element: ElementRef,
private _focusMonitor: FocusMonitor,
private _changeDetectorRef: ChangeDetectorRef) {
@Host() public panel: MatExpansionPanel,
private _element: ElementRef,
private _focusMonitor: FocusMonitor,
private _changeDetectorRef: ChangeDetectorRef) {
const accordionHideToggleChange = panel.accordion ?
panel.accordion._stateChanges.pipe(filter(changes => !!changes.hideToggle)) : EMPTY;
// Since the toggle state depends on an @Input on the panel, we
// need to subscribe and trigger change detection manually.
// need to subscribe and trigger change detection manually.
this._parentChangeSubscription = merge(
panel.opened,
panel.closed,
accordionHideToggleChange,
panel._inputChanges.pipe(filter(changes => !!(changes.hideToggle || changes.disabled)))
)
.subscribe(() => this._changeDetectorRef.markForCheck());
+6 -9
View File
@@ -76,7 +76,9 @@ export class MatExpansionPanel extends _CdkAccordionItem
implements AfterContentInit, OnChanges, OnDestroy {
/** Whether the toggle indicator should be hidden. */
@Input()
get hideToggle(): boolean { return this._hideToggle; }
get hideToggle(): boolean {
return this._hideToggle || (this.accordion && this.accordion.hideToggle);
}
set hideToggle(value: boolean) {
this._hideToggle = coerceBooleanProperty(value);
}
@@ -111,17 +113,12 @@ export class MatExpansionPanel extends _CdkAccordionItem
this.accordion = accordion;
}
/** Whether the expansion indicator should be hidden. */
_getHideToggle(): boolean {
if (this.accordion) {
return this.accordion.hideToggle;
}
return this.hideToggle;
}
/** Determines whether the expansion panel should have spacing between it and its siblings. */
_hasSpacing(): boolean {
if (this.accordion) {
// We don't need to subscribe to the `stateChanges` of the parent accordion because each time
// the [displayMode] input changes, the change detection will also cover the host bindings
// of this expansion panel.
return (this.expanded ? this.accordion.displayMode : this._getExpandedState()) === 'default';
}
return false;