Observables

Observables provide support for passing messages between publishers and subscribers in your application. Observables offer significant benefits over other techniques for event handling, asynchronous programming, and handling multiple values.
Observables are declarative—that is, you define a function for publishing values, but it is not executed until a consumer subscribes to it. The subscribed consumer then receives notifications until the function completes, or until they unsubscribe.
An observable can deliver multiple values of any type—literals, messages, or events, depending on the context. The API for receiving values is the same whether the values are delivered synchronously or asynchronously. Because setup and teardown logic are both handled by the observable, your application code only needs to worry about subscribing to consume values, and when done, unsubscribing. Whether the stream was keystrokes, an HTTP response, or an interval timer, the interface for listening to values and stopping listening is the same.
Because of these advantages, observables are used extensively within Angular, and are recommended for app development as well.

Basic usage and terms

As a publisher, you create an Observable instance that defines a subscriber function. This is the function that is executed when a consumer calls the subscribe() method. The subscriber function defines how to obtain or generate values or messages to be published.

To execute the observable you have created and begin receiving notifications, you call its subscribe() method, passing an observer. This is a JavaScript object that defines the handlers for the notifications you receive. The subscribe() call returns a Subscription object that has an unsubscribe() method, which you call to stop receiving notifications.

Defining observers

A handler for receiving observable notifications implements the Observer interface. It is an object that defines callback methods to handle the three types of notifications that an observable can send:

Subscribing

An Observable instance begins publishing values only when someone subscribes to it. You subscribe by calling the subscribe() method of the instance, passing an observer object to receive the notifications.
In order to show how subscribing works, we need to create a new observable. There is a constructor that you use to create new instances, but for illustration, we can use some static methods on the Observable class that create simple observables of frequently used types:
  • Observable.of(...items)—Returns an Observable instance that synchronously delivers the values provided as arguments.
  • Observable.from(iterable)—Converts its argument to an Observable instance. This method is commonly used to convert an array to an observable.




























Creating observables

Use the Observable constructor to create an observable stream of any type. The constructor takes as its argument the subscriber function to run when the observable’s subscribe() method executes. A subscriber function receives an Observer object, and can publish values to the observer's next() method.

Multicasting

A typical observable creates a new, independent execution for each subscribed observer. When an observer subscribes, the observable wires up an event handler and delivers values to that observer. When a second observer subscribes, the observable then wires up a new event handler and delivers values to that second observer in a separate execution.
Sometimes, instead of starting an independent execution for each subscriber, you want each subscription to get the same values—even if values have already started emitting. This might be the case with something like an observable of clicks on the document object.
Multicasting is the practice of broadcasting to a list of multiple subscribers in a single execution. With a multicasting observable, you don't register multiple listeners on the document, but instead re-use the first listener and send values out to each subscriber.

When creating an observable you should determine how you want that observable to be used and whether or not you want to multicast its values.

Error handling

Because observables produce values asynchronously, try/catch will not effectively catch errors. Instead, you handle errors by specifying an error callback on the observer. Producing an error also causes the observable to clean up subscriptions and stop producing values. An observable can either produce values (calling the next callback), or it can complete, calling either the complete or error callback.









The RxJS library

Reactive programming is an asynchronous programming paradigm concerned with data streams and the propagation of change (Wikipedia). RxJS (Reactive Extensions for JavaScript) is a library for reactive programming using observables that makes it easier to compose asynchronous or callback-based code (RxJS Docs).
RxJS provides an implementation of the Observable type, which is needed until the type becomes part of the language and until browsers support it. The library also provides utility functions for creating and working with observables. These utility functions can be used for:

  • Converting existing code for async operations into observables
  • Iterating through the values in a stream
  • Mapping values to different types
  • Filtering streams
  • Composing multiple streams

Observable creation functions

RxJS offers a number of functions that can be used to create new observables. These functions can simplify the process of creating observables from things such as events, timers, promises, and so on.

Operators

Operators are functions that build on the observables foundation to enable sophisticated manipulation of collections. For example, RxJS defines operators such as map(), filter(), concat(), and flatMap().
Operators take configuration options, and they return a function that takes a source observable. When executing this returned function, the operator observes the source observable’s emitted values.

You can use pipes to link operators together. Pipes let you combine multiple functions into a single function. The pipe() function takes as its arguments the functions you want to combine, and returns a new function that, when executed, runs the composed functions in sequence.
A set of operators applied to an observable is a recipe—that is, a set of instructions for producing the values you’re interested in. By itself, the recipe doesn’t do anything. You need to call subscribe() to produce a result through the recipe.

Common operators

RxJS provides many operators, but only a handful are used frequently. For a list of operators and usage samples, visit the RxJS API Documentation.
Note that, for Angular apps, we prefer combining operators with pipes, rather than chaining. Chaining is used in many RxJS examples. 























Error handling

In addition to the error() handler that you provide on subscription, RxJS provides the catchError operator that lets you handle known errors in the observable recipe.
For instance, suppose you have an observable that makes an API request and maps to the response from the server. If the server returns an error or the value doesn’t exist, an error is produced. If you catch this error and supply a default value, your stream continues to process values rather than erroring out.

Naming conventions for observables

Because Angular applications are mostly written in TypeScript, you will typically know when a variable is an observable. Although the Angular framework does not enforce a naming convention for observables, you will often see observables named with a trailing “$” sign.
This can be useful when scanning through code and looking for observable values. Also, if you want a property to store the most recent value from an observable, it can be convenient to simply use the same name with or without the “$”.


Observables in Angular

Angular makes use of observables as an interface to handle a variety of common asynchronous operations. For example:
  • The EventEmitter class extends Observable.
  • The HTTP module uses observables to handle AJAX requests and responses.
  • The Router and Forms modules use observables to listen for and respond to user-input events.

Event emitter

Angular provides an EventEmitter class that is used when publishing values from a component through the @Output() decorator. EventEmitter extends Observable, adding an emit() method so it can send arbitrary values. When you call emit(), it passes the emitted value to the next() method of any subscribed observer.
A good example of usage can be found on the EventEmitter documentation. Here is the example component that listens for open and close events:

<zippy (open)="onOpen($event)" (close)="onClose($event)"></zippy>

HTTP

Angular’s HttpClient returns observables from HTTP method calls. For instance, http.get(‘/api’) returns an observable. This provides several advantages over promise-based HTTP APIs:
  • Observables do not mutate the server response (as can occur through chained .then() calls on promises). Instead, you can use a series of operators to transform values as needed.
  • HTTP requests are cancellable through the unsubscribe() method.
  • Requests can be configured to get progress event updates.
  • Failed requests can be retried easily.

Router

Router.events provides events as observables. You can use the filter() operator from RxJS to look for events of interest, and subscribe to them in order to make decisions based on the sequence of events in the navigation process.

Reactive forms

Reactive forms have properties that use observables to monitor form control values. The FormControl properties valueChanges and statusChanges contain observables that raise change events. Subscribing to an observable form-control property is a way of triggering application logic within the component class.

Observables compared to other techniques

You can often use observables instead of promises to deliver values asynchronously. Similarly, observables can take the place of event handlers. Finally, because observables deliver multiple values, you can use them where you might otherwise build and operate on arrays.
Observables behave somewhat differently from the alternative techniques in each of these situations, but offer some significant advantages. Here are detailed comparisons of the differences.

Observables compared to promises

Observables are often compared to promises. Here are some key differences:

  • Observables are declarative; computation does not start until subscription. Promises execute immediately on creation. This makes observables useful for defining recipes that can be run whenever you need the result.
  • Observables provide many values. Promises provide one. This makes observables useful for getting multiple values over time.
  • Observables differentiate between chaining and subscription. Promises only have .then() clauses. This makes observables useful for creating complex transformation recipes to be used by other part of the system, without causing the work to be executed.
  • Observables subscribe() is responsible for handling errors. Promises push errors to the child promises. This makes observables useful for centralized and predictable error handling.

Observables compared to events API

Observables are very similar to event handlers that use the events API. Both techniques define notification handlers, and use them to process multiple values delivered over time. Subscribing to an observable is equivalent to adding an event listener. One significant difference is that you can configure an observable to transform an event before passing the event to the handler.
Using observables to handle events and asynchronous operations can have the advantage of greater consistency in contexts such as HTTP requests.

Observables compared to arrays

An observable produces values over time. An array is created as a static set of values. In a sense, observables are asynchronous where arrays are synchronous. In the following examples, ➞ implies asynchronous value delivery.

































































Bootstrapping

Prerequisites

A basic understanding of the following:


An NgModule describes how the application parts fit together. Every application has at least one Angular module, the root module that you bootstrap to launch the application. By convention, it is usually called AppModule.


After the import statements is a class with the @NgModule decorator.
The @NgModule decorator identifies AppModule as an NgModule class. @NgModule takes a metadata object that tells Angular how to compile and launch the application.
  • declarations—this application's lone component.
  • imports—import BrowserModule to have browser specific services such as DOM rendering, sanitization, and location.
  • providers—the service providers.
  • bootstrap—the root component that Angular creates and inserts into the index.html host web page.

The default CLI application only has one component, AppComponent, so it is in both the declarations and the bootstrap arrays.

The declarations array

The module's declarations array tells Angular which components belong to that module. As you create more components, add them to declarations.
You must declare every component in exactly one NgModule class. If you use a component without declaring it, Angular returns an error message.

Using directives with @NgModule

Use the declarations array for directives. To use a directive, component, or pipe in a module, you must do a few things:
  1. Export it from the file where you wrote it.
  2. Import it into the appropriate module.
  3. Declare it in the @NgModule declarations array.

The bootstrap array

The application launches by bootstrapping the root AppModule, which is also referred to as an entryComponent. Among other things, the bootstrapping process creates the component(s) listed in the bootstrap array and inserts each one into the browser DOM.

NgModules

Prerequisites

A basic understanding of the following concepts:

NgModules configure the injector and the compiler and help organize related things together.
An NgModule is a class marked by the @NgModule decorator. @NgModule takes a metadata object that describes how to compile a component's template and how to create an injector at runtime. It identifies the module's own components, directives, and pipes, making some of them public, through the exports property, so that external components can use them. @NgModule can also add service providers to the application dependency injectors.
For an example app showcasing all the techniques that NgModules related pages cover, see the live example / download example. For explanations on the individual techniques, visit the relevant NgModule pages under the NgModules section.

Angular modularity

Modules are a great way to organize an application and extend it with capabilities from external libraries.
Angular libraries are NgModules, such as FormsModule, HttpClientModule, and RouterModule. Many third-party libraries are available as NgModules such as Material Design, Ionic, and AngularFire2.
NgModules consolidate components, directives, and pipes into cohesive blocks of functionality, each focused on a feature area, application business domain, workflow, or common collection of utilities.
Modules can also add services to the application. Such services might be internally developed, like something you'd develop yourself or come from outside sources, such as the Angular router and HTTP client.
Modules can be loaded eagerly when the application starts or lazy loaded asynchronously by the router.
NgModule metadata does the following:
  • Declares which components, directives, and pipes belong to the module.
  • Makes some of those components, directives, and pipes public so that other module's component templates can use them.
  • Imports other modules with the components, directives, and pipes that components in the current module need.
  • Provides services that the other application components can use.
Every Angular app has at least one module, the root module. You bootstrap that module to launch the application.

The root module is all you need in a simple application with a few components. As the app grows, you refactor the root module into feature modules that represent collections of related functionality. You then import these modules into the root module.

Entry Components

Prerequisites:

A basic understanding of the following concepts:

An entry component is any component that Angular loads imperatively, (which means you’re not referencing it in the template), by type. You specify an entry component by bootstrapping it in an NgModule, or including it in a routing definition.
To contrast the two types of components, there are components which are included in the template, which are declarative. Additionally, there are components which you load imperatively; that is, entry components.
There are two main kinds of entry components:
  • The bootstrapped root component.
  • A component you specify in a route definition.

A bootstrapped entry component

The following is an example of specifying a bootstrapped component, AppComponent, in a basic app.module.ts:

Providers

Prerequisites:

For the final sample app using the provider that this page describes, see the live example / download example.

A provider is an instruction to the DI system on how to obtain a value for a dependency. Most of the time, these dependencies are services that you create and provide.

Providing a service

If you already have a CLI generated app, create a service using the following CLI command in the root project directory. Replace User with the name of your service.
      
ng generate service User
    
This command creates the following UserService skeleton:
src/app/user.service.0.ts
      
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class UserService {
}
    
You can now inject UserService anywhere in your application.
The service itself is a class that the CLI generated and that's decorated with @Injectable. By default, this decorator is configured with a providedIn property, which creates a provider for the service. In this case, providedIn: 'root' specifies that the service should be provided in the root injector.

Provider scope

When you add a service provider to the root application injector, it’s available throughout the app. Additionally, these providers are also available to all the classes in the app as long they have the lookup token.

You should always provide your service in the root injector unless there is a case where you want the service to be available only if the consumer imports a particular @NgModule.

Singleton services

Prerequisites:

For a sample app using the app-wide singleton service that this page describes, see the live example / download example showcasing all the documented features of NgModules.

Providing a singleton service

There are two ways to make a service a singleton in Angular:
  • Declare that the service should be provided in the application root.
  • Include the service in the AppModule or in a module that is only imported by the AppModule.

Beginning with Angular 6.0, the preferred way to create a singleton services is to specify on the service that it should be provided in the application root.

Lazy Loading Feature Modules

Prerequisites

A basic understanding of the following:
For the final sample app with two lazy loaded modules that this page describes, see the live example / download example.

High level view

There are three main steps to setting up a lazy loaded feature module:

  1. Create the feature module.
  2. Create the feature module’s routing module.
  3. Configure the routes.































forRoot() and forChild()

You might have noticed that the CLI adds RouterModule.forRoot(routes) to the app-routing.module.ts imports array. This lets Angular know that this module, AppRoutingModule, is a routing module and forRoot() specifies that this is the root routing module. It configures all the routes you pass to it, gives you access to the router directives, and registers the RouterService. Use forRoot() in the AppRoutingModule—that is, one time in the app at the root level.
The CLI also adds RouterModule.forChild(routes) to feature routing modules. This way, Angular knows that the route list is only responsible for providing additional routes and is intended for feature modules. You can use forChild() in multiple modules.

forRoot() contains injector configuration which is global; such as configuring the Router. forChild() has no injector configuration, only directives such as RouterOutlet and RouterLink.


Dependency Injection in Angular

Dependency injection (DI), is an important application design pattern. Angular has its own DI framework, which is typically used in the design of Angular applications to increase their efficiency and modularity.
Dependencies are services or objects that a class needs to perform its function. DI is a coding pattern in which a class asks for dependencies from external sources rather than creating them itself.
In Angular, the DI framework provides declared dependencies to a class when that class is instantiated. This guide explains how DI works in Angular, and how you use it to make your apps flexible, efficient, and robust, as well as testable and maintainable.

You can run the live example / download example of the sample app that accompanies this guide.

Create and register an injectable service

The DI framework lets you supply data to a component from an injectable service class, defined in its own file. To demonstrate, we'll create an injectable service class that provides a list of heroes, and register that class as a provider of that service.
Having multiple classes in the same file can be confusing. We generally recommend that you define components and services in separate files.
If you do combine a component and service in the same file, it is important to define the service first, and then the component. If you define the component before the service, you get a run-time null reference error.
It is possible to define the component first with the help of the forwardRef() method as explained in this blog post.
You can also use forward references to break circular dependencies. See an example in the DI Cookbook.


Configure an injector with a service provider

The class we have created provides a service. The @Injectable() decorator marks it as a service that can be injected, but Angular can't actually inject it anywhere until you configure an Angular dependency injector with a provider of that service.
The injector is responsible for creating service instances and injecting them into classes like HeroListComponent.
You rarely create an Angular injector yourself. Angular creates injectors for you as it executes the app, starting with the root injector that it creates during the bootstrap process.

A provider tells an injector how to create the service. You must configure an injector with a provider before that injector can create a service (or provide any other kind of dependency).
You can configure injectors with providers at different levels of your app, by setting a metadata value in one of three places:
  • In the @Injectable() decorator for the service itself.
  • In the @NgModule() decorator for an NgModule.
  • In the @Component() decorator for a component.
The @Injectable() decorator has the providedIn metadata option, where you can specify the provider of the decorated service class with the root injector, or with the injector for a specific NgModule.

The @NgModule() and @Component() decorators have the providers metadata option, where you can configure providers for NgModule-level or component-level injectors.

Behind the scenes, each component sets up its own injector with zero, one, or more providers defined for that component itself.
When you resolve an instance of Car at the deepest component (C), its injector produces an instance of Car resolved by injector (C) with an Engine resolved by injector (B) and Tires resolved by the root injector (A).




HttpClient

Most front-end applications communicate with backend services over the HTTP protocol. Modern browsers support two different APIs for making HTTP requests: the XMLHttpRequest interface and the fetch() API.
The HttpClient in @angular/common/http offers a simplified client HTTP API for Angular applications that rests on the XMLHttpRequest interface exposed by browsers. Additional benefits of HttpClient include testability features, typed request and response objects, request and response interception, Observable apis, and streamlined error handling.
You can run the live example / download example that accompanies this guide.

The sample app does not require a data server. It relies on the Angular in-memory-web-api, which replaces the HttpClient module's HttpBackend. The replacement service simulates the behavior of a REST-like backend.
Look at the AppModule imports to see how it is configured.

































Making a POST request

Apps often POST data to a server. They POST when submitting a form. In the following example, the HeroesService posts when adding a hero to the database.

/** POST: add a new hero to the database */
addHero (hero: Hero): Observable<Hero> {
  return this.http.post<Hero>(this.heroesUrl, hero, httpOptions)
    .pipe(
      catchError(this.handleError('addHero', hero))
    );
}

HttpEvents

You may have expected the intercept() and handle() methods to return observables of HttpResponse<any> as most HttpClient methods do.
Instead they return observables of HttpEvent<any>.
That's because interceptors work at a lower level than those HttpClient methods. A single HTTP request can generate multiple events, including upload and download progress events. The HttpResponse class itself is actually an event, whose type is HttpEventType.HttpResponseEvent.
Many interceptors are only concerned with the outgoing request and simply return the event stream from next.handle() without modifying it.

But interceptors that examine and modify the response from next.handle() will see all of these events. Your interceptor should return every event untouched unless it has a compelling reason to do otherwise.

Return a multi-valued Observable

The HttpClient.get() method normally returns an observable that either emits the data or an error. Some folks describe it as a "one and done" observable.
But an interceptor can change this to an observable that emits more than once.

Listening to progress events

Sometimes applications transfer large amounts of data and those transfers can take a long time. File uploads are a typical example. Give the users a better experience by providing feedback on the progress of such transfers.
To make a request with progress events enabled, you can create an instance of HttpRequest with the reportProgress option set true to enable tracking of progress events.

Routing & Navigation

The Angular Router enables navigation from one view to the next as users perform application tasks.
This guide covers the router's primary features, illustrating them through the evolution of a small application that you can run live in the browser / download example.

Overview

The browser is a familiar model of application navigation:
  • Enter a URL in the address bar and the browser navigates to a corresponding page.
  • Click links on the page and the browser navigates to a new page.
  • Click the browser's back and forward buttons and the browser navigates backward and forward through the history of pages you've seen.

The Angular Router ("the router") borrows from this model. It can interpret a browser URL as an instruction to navigate to a client-generated view. It can pass optional parameters along to the supporting view component that help it decide what specific content to present. You can bind the router to links on a page and it will navigate to the appropriate application view when the user clicks a link. You can navigate imperatively when the user clicks a button, selects from a drop box, or in response to some other stimulus from any source. And the router logs activity in the browser's history journal so the back and forward buttons work as well.

<base href>

Most routing applications should add a <base> element to the index.html as the first child in the <head> tag to tell the router how to compose navigation URLs.
If the app folder is the application root, as it is for the sample application, set the href value exactly as shown here.
<base href="/">

Router imports

The Angular Router is an optional service that presents a particular component view for a given URL. It is not part of the Angular core. It is in its own library package, @angular/router. Import what you need from it as you would from any other Angular package.
import { RouterModule, Routes } from '@angular/router';

Configuration

A routed Angular application has one singleton instance of the Router service. When the browser's URL changes, that router looks for a corresponding Route from which it can determine the component to display.
A router has no routes until you configure it. The following example creates five route definitions, configures the router via the RouterModule.forRoot method, and adds the result to the AppModule's imports array.
const appRoutes: Routes = [
  { path: 'crisis-center', component: CrisisListComponent },
  { path: 'hero/:id',      component: HeroDetailComponent },
  {
    path: 'heroes',
    component: HeroListComponent,
    data: { title: 'Heroes List' }
  },
  { path: '',
    redirectTo: '/heroes',
    pathMatch: 'full'
  },
  { path: '**', component: PageNotFoundComponent }
];
The appRoutes array of routes describes how to navigate. Pass it to the RouterModule.forRoot method in the module imports to configure the router.
Each Route maps a URL path to a component. There are no leading slashes in the path. The router parses and builds the final URL for you, allowing you to use both relative and absolute paths when navigating between application views.

The :id in the second route is a token for a route parameter. In a URL such as /hero/42, "42" is the value of the id parameter. The corresponding HeroDetailComponent will use that value to find and present the hero whose id is 42. You'll learn more about route parameters later in this guide.

Router outlet

The RouterOutlet is a directive from the router library that is used like a component. It acts as a placeholder that marks the spot in the template where the router should display the components for that outlet.
<router-outlet></router-outlet>
<!-- Routed components go here -->
Now you have routes configured and a place to render them, but how do you navigate? The URL could arrive directly from the browser address bar. But most of the time you navigate as a result of some user action such as the click of an anchor tag.
<nav>
  <a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a>
  <a routerLink="/heroes" routerLinkActive="active">Heroes</a>
</nav>
<router-outlet></router-outlet>

The RouterLinkActive directive toggles css classes for active RouterLink bindings based on the current RouterState.
On each anchor tag, you see a property binding to the RouterLinkActive directive that look like routerLinkActive="...".

The template expression to the right of the equals (=) contains a space-delimited string of CSS classes that the Router will add when this link is active (and remove when the link is inactive). You set the RouterLinkActive directive to a string of classes such as [routerLinkActive]="'active fluffy'" or bind it to a component property that returns such a string.

Router state

After the end of each successful navigation lifecycle, the router builds a tree of ActivatedRoute objects that make up the current state of the router. You can access the current RouterState from anywhere in the application using the Router service and the routerState property.
Each ActivatedRoute in the RouterState provides methods to traverse up and down the route tree to get information from parent, child and sibling routes.

Activated route

The route path and parameters are available through an injected router service called the ActivatedRoute. I

Router events

During each navigation, the Router emits navigation events through the Router.events property. These events range from when the navigation starts and ends to many points in between.

A crisis center with child routes

This section shows you how to organize the crisis center to conform to the following recommended pattern for Angular applications:
  • Each feature area resides in its own folder.
  • Each feature has its own Angular feature module.
  • Each area has its own area root component.
  • Each area root component has its own router outlet and child routes.
  • Feature area routes rarely (if ever) cross with routes of other features.

If your app had many feature areas, the app component trees might look like this:

Introduction to Angular animations

Animation provides the illusion of motion: HTML elements change styling over time. Well-designed animations can make your application more fun and easier to use, but they aren't just cosmetic. Animations can improve your app and user experience in a number of ways:
  • Without animations, web page transitions can seem abrupt and jarring.
  • Motion greatly enhances the user experience, so animations give users a chance to detect the application's response to their actions.
  • Good animations intuitively call the user's attention to where it is needed.
Typically, animations involve multiple style transformations over time. An HTML element can move, change color, grow or shrink, fade, or slide off the page. These changes can occur simultaneously or sequentially. You can control the timing of each transformation.

Angular's animation system is built on CSS functionality, which means you can animate any property that the browser considers animatable. This includes positions, sizes, transforms, colors, borders, and more. The W3C maintains a list of animatable properties on its CSS Transitions page.

Animation state and styles

Use Angular's state() function to define different states to call at the end of each transition. This function takes two arguments: a unique name like open or closed and a style() function.
Use the style() function to define a set of styles to associate with a given state name. Note that the style attributes must be in camelCase.

Let's see how Angular's state() function works with the style⁣­(⁠) function to set CSS style attributes. In this code snippet, multiple style attributes are set at the same time for the state.

Transitions and timing

In Angular, you can set multiple styles without any animation. However, without further refinement, the button instantly transforms with no fade, no shrinkage, or other visible indicator that a change is occurring.
To make the change less abrupt, we need to define an animation transition to specify the changes that occur between one state and another over a period of time. The transition() function accepts two arguments: the first argument accepts an expression that defines the direction between two transition states, and the second argument accepts an animate() function.
Use the animate() function to define the length, delay, and easing of a transition, and to designate the style function for defining styles while transitions are taking place. You can also use the animate() function to define the keyframes() function for multi-step animations. These definitions are placed in the second argument of the animate() function.

Animation metadata: duration, delay, and easing

The animate() function (second argument of the transition function) accepts the timings and styles input parameters.
The timings parameter takes a string defined in three parts.
animate ('duration delay easing')
The first part, duration, is required. The duration can be expressed in milliseconds as a simple number without quotes, or in seconds with quotes and a time specifier. For example, a duration of a tenth of a second can be expressed as follows:
  • As a plain number, in milliseconds: 100
  • In a string, as milliseconds: '100ms'
  • In a string, as seconds: '0.1s'
The second argument, delay, has the same syntax as duration. For example:
  • Wait for 100ms and then run for 200ms: '0.2s 100ms'
The third argument, easing, controls how the animation accelerates and decelerates during its runtime. For example, ease-in causes the animation to begin slowly, and to pick up speed as it progresses.

  • Wait for 100ms, run for 200ms. Use a deceleration curve to start out fast and slowly decelerate to a resting point: '0.2s 100ms ease-out'
  • Run for 200ms, with no delay. Use a standard curve to start slow, accelerate in the middle, and then decelerate slowly at the end: '0.2s ease-in-out'
  • Start immediately, run for 200ms. Use a acceleration curve to start slow and end at full velocity: '0.2s ease-in'

Triggering the animation

An animation requires a trigger, so that it knows when to start. The trigger() function collects the states and transitions, and gives the animation a name, so that you can attach it to the triggering element in the HTML template.
The trigger() function describes the property name to watch for changes. When a change occurs, the trigger initiates the actions included in its definition. These actions can be transitions or other functions, as we'll see later on.

In this example, we'll name the trigger openClose, and attach it to the button element. The trigger describes the open and closed states, and the timings for the two transitions.


Defining animations and attaching them to the HTML template

Animations are defined in the metadata of the component that controls the HTML element to be animated. Put the code that defines your animations under the animations: property within the @Component() decorator.

Summary

You learned to add animation to a simple transition between two states, using style() and state() along with animate() for the timing.
You can learn about more advanced features in Angular animations under the Animation section, beginning with advanced techniques in transition and triggers.

Animations transitions and triggers

You learned the basics of Angular animations in the introduction page.

In this guide, we go into greater depth on special transition states such as * (wildcard) and void, and show how these special states are used for elements entering and leaving a view. The chapter also explores on multiple animation triggers, animation callbacks and sequence-based animation using keyframes.

Wildcard state

An asterisk * or wildcard matches any animation state. This is useful for defining transitions that apply regardless of the HTML element's start or end state.
For example, a transition of open => * applies when the element's state changes from open to anything else.

Complex animation sequences

Prerequisites

A basic understanding of the following concepts:

So far, we've learned simple animations of single HTML elements. Angular also lets you animate coordinated sequences, such as an entire grid or list of elements as they enter and leave a page. You can choose to run multiple animations in parallel, or run discrete animations sequentially, one following another.
Functions that control complex animation sequences are as follows:

  • query() finds one or more inner HTML elements.
  • stagger() applies a cascading delay to animations for multiple elements.
  • group() runs multiple animation steps in parallel.
  • sequence() runs animation steps one after another.

Reusable animations

Prerequisites

A basic understanding of the following concepts:

The AnimationOptions interface in Angular animations enables you to create animations that you can reuse across different components.

Creating reusable animations

To create a reusable animation, use the animation() method to define an animation in a separate .ts file and declare this animation definition as a const export variable. You can then import and reuse this animation in any of your app components using the useAnimation() API.

Route transition animations

Prerequisites

A basic understanding of the following concepts:

Routing enables users to navigate between different routes in an application. When a user navigates from one route to another, the Angular router maps the URL path to a relevant component and displays its view. Animating this route transition can greatly enhance the user experience.
The Angular router comes with high-level animation functions that let you animate the transitions between views when a route changes. To produce an animation sequence when switching between routes, you need to define nested animation sequences. Start with the top-level component that hosts the view, and nest additional animations in the components that host the embedded views.
To enable routing transition animation, do the following:

  1. Import the routing module into the application and create a routing configuration that defines the possible routes.
  2. Add a router outlet to tell the Angular router where to place the activated components in the DOM.
  3. Define the animation.

Cheat Sheet


Setup for local development

The QuickStart live-coding / download example example is an Angular playground. It's not where you'd develop a real application. You should develop locally on your own machine ... and that's also how we think you should learn Angular.
Setting up a new project on your machine is quick and easy with the QuickStart seed, maintained on github.

Make sure you have Node.js® and npm installed.

Deployment

This page describes techniques for deploying your Angular application to a remote server.

Upgrading from AngularJS to Angular

Angular is the name for the Angular of today and tomorrow.
AngularJS is the name for all 1.x versions of Angular.
AngularJS apps are great. Always consider the business case before moving to Angular. An important part of that case is the time and effort to get there. This guide describes the built-in tools for efficiently migrating AngularJS projects over to the Angular platform, a piece at a time.
Some applications will be easier to upgrade than others, and there are many ways to make it easier for yourself. It is possible to prepare and align AngularJS applications with Angular even before beginning the upgrade process. These preparation steps are all about making the code more decoupled, more maintainable, and better aligned with modern development tools. That means in addition to making the upgrade easier, you will also improve the existing AngularJS applications.

One of the keys to a successful upgrade is to do it incrementally, by running the two frameworks side by side in the same application, and porting AngularJS components to Angular one by one. This makes it possible to upgrade even large and complex applications without disrupting other business, because the work can be done collaboratively and spread over a period of time. The upgrade module in Angular has been designed to make incremental upgrading seamless.

AngularJS to Angular Concepts: Quick Reference

Angular is the name for the Angular of today and tomorrow. AngularJS is the name for all v1.x versions of Angular.
This guide helps you transition from AngularJS to Angular by mapping AngularJS syntax to the equivalent Angular syntax.

See the Angular syntax in this live example / download example.