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 anObservable
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 theObserver
interface. It is an object that defines callback methods to handle the
three types of notifications that an observable can send:Subscribing
AnObservable
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 anObservable
instance that synchronously delivers the values provided as arguments.Observable.from(iterable)
—Converts its argument to anObservable
instance. This method is commonly used to convert an array to an observable.
Creating observables
Use theObservable
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 anerror
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 asmap()
, 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 theerror()
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 extendsObservable
. - 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 anEventEmitter
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’sHttpClient
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. TheFormControl
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:- Export it from the file where you wrote it.
- Import it into the appropriate module.
- 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
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.
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:
- A basic understanding of Bootstrapping.
- Familiarity with Frequently Used Modules.
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: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:
- A basic understanding of Bootstrapping.
- Familiarity with Providers.
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 theAppModule
.
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:- Feature Modules.
- JavaScript Modules vs. NgModules.
- Frequently Used Modules.
- Types of Feature Modules.
- Routing and Navigation.
High level view
There are three main steps to setting up a lazy loaded feature module:- Create the feature module.
- Create the feature module’s routing module.
- 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
You can also use forward references to break circular dependencies. See an example in the DI Cookbook.
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.
@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: theXMLHttpRequest
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
The sample app does not require a data server.
It relies on the
Angular in-memory-web-api,
which replaces the HttpClient module's
Look at the
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 theintercept()
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
TheHttpClient.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 AngularRouter
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
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 theRouter
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
TheRouterOutlet
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 -->
Router links
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>
Active router links
TheRouterLinkActive
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 ofActivatedRoute
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. IRouter events
During each navigation, theRouter
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.
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'sstate()
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
Theanimate()
function (second argument of the transition function) accepts the timings
and styles
input parameters.The
timings
parameter takes a string defined in three parts.The first part,animate ('duration delay easing')
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'
delay
, has the same syntax as duration
. For example:- Wait for 100ms and then run for 200ms:
'0.2s 100ms'
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. Thetrigger()
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 theanimations:
property within the @Component()
decorator.Summary
You learned to add animation to a simple transition between two states, usingstyle()
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 theanimation()
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:
- Import the routing module into the application and create a routing configuration that defines the possible routes.
- Add a router outlet to tell the Angular router where to place the activated components in the DOM.
- Define the animation.
Cheat Sheet
Setup for local development
TheSetting 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
0 comments:
Post a Comment