fix(animations): do not retain deleted nodes during an non-removal animation (#17153)

Closes #17086
This commit is contained in:
Matias Niemelä 2017-06-01 14:02:41 -07:00 committed by Victor Berchet
parent 598fdad089
commit 068133ec85
2 changed files with 63 additions and 27 deletions

View File

@ -871,24 +871,9 @@ export class TransitionAnimationEngine {
const players = queriedElements.get(element);
if (players) {
optimizeGroupPlayer(players).onDone(fn);
} else {
let elementPlayers: AnimationPlayer[]|null = null;
let parent = element;
while (parent = parent.parentNode) {
const playersForThisElement = this.playersByElement.get(parent);
if (playersForThisElement && playersForThisElement.length) {
elementPlayers = playersForThisElement;
break;
}
}
if (elementPlayers) {
optimizeGroupPlayer(elementPlayers).onDone(fn);
} else {
fn();
}
}
});
rootPlayers.forEach(player => {

View File

@ -1127,14 +1127,13 @@ export function main() {
expect(count).toEqual(2);
});
it('should always make children wait for the parent animation to finish before any removals occur',
it('should allow inner removals to happen when a non removal-based parent animation is set to animate',
() => {
@Component({
selector: 'ani-cmp',
template: `
<div #parent [@parent]="exp1" class="parent">
<div #child1 *ngIf="exp2" class="child1"></div>
<div #child2 *ngIf="exp2" class="child2"></div>
<div #child *ngIf="exp2" class="child"></div>
</div>
`,
animations: [trigger(
@ -1148,9 +1147,7 @@ export function main() {
@ViewChild('parent') public parent: any;
@ViewChild('child1') public child1Elm: any;
@ViewChild('child2') public child2Elm: any;
@ViewChild('child') public child: any;
}
TestBed.configureTestingModule({declarations: [Cmp]});
@ -1170,10 +1167,69 @@ export function main() {
engine.flush();
const player = getLog()[0];
const p = cmp.parent.nativeElement;
const c = cmp.child.nativeElement;
expect(p.contains(c)).toBeTruthy();
cmp.exp2 = false;
fixture.detectChanges();
engine.flush();
expect(p.contains(c)).toBeFalsy();
player.finish();
expect(p.contains(c)).toBeFalsy();
});
it('should make inner removals wait until a parent based removal animation has finished',
() => {
@Component({
selector: 'ani-cmp',
template: `
<div #parent *ngIf="exp1" @parent class="parent">
<div #child1 *ngIf="exp2" class="child1"></div>
<div #child2 *ngIf="exp2" class="child2"></div>
</div>
`,
animations: [trigger(
'parent',
[transition(
':leave', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])]
})
class Cmp {
public exp1: any;
public exp2: any;
@ViewChild('parent') public parent: any;
@ViewChild('child1') public child1Elm: any;
@ViewChild('child2') public child2Elm: any;
}
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.get(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.exp1 = true;
cmp.exp2 = true;
fixture.detectChanges();
engine.flush();
resetLog();
const p = cmp.parent.nativeElement;
const c1 = cmp.child1Elm.nativeElement;
const c2 = cmp.child2Elm.nativeElement;
cmp.exp1 = false;
cmp.exp2 = false;
fixture.detectChanges();
engine.flush();
expect(p.contains(c1)).toBeTruthy();
expect(p.contains(c2)).toBeTruthy();
@ -1183,11 +1239,6 @@ export function main() {
expect(p.contains(c1)).toBeTruthy();
expect(p.contains(c2)).toBeTruthy();
player.finish();
expect(p.contains(c1)).toBeFalsy();
expect(p.contains(c2)).toBeFalsy();
});
it('should substitute in values if the provided state match is an object with values', () => {