mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(expansion): add animation events for expansion panels (#12412)
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
<h1>Single Expansion Panel</h1>
|
||||
|
||||
<mat-expansion-panel class="demo-expansion-width" #myPanel>
|
||||
<mat-expansion-panel class="demo-expansion-width" #myPanel
|
||||
(afterExpand)="addEvent('afterExpand')"
|
||||
(afterCollapse)="addEvent('afterCollapse')">
|
||||
<mat-expansion-panel-header [expandedHeight]="expandedHeight" [collapsedHeight]="collapsedHeight">
|
||||
<mat-panel-description>This is a panel description.</mat-panel-description>
|
||||
<mat-panel-title>Panel Title</mat-panel-title>
|
||||
@@ -29,6 +31,11 @@
|
||||
</mat-form-field>
|
||||
<br>
|
||||
|
||||
<p>Expansion Panel Animation Events</p>
|
||||
<code class="demo-expansion-code">
|
||||
<pre *ngFor="let event of events">{{event}}</pre>
|
||||
</code>
|
||||
|
||||
<h1>matAccordion</h1>
|
||||
<div>
|
||||
<p>Accordion Options</p>
|
||||
@@ -56,7 +63,7 @@
|
||||
</div>
|
||||
<br>
|
||||
<mat-accordion [displayMode]="displayMode" [multi]="multi"
|
||||
class="demo-expansion-width">
|
||||
class="demo-expansion-width">
|
||||
<mat-expansion-panel #panel1 [hideToggle]="hideToggle">
|
||||
<mat-expansion-panel-header>Section 1</mat-expansion-panel-header>
|
||||
<p>This is the content text that makes sense here.</p>
|
||||
|
||||
@@ -2,3 +2,16 @@
|
||||
width: 600px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.demo-expansion-code {
|
||||
background: #d3d3d3;
|
||||
display: block;
|
||||
height: 10em;
|
||||
overflow: auto;
|
||||
padding: 0 5px;
|
||||
width: 400px;
|
||||
|
||||
pre {
|
||||
margin: 0.25em 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,4 +26,9 @@ export class ExpansionDemo {
|
||||
showPanel3 = true;
|
||||
expandedHeight: string;
|
||||
collapsedHeight: string;
|
||||
events: string[] = [];
|
||||
|
||||
addEvent(eventName: string) {
|
||||
this.events.push(`${eventName} - ${new Date().toISOString()}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,12 @@ import {
|
||||
Component,
|
||||
ContentChild,
|
||||
Directive,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnDestroy,
|
||||
Optional,
|
||||
Output,
|
||||
SimpleChanges,
|
||||
SkipSelf,
|
||||
ViewContainerRef,
|
||||
@@ -69,7 +71,7 @@ let uniqueId = 0;
|
||||
}
|
||||
})
|
||||
export class MatExpansionPanel extends CdkAccordionItem
|
||||
implements AfterContentInit, OnChanges, OnDestroy {
|
||||
implements AfterContentInit, OnChanges, OnDestroy {
|
||||
/** Whether the toggle indicator should be hidden. */
|
||||
@Input()
|
||||
get hideToggle(): boolean { return this._hideToggle; }
|
||||
@@ -78,6 +80,12 @@ export class MatExpansionPanel extends CdkAccordionItem
|
||||
}
|
||||
private _hideToggle = false;
|
||||
|
||||
/** An event emitted after the body's expansion animation happens. */
|
||||
@Output() afterExpand = new EventEmitter<void>();
|
||||
|
||||
/** An event emitted after the body's collapse animation happens. */
|
||||
@Output() afterCollapse = new EventEmitter<void>();
|
||||
|
||||
/** Stream that emits for changes in `@Input` properties. */
|
||||
readonly _inputChanges = new Subject<SimpleChanges>();
|
||||
|
||||
@@ -147,7 +155,7 @@ export class MatExpansionPanel extends CdkAccordionItem
|
||||
_bodyAnimation(event: AnimationEvent) {
|
||||
const classList = event.element.classList;
|
||||
const cssClass = 'mat-expanded';
|
||||
const {phaseName, toState} = event;
|
||||
const {phaseName, toState, fromState} = event;
|
||||
|
||||
// Toggle the body's `overflow: hidden` class when closing starts or when expansion ends in
|
||||
// order to prevent the cases where switching too early would cause the animation to jump.
|
||||
@@ -155,9 +163,17 @@ export class MatExpansionPanel extends CdkAccordionItem
|
||||
// with doing it via change detection.
|
||||
if (phaseName === 'done' && toState === 'expanded') {
|
||||
classList.add(cssClass);
|
||||
} else if (phaseName === 'start' && toState === 'collapsed') {
|
||||
}
|
||||
if (phaseName === 'start' && toState === 'collapsed') {
|
||||
classList.remove(cssClass);
|
||||
}
|
||||
|
||||
if (phaseName === 'done' && toState === 'expanded' && fromState !== 'void') {
|
||||
this.afterExpand.emit();
|
||||
}
|
||||
if (phaseName === 'done' && toState === 'collapsed' && fromState !== 'void') {
|
||||
this.afterCollapse.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ describe('MatExpansionPanel', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
MatExpansionModule,
|
||||
NoopAnimationsModule,
|
||||
MatExpansionModule
|
||||
],
|
||||
declarations: [
|
||||
PanelWithContent,
|
||||
@@ -44,8 +44,9 @@ describe('MatExpansionPanel', () => {
|
||||
}));
|
||||
|
||||
it('should be able to render panel content lazily', fakeAsync(() => {
|
||||
let fixture = TestBed.createComponent(LazyPanelWithContent);
|
||||
let content = fixture.debugElement.query(By.css('.mat-expansion-panel-content')).nativeElement;
|
||||
const fixture = TestBed.createComponent(LazyPanelWithContent);
|
||||
const content = fixture.debugElement.query(
|
||||
By.css('.mat-expansion-panel-content')).nativeElement;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(content.textContent.trim()).toBe('', 'Expected content element to be empty.');
|
||||
@@ -58,8 +59,9 @@ describe('MatExpansionPanel', () => {
|
||||
}));
|
||||
|
||||
it('should render the content for a lazy-loaded panel that is opened on init', fakeAsync(() => {
|
||||
let fixture = TestBed.createComponent(LazyPanelOpenOnLoad);
|
||||
let content = fixture.debugElement.query(By.css('.mat-expansion-panel-content')).nativeElement;
|
||||
const fixture = TestBed.createComponent(LazyPanelOpenOnLoad);
|
||||
const content = fixture.debugElement.query(
|
||||
By.css('.mat-expansion-panel-content')).nativeElement;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(content.textContent.trim())
|
||||
@@ -161,10 +163,10 @@ describe('MatExpansionPanel', () => {
|
||||
}));
|
||||
|
||||
it('should not override the panel margin if it is not inside an accordion', fakeAsync(() => {
|
||||
let fixture = TestBed.createComponent(PanelWithCustomMargin);
|
||||
const fixture = TestBed.createComponent(PanelWithCustomMargin);
|
||||
fixture.detectChanges();
|
||||
|
||||
let panel = fixture.debugElement.query(By.css('mat-expansion-panel'));
|
||||
const panel = fixture.debugElement.query(By.css('mat-expansion-panel'));
|
||||
let styles = getComputedStyle(panel.nativeElement);
|
||||
|
||||
expect(panel.componentInstance._hasSpacing()).toBe(false);
|
||||
@@ -221,7 +223,7 @@ describe('MatExpansionPanel', () => {
|
||||
}));
|
||||
|
||||
it('should make sure accordion item runs ngOnDestroy when expansion panel is destroyed', () => {
|
||||
let fixture = TestBed.createComponent(PanelWithContentInNgIf);
|
||||
const fixture = TestBed.createComponent(PanelWithContentInNgIf);
|
||||
fixture.detectChanges();
|
||||
let destroyedOk = false;
|
||||
fixture.componentInstance.panel.destroyed.subscribe(() => destroyedOk = true);
|
||||
@@ -264,6 +266,27 @@ describe('MatExpansionPanel', () => {
|
||||
'Expected class to be added after the animation has finished');
|
||||
}));
|
||||
|
||||
it('should emit events for body expanding and collapsing animations', fakeAsync(() => {
|
||||
const fixture = TestBed.createComponent(PanelWithContent);
|
||||
fixture.detectChanges();
|
||||
let afterExpand = 0;
|
||||
let afterCollapse = 0;
|
||||
fixture.componentInstance.panel.afterExpand.subscribe(() => afterExpand++);
|
||||
fixture.componentInstance.panel.afterCollapse.subscribe(() => afterCollapse++);
|
||||
|
||||
fixture.componentInstance.expanded = true;
|
||||
fixture.detectChanges();
|
||||
flush();
|
||||
expect(afterExpand).toBe(1);
|
||||
expect(afterCollapse).toBe(0);
|
||||
|
||||
fixture.componentInstance.expanded = false;
|
||||
fixture.detectChanges();
|
||||
flush();
|
||||
expect(afterExpand).toBe(1);
|
||||
expect(afterCollapse).toBe(1);
|
||||
}));
|
||||
|
||||
describe('disabled state', () => {
|
||||
let fixture: ComponentFixture<PanelWithContent>;
|
||||
let panel: HTMLElement;
|
||||
@@ -373,7 +396,7 @@ class PanelWithContentInNgIf {
|
||||
</mat-expansion-panel>`
|
||||
})
|
||||
class PanelWithCustomMargin {
|
||||
expanded: boolean = false;
|
||||
expanded = false;
|
||||
}
|
||||
|
||||
@Component({
|
||||
|
||||
Reference in New Issue
Block a user