fix(ivy): ensure animation @bindings work for {key:value} and empty bindings (#28026)
PR Close #28026
This commit is contained in:

committed by
Andrew Kushnir

parent
0136274f33
commit
94c0b7a362
@ -688,10 +688,19 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
const instruction = mapBindingToInstruction(input.type);
|
||||
if (input.type === BindingType.Animation) {
|
||||
const value = input.value.visit(this._valueConverter);
|
||||
// setProperty without a value doesn't make any sense
|
||||
if (value.name || value.value) {
|
||||
const bindingName = prepareSyntheticPropertyName(input.name);
|
||||
// animation bindings can be presented in the following formats:
|
||||
// 1j [@binding]="fooExp"
|
||||
// 2. [@binding]="{value:fooExp, params:{...}}"
|
||||
// 3. [@binding]
|
||||
// 4. @binding
|
||||
// only formats 1. and 2. include the actual binding of a value to
|
||||
// an expression and therefore only those should be the only two that
|
||||
// are allowed. The check below ensures that a binding with no expression
|
||||
// does not get an empty `elementProperty` instruction created for it.
|
||||
const hasValue = value && (value instanceof LiteralPrimitive) ? !!value.value : true;
|
||||
if (hasValue) {
|
||||
this.allocateBindingSlots(value);
|
||||
const bindingName = prepareSyntheticPropertyName(input.name);
|
||||
this.updateInstruction(input.sourceSpan, R3.elementProperty, () => {
|
||||
return [
|
||||
o.literal(elementIndex), o.literal(bindingName),
|
||||
|
@ -373,12 +373,12 @@ const DEFAULT_COMPONENT_ID = '1';
|
||||
expect(players.length).toEqual(0);
|
||||
});
|
||||
|
||||
fixmeIvy('unknown').it(
|
||||
'should allow a transition to use a function to determine what method to run and expose any parameter values',
|
||||
it('should allow a transition to use a function to determine what method to run and expose any parameter values',
|
||||
() => {
|
||||
const transitionFn =
|
||||
(fromState: string, toState: string, element: any,
|
||||
params: {[key: string]: any}) => { return params['doMatch'] == true; };
|
||||
(fromState: string, toState: string, element: any, params: {[key: string]: any}) => {
|
||||
return params['doMatch'] == true;
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: 'if-cmp',
|
||||
@ -1567,8 +1567,9 @@ 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',
|
||||
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',
|
||||
@ -1576,9 +1577,10 @@ const DEFAULT_COMPONENT_ID = '1';
|
||||
<div *ngIf="exp" class="ng-if" [@trig1]="exp2" @trig2></div>
|
||||
`,
|
||||
animations: [
|
||||
trigger('trig1', [transition(
|
||||
'state => void', [animate(1000, style({opacity: 0}))])]),
|
||||
trigger(
|
||||
'trig1', [transition('state => void', [animate(1000, style({opacity: 0}))])]),
|
||||
trigger('trig2', [transition(':leave', [animate(1000, style({width: '0px'}))])])
|
||||
'trig2', [transition(':leave', [animate(1000, style({width: '0px'}))])])
|
||||
]
|
||||
})
|
||||
class Cmp {
|
||||
@ -1926,8 +1928,7 @@ const DEFAULT_COMPONENT_ID = '1';
|
||||
expect(p.contains(c2)).toBeTruthy();
|
||||
});
|
||||
|
||||
fixmeIvy('unknown').it(
|
||||
'should detect trigger changes based on object.value properties', () => {
|
||||
it('should detect trigger changes based on object.value properties', () => {
|
||||
@Component({
|
||||
selector: 'ani-cmp',
|
||||
template: `
|
||||
@ -1968,8 +1969,9 @@ const DEFAULT_COMPONENT_ID = '1';
|
||||
expect(players[0].duration).toEqual(5678);
|
||||
});
|
||||
|
||||
fixmeIvy('FW-932: Animation @triggers are not reported to the renderer in Ivy as they are in VE').it(
|
||||
'should not render animations when the object expression value is the same as it was previously',
|
||||
fixmeIvy(
|
||||
'FW-932: Animation @triggers are not reported to the renderer in Ivy as they are in VE')
|
||||
.it('should not render animations when the object expression value is the same as it was previously',
|
||||
() => {
|
||||
@Component({
|
||||
selector: 'ani-cmp',
|
||||
@ -2012,8 +2014,7 @@ const DEFAULT_COMPONENT_ID = '1';
|
||||
expect(players.length).toEqual(0);
|
||||
});
|
||||
|
||||
fixmeIvy('unknown').it(
|
||||
'should update the final state styles when params update even if the expression hasn\'t changed',
|
||||
it('should update the final state styles when params update even if the expression hasn\'t changed',
|
||||
fakeAsync(() => {
|
||||
@Component({
|
||||
selector: 'ani-cmp',
|
||||
@ -2105,8 +2106,7 @@ const DEFAULT_COMPONENT_ID = '1';
|
||||
]);
|
||||
});
|
||||
|
||||
fixmeIvy('unknown').it(
|
||||
'should retain substituted styles on the element once the animation is complete if referenced in the final state',
|
||||
it('should retain substituted styles on the element once the animation is complete if referenced in the final state',
|
||||
fakeAsync(() => {
|
||||
@Component({
|
||||
selector: 'ani-cmp',
|
||||
|
@ -2444,8 +2444,7 @@ import {HostListener} from '../../src/metadata/directives';
|
||||
expect(element.innerText.trim()).toMatch(/this\s+child/mg);
|
||||
}));
|
||||
|
||||
fixmeIvy('unknown').it(
|
||||
'should only mark outermost *directive nodes :enter and :leave when inserts and removals occur',
|
||||
it('should only mark outermost *directive nodes :enter and :leave when inserts and removals occur',
|
||||
() => {
|
||||
@Component({
|
||||
selector: 'ani-cmp',
|
||||
|
Reference in New Issue
Block a user