mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(animations): Trigger leave animation when ViewContainerRef is injected (#48705)
Injecting `ViewContainerRef` into a component makes it effectively a container. The leave animation wasn't triggered on containers before this fix. fixes angular#48667 PR Close #48705
This commit is contained in:
committed by
Dylan Hunn
parent
fc6b10cb15
commit
df65c4fc8f
@@ -72,8 +72,8 @@ export class AnimationEngine {
|
||||
this._transitionEngine.insertNode(namespaceId, element, parent, insertBefore);
|
||||
}
|
||||
|
||||
onRemove(namespaceId: string, element: any, context: any, isHostElement?: boolean): void {
|
||||
this._transitionEngine.removeNode(namespaceId, element, isHostElement || false, context);
|
||||
onRemove(namespaceId: string, element: any, context: any): void {
|
||||
this._transitionEngine.removeNode(namespaceId, element, context);
|
||||
}
|
||||
|
||||
disableAnimations(element: any, disable: boolean) {
|
||||
|
||||
@@ -744,7 +744,7 @@ export class TransitionAnimationEngine {
|
||||
}
|
||||
}
|
||||
|
||||
removeNode(namespaceId: string, element: any, isHostElement: boolean, context: any): void {
|
||||
removeNode(namespaceId: string, element: any, context: any): void {
|
||||
if (isElementNode(element)) {
|
||||
const ns = namespaceId ? this._fetchNamespace(namespaceId) : null;
|
||||
if (ns) {
|
||||
@@ -753,11 +753,9 @@ export class TransitionAnimationEngine {
|
||||
this.markElementAsRemoved(namespaceId, element, false, context);
|
||||
}
|
||||
|
||||
if (isHostElement) {
|
||||
const hostNS = this.namespacesByHostElement.get(element);
|
||||
if (hostNS && hostNS.id !== namespaceId) {
|
||||
hostNS.removeNode(element, context);
|
||||
}
|
||||
const hostNS = this.namespacesByHostElement.get(element);
|
||||
if (hostNS && hostNS.id !== namespaceId) {
|
||||
hostNS.removeNode(element, context);
|
||||
}
|
||||
} else {
|
||||
this._onRemovalComplete(element, context);
|
||||
|
||||
@@ -116,7 +116,7 @@ describe('TransitionAnimationEngine', () => {
|
||||
|
||||
expect(engine.elementContainsData(DEFAULT_NAMESPACE_ID, element)).toBeTruthy();
|
||||
|
||||
engine.removeNode(DEFAULT_NAMESPACE_ID, element, true, true);
|
||||
engine.removeNode(DEFAULT_NAMESPACE_ID, element, true);
|
||||
engine.flush();
|
||||
|
||||
expect(engine.elementContainsData(DEFAULT_NAMESPACE_ID, element)).toBeTruthy();
|
||||
@@ -171,7 +171,7 @@ describe('TransitionAnimationEngine', () => {
|
||||
expect(engine.statesByElement.has(element)).toBe(true, 'Expected parent data to be defined.');
|
||||
expect(engine.statesByElement.has(child)).toBe(true, 'Expected child data to be defined.');
|
||||
|
||||
engine.removeNode(DEFAULT_NAMESPACE_ID, element, true, true);
|
||||
engine.removeNode(DEFAULT_NAMESPACE_ID, element, true);
|
||||
engine.flush();
|
||||
engine.players[0].finish();
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import {animate, animateChild, animation, AnimationEvent, AnimationMetadata, AnimationOptions, AUTO_STYLE, group, keyframes, query, sequence, state, style, transition, trigger, useAnimation, ɵPRE_STYLE as PRE_STYLE} from '@angular/animations';
|
||||
import {AnimationDriver, ɵAnimationEngine, ɵNoopAnimationDriver as NoopAnimationDriver} from '@angular/animations/browser';
|
||||
import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/browser/testing';
|
||||
import {ChangeDetectorRef, Component, HostBinding, HostListener, Inject, RendererFactory2, ViewChild} from '@angular/core';
|
||||
import {ChangeDetectorRef, Component, HostBinding, HostListener, Inject, RendererFactory2, ViewChild, ViewContainerRef} from '@angular/core';
|
||||
import {fakeAsync, flushMicrotasks, TestBed} from '@angular/core/testing';
|
||||
import {ɵDomRendererFactory2} from '@angular/platform-browser';
|
||||
import {ANIMATION_MODULE_TYPE, BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations';
|
||||
@@ -909,6 +909,56 @@ describe('animation tests', function() {
|
||||
]);
|
||||
}));
|
||||
|
||||
it('should trigger a leave animation when the inner has ViewContainerRef injected',
|
||||
fakeAsync(() => {
|
||||
@Component({
|
||||
selector: 'parent-cmp',
|
||||
template: `
|
||||
<child-cmp *ngIf="exp"></child-cmp>
|
||||
`
|
||||
})
|
||||
class ParentCmp {
|
||||
public exp = true;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'child-cmp',
|
||||
template: '...',
|
||||
animations: [trigger(
|
||||
'host',
|
||||
[transition(':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])])]
|
||||
})
|
||||
class ChildCmp {
|
||||
@HostBinding('@host') public hostAnimation = true;
|
||||
constructor(private vcr: ViewContainerRef) {}
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]});
|
||||
|
||||
const engine = TestBed.inject(ɵAnimationEngine);
|
||||
const fixture = TestBed.createComponent(ParentCmp);
|
||||
const cmp = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
expect(getLog().length).toEqual(0);
|
||||
|
||||
cmp.exp = false;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.nativeElement.children.length).toBe(1);
|
||||
|
||||
engine.flush();
|
||||
expect(getLog().length).toEqual(1);
|
||||
|
||||
const [player] = getLog();
|
||||
expect(player.keyframes).toEqual([
|
||||
new Map<string, string|number>([['opacity', '1'], ['offset', 0]]),
|
||||
new Map<string, string|number>([['opacity', '0'], ['offset', 1]]),
|
||||
]);
|
||||
|
||||
player.finish();
|
||||
expect(fixture.debugElement.nativeElement.children.length).toBe(0);
|
||||
}));
|
||||
|
||||
it('should trigger a leave animation when the inner components host binding updates',
|
||||
fakeAsync(() => {
|
||||
@Component({
|
||||
|
||||
@@ -180,7 +180,7 @@ export class BaseAnimationRenderer implements Renderer2 {
|
||||
}
|
||||
|
||||
removeChild(parent: any, oldChild: any, isHostElement: boolean): void {
|
||||
this.engine.onRemove(this.namespaceId, oldChild, this.delegate, isHostElement);
|
||||
this.engine.onRemove(this.namespaceId, oldChild, this.delegate);
|
||||
}
|
||||
|
||||
selectRootElement(selectorOrNode: any, preserveContent?: boolean) {
|
||||
|
||||
Reference in New Issue
Block a user