Quantcast
Channel: Articles by thoughtram
Viewing all articles
Browse latest Browse all 68

Angular 2 Animations - Foundation Concepts

$
0
0

Angular 2 Animations - Foundation Concepts

Animations features often are scary goals for developers. And Angular’s doctrine

“… controllers should not directly modify DOM elements!”

made Animation features intimidating as hell. But Angular 2 animations are not scary! Templates are closely associated/integrated with @Component. We will notice that animations following a similar pattern. Let’s build a component that hides and shows its contents, uses fade animation effects, and allows external components to easily trigger those fade effects.

Our Scenario

Here is a simple Angular 2 component with hide and show features… but no animations (yet):

@Component({selector:'my-fader',template:`<div*ngIf="visibility == 'shown'"><ng-content></ng-content>
Canyouseeme?</div>
`})exportclassMyComponentimplementsOnChanges{visibility='shown';@Input()isVisible:boolean=true;ngOnChanges(){this.visibility=this.isVisible?'shown':'hidden';}}

This component simply publishes an @Input() isVisible property; which allows other external components to show/hide the text content… without any animations.

Configure Component Animations

We want the my-fader component to fade-in or fade-out its text content. And we want to animate those fades effects.


The essential take-away Animation concept is that Angular 2 Animations are triggered on component state changes. Developers should consider state changes simply as value changes in a property of the component instance.


To start animating, let’s first add animation metadata to our component.

@Component({...,template:``,animations:[...])]classMyComponent(){...}

Above we show that the animations metadata property is defined in the @Component decorator. Just like template(s)!

Since our component has a visibility property whose state can change between shown and hidden, let’s configure animations to trigger and animate during each value change.

animations:[trigger('visibilityChanged',[state('shown',style({opacity:1})),state('hidden',style({opacity:0}))])]

But what does the above mean… and why is this syntax used?

The techno-speak above is saying that when the visibilityChanged property changes to the value == ‘shown’, then the host element opacity changes to 1. And when the value changes == ‘hidden’, the host element opacity should change to 0.

Now, you might wonder where visibilityChanged comes from, because our component property is called just visibility. Hold your wild horses Mr. StageCoach, we’ll clarify that soon!”

Since we want to animate these changes instead of instantly hiding/showing the content, we need to configure a transition. With Angular 2 this is also suprisingly easy:

animations:[trigger(visibilityChanged', [
    state('shown' , style({ opacity: 1 })), 
    state('hidden', style({ opacity: 0 })),
    transition('*=>*', animate('.5s'))])]

With the above transition, we added information to the animation configuration so each trigger value change will have a 500 msec transition.

So a fade-in (opacity 0 -> 1, with a duration of 500 msec) will occur when the value changes from hidden to shown. And likewise the fade-out (opacity 1 -> 0, with a duration of 500 msec) will occur when the value changes from shown to hidden. By the way, you could also have used animate('500ms') to indicate the millsecond duration explicitly.

And what does the transition('* => *', ...) mean?

Think of this as a transition from one state (* is a wildcard to mean any) to another state. If we wanted the fadeOut to be slower than the fadeIn, here is how we would configure the animation metadata:

animations:[trigger(visibilityChanged', [
    state('shown' , style({ opacity: 1 })),
    state('hidden', style({ opacity: 0 })),
    transition('shown=>hidden', animate('600ms')),
    transition('hidden=>shown', animate('300ms')),])]

See how easy this is? This notation is so easy to understand. The intention with Angular Animations is to make it easy for developers, to be:

  • intuitive
  • declarative and
  • immediately associated with the component…
  • the animations configuration is right above the Class definition!

Linking Animation to the Component


We are not done yet! While we configured the Animation metadata, I am sure you are wondering:

  • How is the animation property visibilityChanged actually connected to the component?
  • How are the animations linked to the component’s properties?

Since data-binding features are already supported between the component and its template, Angular 2 uses a special template animation syntax to support triggering the animation after data-binding changes. So in the component template, we can do this:

<div[@visibilityChanged]="visibility">
  Can you see me? I should fade in or out...
</div>

Above the @visibilityChanged is the special template animation property and it uses databinding [@visibilityChanged]=“visibility” to bind the component’s visibility property to the animation trigger property visibilityChanged.

And here is the entire component definition updated with Animation features:

import{Component,OnChanges,Input,trigger,state,animate,transition,style}from'@angular/core';@Component({selector:'my-fader',animations:[trigger('visibilityChanged',[state('shown',style({opacity:1})),state('hidden',style({opacity:0})),transition('* => *',animate('.5s'))])],template:`<div[@visibilityChanged]="visibility"><ng-content></ng-content> <p>Canyouseeme?Ishouldfadeinorout...</p>
</div>
`})exportclassFaderComponentimplementsOnChanges{@Input()isVisible:boolean=true;visibility='shown';ngOnChanges(){this.visibility=this.isVisible?'shown':'hidden';}}



This template-binding solution decouples the animation from the component internals and uses the template as the binding bridge.


Our Animation Workflow

Above we have an improvide component definition; enhanced with animation features. Here is a workflow of the [animation] process:

  • the input value for isVisible
  • change detection triggers a call to ngOnChanges()
  • the component visibilty property changes
  • the template databinding updates the @visibilityChanged property value
  • the animation trigger is invoked
  • the state value is used to determine the animation
  • the host opacity change animates for 500 msecs

super-cool

Using Components with internal Animations

Parent components can simply change the state of the child my-fader instances and then magically the contents of the my-fader instance will fadeIn or fadeOut.

Recall that component state == value of isVisible property.

@Component({selector:'my-app',template:`<my-fader[visibility]="showFader">AmIvisible?</my-fader>
<button(click)="showFader = !showFader">Toggle</button>
`})exportclassMyAppComponent{showFader:boolean=true;}

Summary

The Angular 2 Animation engine and compiler does all the hard work of the preparing, managing, and running the animations.

The @Component metadata registers the component animation, and the component template is the glue that bridges the component instance state to the animation trigger property.


Thanks

Kudos to Matias Niemelä for the amazing Animation engine in Angular 2!

matiasvikinghair

These core animation features [discussed above] are available in the Angular 2.0.0 release. And never fear, Matias and his team are working hard on more amazing, intuitive Animation features. So stay tuned for even MORE cool features and blogs coming soon!



Viewing all articles
Browse latest Browse all 68

Trending Articles