From 6ffbbd477173bd6790dc0b2ae493a732d6d40d58 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Wed, 10 Jan 2018 23:49:37 +0100 Subject: [PATCH] feat(expansion-panel): support two-way binding for the expanded property * Supports two-way binding to the `expanded` property on the expansion panel. * Fixes som wrong indentation in the tests. Fixes #9311. --- src/cdk/accordion/accordion-item.ts | 10 ++++++ src/lib/expansion/expansion-panel.ts | 2 +- src/lib/expansion/expansion.spec.ts | 46 ++++++++++++++++++++++------ 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/cdk/accordion/accordion-item.ts b/src/cdk/accordion/accordion-item.ts index d6a8ff69b993..54d22935c874 100644 --- a/src/cdk/accordion/accordion-item.ts +++ b/src/cdk/accordion/accordion-item.ts @@ -37,6 +37,14 @@ export class CdkAccordionItem implements OnDestroy { @Output() opened: EventEmitter = new EventEmitter(); /** Event emitted when the AccordionItem is destroyed. */ @Output() destroyed: EventEmitter = new EventEmitter(); + + /** + * Emits whenever the expanded state of the accordion changes. + * Primarily used to facilitate two-way binding. + * @docs-private + */ + @Output() expandedChange: EventEmitter = new EventEmitter(); + /** The unique AccordionItem id. */ readonly id: string = `cdk-accordion-child-${nextId++}`; @@ -49,6 +57,8 @@ export class CdkAccordionItem implements OnDestroy { // Only emit events and update the internal value if the value changes. if (this._expanded !== expanded) { this._expanded = expanded; + this.expandedChange.emit(expanded); + if (expanded) { this.opened.emit(); /** diff --git a/src/lib/expansion/expansion-panel.ts b/src/lib/expansion/expansion-panel.ts index 1a3f92f5bd53..f3aad2f09703 100644 --- a/src/lib/expansion/expansion-panel.ts +++ b/src/lib/expansion/expansion-panel.ts @@ -73,7 +73,7 @@ export type MatExpansionPanelState = 'expanded' | 'collapsed'; preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, inputs: ['disabled', 'expanded'], - outputs: ['opened', 'closed'], + outputs: ['opened', 'closed', 'expandedChange'], animations: [matExpansionAnimations.bodyExpansion], host: { 'class': 'mat-expansion-panel', diff --git a/src/lib/expansion/expansion.spec.ts b/src/lib/expansion/expansion.spec.ts index fddb687bcb6d..470f7c8120d8 100644 --- a/src/lib/expansion/expansion.spec.ts +++ b/src/lib/expansion/expansion.spec.ts @@ -18,6 +18,7 @@ describe('MatExpansionPanel', () => { PanelWithCustomMargin, LazyPanelWithContent, LazyPanelOpenOnLoad, + PanelWithTwoWayBinding, ], }); TestBed.compileComponents(); @@ -165,15 +166,31 @@ describe('MatExpansionPanel', () => { expect(arrow.style.transform).toBe('rotate(180deg)', 'Expected 180 degree rotation.'); })); - it('make sure accordion item runs ngOnDestroy when expansion panel is destroyed', () => { - let fixture = TestBed.createComponent(PanelWithContentInNgIf); - fixture.detectChanges(); - let destroyedOk = false; - fixture.componentInstance.panel.destroyed.subscribe(() => destroyedOk = true); - fixture.componentInstance.expansionShown = false; - fixture.detectChanges(); - expect(destroyedOk).toBe(true); - }); + it('should make sure accordion item runs ngOnDestroy when expansion panel is destroyed', () => { + let fixture = TestBed.createComponent(PanelWithContentInNgIf); + fixture.detectChanges(); + let destroyedOk = false; + fixture.componentInstance.panel.destroyed.subscribe(() => destroyedOk = true); + fixture.componentInstance.expansionShown = false; + fixture.detectChanges(); + expect(destroyedOk).toBe(true); + }); + + it('should support two-way binding of the `expanded` property', () => { + const fixture = TestBed.createComponent(PanelWithTwoWayBinding); + const header = fixture.debugElement.query(By.css('mat-expansion-panel-header')).nativeElement; + + fixture.detectChanges(); + expect(fixture.componentInstance.expanded).toBe(false); + + header.click(); + fixture.detectChanges(); + expect(fixture.componentInstance.expanded).toBe(true); + + header.click(); + fixture.detectChanges(); + expect(fixture.componentInstance.expanded).toBe(false); + }); describe('disabled state', () => { let fixture: ComponentFixture; @@ -313,3 +330,14 @@ class LazyPanelWithContent { ` }) class LazyPanelOpenOnLoad {} + + +@Component({ + template: ` + + Panel Title + ` +}) +class PanelWithTwoWayBinding { + expanded = false; +}