fix(ivy): ensure animation @trigger ordering is correctly delivered to the renderer (#28165)
In Ivy when elements are created a series of static attribute names are provided over to the construction instruction of that element. Static attribute names include non-binding attribues (like `<div selected>`) as well as animation bindings that do not have a RHS value (like `<div @foo>`). Because of this distinction, value-less animation triggers are rendered first before value-full animation bindings are and this improper ordering has caused various existing tests to fail. This patch ensures that animation bindings are evaluated in the order that they exist within the HTML template code (or host binding code). PR Close #28165
This commit is contained in:

committed by
Alex Rickabaugh

parent
0d6913f037
commit
e172e97e13
@ -1569,64 +1569,61 @@ const DEFAULT_COMPONENT_ID = '1';
|
||||
}
|
||||
});
|
||||
|
||||
fixmeIvy(
|
||||
'FW-932: Animation @triggers are not reported to the renderer in Ivy as they are in VE')
|
||||
.it('should animate removals of nodes to the `void` state for each animation trigger, but treat all auto styles as pre styles',
|
||||
() => {
|
||||
@Component({
|
||||
selector: 'ani-cmp',
|
||||
template: `
|
||||
it('should animate removals of nodes to the `void` state for each animation trigger, but treat all auto styles as pre styles',
|
||||
() => {
|
||||
@Component({
|
||||
selector: 'ani-cmp',
|
||||
template: `
|
||||
<div *ngIf="exp" class="ng-if" [@trig1]="exp2" @trig2></div>
|
||||
`,
|
||||
animations: [
|
||||
trigger('trig1', [transition(
|
||||
'state => void', [animate(1000, style({opacity: 0}))])]),
|
||||
trigger(
|
||||
'trig2', [transition(':leave', [animate(1000, style({width: '0px'}))])])
|
||||
]
|
||||
})
|
||||
class Cmp {
|
||||
public exp = true;
|
||||
public exp2 = 'state';
|
||||
}
|
||||
animations: [
|
||||
trigger(
|
||||
'trig1', [transition('state => void', [animate(1000, style({opacity: 0}))])]),
|
||||
trigger('trig2', [transition(':leave', [animate(1000, style({width: '0px'}))])])
|
||||
]
|
||||
})
|
||||
class Cmp {
|
||||
public exp = true;
|
||||
public exp2 = 'state';
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||
|
||||
const engine = TestBed.get(ɵAnimationEngine);
|
||||
const fixture = TestBed.createComponent(Cmp);
|
||||
const cmp = fixture.componentInstance;
|
||||
cmp.exp = true;
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
resetLog();
|
||||
const engine = TestBed.get(ɵAnimationEngine);
|
||||
const fixture = TestBed.createComponent(Cmp);
|
||||
const cmp = fixture.componentInstance;
|
||||
cmp.exp = true;
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
resetLog();
|
||||
|
||||
const element = getDOM().querySelector(fixture.nativeElement, '.ng-if');
|
||||
assertHasParent(element, true);
|
||||
const element = getDOM().querySelector(fixture.nativeElement, '.ng-if');
|
||||
assertHasParent(element, true);
|
||||
|
||||
cmp.exp = false;
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
cmp.exp = false;
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
|
||||
assertHasParent(element, true);
|
||||
assertHasParent(element, true);
|
||||
|
||||
expect(getLog().length).toEqual(2);
|
||||
expect(getLog().length).toEqual(2);
|
||||
|
||||
const player2 = getLog().pop() !;
|
||||
const player1 = getLog().pop() !;
|
||||
const player2 = getLog().pop() !;
|
||||
const player1 = getLog().pop() !;
|
||||
|
||||
expect(player2.keyframes).toEqual([
|
||||
{width: PRE_STYLE, offset: 0},
|
||||
{width: '0px', offset: 1},
|
||||
]);
|
||||
expect(player2.keyframes).toEqual([
|
||||
{width: PRE_STYLE, offset: 0},
|
||||
{width: '0px', offset: 1},
|
||||
]);
|
||||
|
||||
expect(player1.keyframes).toEqual([
|
||||
{opacity: PRE_STYLE, offset: 0}, {opacity: '0', offset: 1}
|
||||
]);
|
||||
expect(player1.keyframes).toEqual([
|
||||
{opacity: PRE_STYLE, offset: 0}, {opacity: '0', offset: 1}
|
||||
]);
|
||||
|
||||
player2.finish();
|
||||
player1.finish();
|
||||
assertHasParent(element, false);
|
||||
});
|
||||
player2.finish();
|
||||
player1.finish();
|
||||
assertHasParent(element, false);
|
||||
});
|
||||
|
||||
it('should properly cancel all existing animations when a removal occurs', () => {
|
||||
@Component({
|
||||
@ -3372,43 +3369,42 @@ const DEFAULT_COMPONENT_ID = '1';
|
||||
expect(getLog().length).toEqual(1);
|
||||
});
|
||||
|
||||
fixmeIvy('FW-951 - Attribute-only synthetic properties are treated differently in Ivy')
|
||||
.it('should treat the property as true when the expression is missing', () => {
|
||||
@Component({
|
||||
selector: 'parent-cmp',
|
||||
animations: [
|
||||
trigger(
|
||||
'myAnimation',
|
||||
[
|
||||
transition(
|
||||
'* => go',
|
||||
[
|
||||
style({opacity: 0}),
|
||||
animate(500, style({opacity: 1})),
|
||||
]),
|
||||
]),
|
||||
],
|
||||
template: `
|
||||
it('should treat the property as true when the expression is missing', () => {
|
||||
@Component({
|
||||
selector: 'parent-cmp',
|
||||
animations: [
|
||||
trigger(
|
||||
'myAnimation',
|
||||
[
|
||||
transition(
|
||||
'* => go',
|
||||
[
|
||||
style({opacity: 0}),
|
||||
animate(500, style({opacity: 1})),
|
||||
]),
|
||||
]),
|
||||
],
|
||||
template: `
|
||||
<div @.disabled>
|
||||
<div [@myAnimation]="exp"></div>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
class Cmp {
|
||||
exp = '';
|
||||
}
|
||||
})
|
||||
class Cmp {
|
||||
exp = '';
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||
|
||||
const fixture = TestBed.createComponent(Cmp);
|
||||
const cmp = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
resetLog();
|
||||
const fixture = TestBed.createComponent(Cmp);
|
||||
const cmp = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
resetLog();
|
||||
|
||||
cmp.exp = 'go';
|
||||
fixture.detectChanges();
|
||||
expect(getLog().length).toEqual(0);
|
||||
});
|
||||
cmp.exp = 'go';
|
||||
fixture.detectChanges();
|
||||
expect(getLog().length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should respect parent/sub animations when the respective area in the DOM is disabled',
|
||||
fakeAsync(() => {
|
||||
|
Reference in New Issue
Block a user