26

I'm trying to trigger a transition bound to a boolean property, but this doesn't seem to fire.

Here is a cut down version of my animation trigger

trigger( 'trueFalseAnimation', [ transition('* => true', [ style({backgroundColor: '#00f7ad'}), animate('2500ms', style({backgroundColor: '#fff'})) ]), transition('* => false', [ style({backgroundColor: '#ff0000'}), animate('2500ms', style({backgroundColor: '#fff'})) ]) ] ) 

HTML:

<div [@trueFalseAnimation]="model.someProperty">Content here</div> 

To test:

ngOnInit() { setTimeout(() => { this.model.someProperty = true; setTimeOut(() => { this.model.someProperty = false; }, 5000); }, 1000) } 

The trigger never happens when the someProperty changes.

As a quick test I changed the trigger to use a string and it works

trigger( 'trueFalseAnimation', [ transition('* => Success', [ style({backgroundColor: '#00f7ad'}), animate('2500ms', style({backgroundColor: '#fff'})) ]), transition('* => Failed', [ style({backgroundColor: '#ff0000'}), animate('2500ms', style({backgroundColor: '#fff'})) ]) ] ) 

To test:

ngOnInit() { setTimeout(() => { this.model.someProperty = "Success"; setTimeOut(() => { this.model.someProperty = "Failed"; }, 5000); }, 1000) } 

The second example works just fine

My questions are

  1. Are boolean supported as triggers?
  2. If yes to #1 what am I doing wrong?

3 Answers 3

29
+25
  1. It seems not. I saw that an an issue (12337) has already been raised for this, but there has been no update so far.
  2. One other alternative is to use 1 and 0 instead of true and false.

See the plunker from here.

trigger('isVisibleChanged', [ state('true' , style({ opacity: 1, transform: 'scale(1.0)' })), state('false', style({ opacity: 0, transform: 'scale(0.0)' })), transition('1 => 0', animate('300ms')), transition('0 => 1', animate('900ms')) ]) 
Sign up to request clarification or add additional context in comments.

6 Comments

For those seeing this answer in 2017: Since Angular 4.0.1, you will need to use state('1', ... and state('0', ...) instead of state('true', ...) and state('false', ...)
state('0',...) I spent hours to get that damn thing to work. thanks for the hint!
I had the same issue with using hyphens in my state name. Changing the state name to camelCase fixed my issue.
I was lucky enough to stumbled upon this pull request so I saved myself a couple of hours of banging my head into a wall.
Greetings from 2019! This has been fixed. boolean-value-matching
|
3

I'm having the same issue. Not sure if boolean are supported as triggers, but the workaround I found was to define a string property with a getter to return the boolean value as string. Something like this:

get somePropertyStr():string { return this.someProperty.toString(); } 

Then you should bind your animation to that somePropertyStr property.

Once again, this is an ugly workaround, best thing would be able to use the boolean value.

1 Comment

This seems to be a great work around but I'd love some response from the angular 2 team. Thank you
0

Edit: As some other answers allude to, the behavior has changed. If you're interested here is the relevant Angular source code:

const TRUE_BOOLEAN_VALUES = new Set<string>(['true', '1']); const FALSE_BOOLEAN_VALUES = new Set<string>(['false', '0']); function makeLambdaFromStates(lhs: string, rhs: string): TransitionMatcherFn { const LHS_MATCH_BOOLEAN = TRUE_BOOLEAN_VALUES.has(lhs) || FALSE_BOOLEAN_VALUES.has(lhs); const RHS_MATCH_BOOLEAN = TRUE_BOOLEAN_VALUES.has(rhs) || FALSE_BOOLEAN_VALUES.has(rhs); return (fromState: any, toState: any): boolean => { let lhsMatch = lhs == ANY_STATE || lhs == fromState; let rhsMatch = rhs == ANY_STATE || rhs == toState; if (!lhsMatch && LHS_MATCH_BOOLEAN && typeof fromState === 'boolean') { lhsMatch = fromState ? TRUE_BOOLEAN_VALUES.has(lhs) : FALSE_BOOLEAN_VALUES.has(lhs); } if (!rhsMatch && RHS_MATCH_BOOLEAN && typeof toState === 'boolean') { rhsMatch = toState ? TRUE_BOOLEAN_VALUES.has(rhs) : FALSE_BOOLEAN_VALUES.has(rhs); } return lhsMatch && rhsMatch; }; } 

It's a little tricky to follow unless you're debugging it yourself but basically the important thing to notice is that fromState and toState are the values (when there is a change) that you set on the animation in the template: eg. [@animation]="animationState"

So you can see they explicitly allow them to be booleans (typeof fromState === 'boolean').

The reason I got caught out (and found my way back to my own old answer) is that Angular's AnimationEvent defines them as strings:

 /** * The name of the state from which the animation is triggered. */ fromState: string; /** * The name of the state in which the animation completes. */ toState: string; 

So therefore on completion of an animation where your state is set to a boolean (eg. true / false and NOT 'true' / 'false' you'll run into a typing issue.

The actual value of event.fromState may be true so

  • event.fromState == true gives a compiler error ('string' and 'boolean' have no type overlap)
  • event.fromState == 'true' will NEVER be true (since the value is actually true)

So you'd need to either use:

 if (<any>(event.toState) == true) 

OR

 if ((event.toState as string | boolean) == true) 

Old answer:

A state is defined as being a string, so we need to stick to that.

The simplest - but ickiest - way based on your code is this

<div [@trueFalseAnimation]="model.someProperty?.toString()">Content here</div> 

But this is pretty awful, so this is probably better

<div [@trueFalseAnimation]="model.someProperty ? 'active' : 'inactive'">Content here</div> <div [@trueFalseAnimation]="model.someProperty ? 'visible' : 'hidden'">Content here</div> <div [@trueFalseAnimation]="model.someProperty ? 'up' : 'down'">Content here</div> <div [@trueFalseAnimation]="model.someProperty ? 'left' : 'right'">Content here</div> 

The best advice here would be to use a state that corresponds to what it really means. What does true and false really mean in this context anyway?

I considered making a pipe to convert a boolean, but the only benefit of that would be to make sure you're being consistent with your state strings.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.