Slide 1

Slide 1 text

Animateyour ANGULARapps

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

angular.io/guide/animations Well-designed animations can make a UI not only more fun but also easier to use “

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

@cironunesdev

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Animations in JavaScript? Why not just CSS?

Slide 9

Slide 9 text

Animations in JavaScript? Why not just CSS? Dynamic elements, page transitions Animate independently of the amount of elements, animate routes

Slide 10

Slide 10 text

Animations in JavaScript? Why not just CSS? Dynamic elements, page transitions Programmatic animations Animate independently of the amount of elements, animate routes Full control over the logic of the animations

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

How can I animate in JS?

Slide 15

Slide 15 text

How can I animate in JS? Declarative Bind animations to the template

Slide 16

Slide 16 text

How can I animate in JS? Declarative Bind animations to the template Imperative Trigger animations programmatically

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

Agenda What are we going to learn today?

Slide 19

Slide 19 text

Agenda What are we going to learn today? Basic and multi-step 1

Slide 20

Slide 20 text

Agenda What are we going to learn today? Basic and multi-step 1 Dynamic # of items 2

Slide 21

Slide 21 text

Agenda What are we going to learn today? Basic and multi-step 1 Dynamic # of items 2 Page transitions 3

Slide 22

Slide 22 text

Agenda What are we going to learn today? Basic and multi-step 1 Dynamic # of items 2 Page transitions 3 Programatic animations 4

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

Create a project using the CLI

Slide 25

Slide 25 text

Create a project using the CLI

Slide 26

Slide 26 text

Create a project using the CLI ~ $ npm i -g @angular/cli

Slide 27

Slide 27 text

Create a project using the CLI ~ $ npm i -g @angular/cli ~ $ ng new my-project

Slide 28

Slide 28 text

... import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @NgModule({ imports: [ BrowserModule, BrowserAnimationsModule ] }) export class AppModule {} Setup app.module.ts

Slide 29

Slide 29 text

... import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @NgModule({ imports: [ BrowserModule, BrowserAnimationsModule ] }) export class AppModule {} Setup app.module.ts NoopAnimationsModule Protip: for tests use:

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

Web Animations API

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

Enable the polyfill

Slide 34

Slide 34 text

Enable the polyfill Hot of the press: in v6 it fallbacks to CSS Keyframes for you!

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

1. Basic and multi-step

Slide 37

Slide 37 text

angular.io/guide/animations Good user interfaces transition smoothly between states with engaging animations that call attention where it's needed “

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

1. Create the animation

Slide 42

Slide 42 text

import { trigger, ... } from '@angular/animations'; export const fadeAnimation = trigger('fade', [ state('inactive', style({ opacity: 0 })), state('active', style({ opacity: 1 })), transition('inactive <=> active', animate('450ms ease-in')) ]); Register the trigger fade.animation.ts

Slide 43

Slide 43 text

import { state, style, ... } from '@angular/animations'; export const fadeAnimation = trigger('fade', [ state('inactive', style({ opacity: 0 })), state('active', style({ opacity: 1 })), transition('inactive <=> active', animate('450ms ease-in')) ]); Setup states fade.animation.ts

Slide 44

Slide 44 text

import { transition, animate, ... } from '@angular/animations'; export const fadeAnimation = trigger('fade', [ state('inactive', style({ opacity: 0 })), state(‘active', style({ opacity: 1 })), transition('inactive <=> active', animate('450ms ease-in')) ]); Setup transitions fade.animation.ts

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

2. Use it in a component

Slide 47

Slide 47 text

import { fadeAnimation } from './fade.animation'; @Component({ ..., animations: [fadeAnimation] }) export class HelloWorldComponent {} Import the animation hello.component.ts

Slide 48

Slide 48 text

import { fadeAnimation } from './fade.animation'; @Component({ ..., animations: [fadeAnimation] }) export class HelloWorldComponent {} Include it hello.component.ts

Slide 49

Slide 49 text

... export class HelloWorldComponent { cmpState = 'inactive'; toggle() { this.cmpState = 'active'; } } Change state hello.component.ts

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

3. Apply it in the template

Slide 52

Slide 52 text

Hello world!

Apply the animation hello.component.html

Slide 53

Slide 53 text

Hello world!

Callbacks hello.component.html

Slide 54

Slide 54 text

export interface AnimationEvent { fromState: string; toState: string; totalTime: number; phaseName: string; element: any; triggerName: string; } AnimationEvent animation_event.ts

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

What about multi-step animations?

Slide 57

Slide 57 text

animate('5s', keyframes([ style({ backgroundColor: 'red', offset: 0 }), style({ backgroundColor: 'blue', offset: 0.2 }), style({ backgroundColor: 'orange', offset: 0.3 }), style({ backgroundColor: 'black', offset: 1 }) ])); Keyframes multistep.animation.ts

Slide 58

Slide 58 text

animate('5s', keyframes([ style({ backgroundColor: 'red', offset: 0 }), style({ backgroundColor: 'blue', offset: 0.2 }), style({ backgroundColor: 'orange', offset: 0.3 }), style({ backgroundColor: 'black', offset: 1 }) ])); Keyframes multistep.animation.ts

Slide 59

Slide 59 text

No content

Slide 60

Slide 60 text

2. Dynamic # of items

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

transition('inactive => active’, [ query('.container .item', [ style({ opacity: 0, transform: 'translateY(-50px)' }), stagger(100, [ animate('500ms', style({ opacity: 1, transform: 'none' })) ]) ]) ]) Setup the transition appear.animation.ts

Slide 63

Slide 63 text

transition('inactive => active', [ query('.container .item', [ style({ opacity: 0, transform: 'translateY(-50px)' }), stagger(100, [ animate('500ms', style({ opacity: 1, transform: 'none' })) ]) ]) ]) Query the DOM appear.animation.ts

Slide 64

Slide 64 text

transition('inactive => active', [ query('.container .item', [ style({ opacity: 0, transform: 'translateY(-50px)' }), stagger(100, [ animate('500ms', style({ opacity: 1, transform: 'none' })) ]) ]) ]) Initial styles appear.animation.ts

Slide 65

Slide 65 text

transition('inactive => active', [ query('.container .item', [ style({ opacity: 0, transform: 'translateY(-50px)' }), stagger(100, [ animate('500ms', style({ opacity: 1, transform: 'none' })) ]) ]) ]) Animate one by one appear.animation.ts

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

No content

Slide 68

Slide 68 text

3. Page transitions

Slide 69

Slide 69 text

No content

Slide 70

Slide 70 text

No content

Slide 71

Slide 71 text

1. Setup the template

Slide 72

Slide 72 text

Get data out of the outlet route.animation.ts

Slide 73

Slide 73 text

Bind to the animation route.animation.ts

Slide 74

Slide 74 text

Bind to the animation route.animation.ts Protip: you’ll want to use CSS to make your container use the whole page position: absolute; top: 0; right: 0; left: 0;

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

2. Configure route data

Slide 77

Slide 77 text

Routes config route.animation.ts const ROUTES: Routes = [ { path: '', component: HomeComponent, data: { page: '1' } }, { path: 'about', component: AboutComponent, data: { page: '2' } } ];

Slide 78

Slide 78 text

Routes config route.animation.ts const ROUTES: Routes = [ { path: '', component: HomeComponent, data: { page: '1' } }, { path: 'about', component: AboutComponent, data: { page: '2' } } ];

Slide 79

Slide 79 text

No content

Slide 80

Slide 80 text

3. Setup the animation

Slide 81

Slide 81 text

transition('1 => 2', [ style({ height: '!' }), query(':enter', style({ transform: 'translateX(-100%)' })), group([ query(':leave', animate('.6s cubic-bezier(…)', style({ transform: 'translat query(':enter', animate('.6s cubic-bezier(…)', style({ transform: 'translat ]) ]) Initial styles. Notice the '!' route.animation.ts

Slide 82

Slide 82 text

1 0 2 100% -100%

Slide 83

Slide 83 text

1 2 -100% 100% 0

Slide 84

Slide 84 text

transition('1 => 2', [ style({ height: '!' }), query(':enter', style({ transform: 'translateX(-100%)' })), group([ query(':leave', animate('.6s cubic-bezier(…)', style({ transform: 'translat query(':enter', animate('.6s cubic-bezier(…)', style({ transform: 'translat ]) ]) Initial styles route.animation.ts

Slide 85

Slide 85 text

transition('1 => 2', [ style({ height: '!' }), query(':enter', style({ transform: 'translateX(-100%)' })), group([ query(':leave', animate('.6s cubic-bezier(…)', style({ transform: 'translat query(':enter', animate('.6s cubic-bezier(…)', style({ transform: 'translat ]) ]) Initial styles route.animation.ts Protip: :enter is just an alias for void => *

Slide 86

Slide 86 text

transition('1 => 2', [ style({ height: '!' }), query(':enter', style({ transform: 'translateX(-100%)' })), group([ query(':leave', animate('.6s cubic-bezier(…)', style({ transform: 'translateX(100%)' }))), query(':enter', animate('.6s cubic-bezier(…)', style({ transform: 'translateX(0)' }))) ]) ]) Parallelise with group route.animation.ts

Slide 87

Slide 87 text

transition('1 => 2', [ style({ height: '!' }), query(':enter', style({ transform: 'translateX(-100%)' })), group([ query(':leave', animate('.6s cubic-bezier(…)', style({ transform: 'translateX(100%)' }))), query(':enter', animate('.6s cubic-bezier(…)', style({ transform: 'translateX(0)' }))) ]) ]) Parallelise with group route.animation.ts Protip: :leave is just an alias for * => void

Slide 88

Slide 88 text

transition('1 => 2', [ style({ height: '!' }), query(':enter', style({ transform: 'translateX(-100%)' })), group([ query(':leave', animate('.6s cubic-bezier(…)', style({ transform: 'translateX(100%)' }))), query(':enter', animate('.6s cubic-bezier(…)', style({ transform: 'translateX(0)' }))) ]) ]) Parallelise with group route.animation.ts

Slide 89

Slide 89 text

No content

Slide 90

Slide 90 text

No content

Slide 91

Slide 91 text

4. Programmatic animations

Slide 92

Slide 92 text

No content

Slide 93

Slide 93 text

No content

Slide 94

Slide 94 text

export class StoriesComponent { @Input('position') set position(pos: number) { this.pause(); this.player.setPosition(pos / 100); } play() { this.player.play(); } pause() { this.player.pause(); } } stories.component.ts

Slide 95

Slide 95 text

export class StoriesComponent { @Input('position') set position(pos: number) { this.pause(); this.player.setPosition(pos / 100); } play() { this.player.play(); } pause() { this.player.pause(); } } stories.component.ts

Slide 96

Slide 96 text

constructor(private builder: AnimationBuilder, private element: ElementRef) { const animation = this.builder.build([...]); const player = animation.create(this.element.nativeElement); } Inject builder and element stories.component.ts

Slide 97

Slide 97 text

constructor(private builder: AnimationBuilder, private element: ElementRef) { const animation = this.builder.build([...]); const player = animation.create(this.element.nativeElement); } Build the animation stories.component.ts

Slide 98

Slide 98 text

constructor(private builder: AnimationBuilder, private element: ElementRef) { const animation = this.builder.build([...]); const player = animation.create(this.element.nativeElement); } Create the player stories.component.ts

Slide 99

Slide 99 text

No content

Slide 100

Slide 100 text

No content

Slide 101

Slide 101 text

No content

Slide 102

Slide 102 text

Takeaways

Slide 103

Slide 103 text

No content

Slide 104

Slide 104 text

CSS can take you so far

Slide 105

Slide 105 text

No content

Slide 106

Slide 106 text

No content

Slide 107

Slide 107 text

No content

Slide 108

Slide 108 text

No content

Slide 109

Slide 109 text

Thanks! @cironunesdev

Slide 110

Slide 110 text

No content

Slide 111

Slide 111 text

Bonus time! https://stackblitz.com/edit/zen-feedback

Slide 112

Slide 112 text

No content

Slide 113

Slide 113 text

Slides of this talk: cnun.es/animations Interactive Angular animation guide: animationsftw.in Links Where to go? My website: cironunes.com Docs: next.angular.io/guide/animations