Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(animations): ensure consistent transition namespace ordering #19854

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -571,7 +571,7 @@ export class TransitionAnimationEngine {

createNamespace(namespaceId: string, hostElement: any) {
const ns = new AnimationTransitionNamespace(namespaceId, hostElement, this);
if (hostElement.parentNode) {
if (this.bodyNode && this.driver.containsElement(this.bodyNode, hostElement)) {
this._balanceNamespaceList(ns, hostElement);
} else {
// defer this later until flush during when the host element has
Expand All @@ -580,7 +580,7 @@ export class TransitionAnimationEngine {
this.newHostElements.set(hostElement, ns);

// given that this host element is apart of the animation code, it
// may or may not be inserted by a parent node that is an of an
// may or may not be inserted by a parent node that is of an
// animation renderer type. If this happens then we can still have
// access to this item when we query for :enter nodes. If the parent
// is a renderer then the set data-structure will normalize the entry
Expand Down
85 changes: 85 additions & 0 deletions packages/core/test/animation/animation_query_integration_spec.ts
Expand Up @@ -2374,6 +2374,91 @@ describe('animation query tests', function() {
]);
});

it(`should emulate a leave animation on a nested sub component's inner elements when a parent leave animation occurs with animateChild`,
() => {
@Component({
selector: 'ani-cmp',
template: `
<div @myAnimation *ngIf="exp" class="parent">
<child-cmp></child-cmp>
</div>
`,
animations: [
trigger(
'myAnimation',
[
transition(
':leave',
[
query('@*', animateChild()),
]),
]),
]
})
class ParentCmp {
public exp: boolean = true;
}

@Component({
selector: 'child-cmp',
template: `
<nested-child-cmp></nested-child-cmp>
`
})
class ChildCmp {
}

@Component({
selector: 'nested-child-cmp',
template: `
<section>
<div class="inner-div" @myChildAnimation></div>
</section>
`,
animations: [
trigger(
'myChildAnimation',
[
transition(
':leave',
[
style({opacity: 0}),
animate('1s', style({opacity: 1})),
]),
]),
]
})
class NestedChildCmp {
}

TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp, NestedChildCmp]});

const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(ParentCmp);
const cmp = fixture.componentInstance;

cmp.exp = true;
fixture.detectChanges();

cmp.exp = false;
fixture.detectChanges();

// Inspect the players of the AnimationEngine and not those from getLog. The latter only
// returns the actual animation players, which the parent leave animation is not part
// of given that it does not have animation instructions of its own.
const players = engine.players;
expect(players.length).toEqual(1);
const player = players[0] as TransitionAnimationPlayer;
const realPlayer = player.getRealPlayer() as MockAnimationPlayer;

expect(player.element.classList.contains('parent')).toBeTruthy();
expect(realPlayer.element.classList.contains('inner-div')).toBeTruthy();
expect(realPlayer.keyframes).toEqual([
{opacity: '0', offset: 0},
{opacity: '1', offset: 1},
]);
});

it('should not cause a removal of inner @trigger DOM nodes when a parent animation occurs',
fakeAsync(() => {
@Component({
Expand Down