feat(docs-infra): implement figure styles (#33259)
PR#28396 originally addressed an update via issue #23983 to make images more visible with a white background (implementation of gray "lightbox"). This PR implements those styles defined in PR#28396. PR Close #33259
This commit is contained in:
parent
355e54a410
commit
ba29e4d953
|
@ -69,8 +69,10 @@ Let's animate a simple transition that changes a single HTML element from one st
|
|||
|
||||
In HTML, these attributes are set using ordinary CSS styles such as color and opacity. In Angular, use the `style()` function to specify a set of CSS styles for use with animations. You can collect a set of styles in an animation state, and give the state a name, such as `open` or `closed`.
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/animations/open-closed.png" alt="open and closed states">
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/animations/open-closed.png" alt="open and closed states">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
### Animation state and styles
|
||||
|
@ -166,8 +168,10 @@ The `trigger()` function describes the property name to watch for changes. When
|
|||
|
||||
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.
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/animations/triggering-the-animation.png" alt="triggering the animation">
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/animations/triggering-the-animation.png" alt="triggering the animation">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
|
|
@ -51,8 +51,10 @@ You define a component's view with its companion template. A template is a form
|
|||
|
||||
Views are typically arranged hierarchically, allowing you to modify or show and hide entire UI sections or pages as a unit. The template immediately associated with a component defines that component's *host view*. The component can also define a *view hierarchy*, which contains *embedded views*, hosted by other components.
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/architecture/component-tree.png" alt="Component tree" class="left">
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/architecture/component-tree.png" alt="Component tree" class="left">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
A view hierarchy can include views from components in the same NgModule, but it also can (and often does) include views from components that are defined in different NgModules.
|
||||
|
@ -81,8 +83,10 @@ Angular supports *two-way data binding*, a mechanism for coordinating the parts
|
|||
|
||||
The following diagram shows the four forms of data binding markup. Each form has a direction: to the DOM, from the DOM, or both.
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/architecture/databinding.png" alt="Data Binding" class="left">
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/architecture/databinding.png" alt="Data Binding" class="left">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
This example from the `HeroListComponent` template uses three of these forms.
|
||||
|
@ -110,14 +114,18 @@ as with event binding.
|
|||
Angular processes *all* data bindings once for each JavaScript event cycle,
|
||||
from the root of the application component tree through all child components.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/architecture/component-databinding.png" alt="Data Binding" class="left">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Data binding plays an important role in communication between a template and its component, and is also important for communication between parent and child components.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/architecture/parent-child-binding.png" alt="Parent/Child binding" class="left">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
### Pipes
|
||||
|
|
|
@ -35,20 +35,20 @@ Here's a simple root NgModule definition.
|
|||
|
||||
NgModules provide a *compilation context* for their components. A root NgModule always has a root component that is created during bootstrap, but any NgModule can include any number of additional components, which can be loaded through the router or created through the template. The components that belong to an NgModule share a compilation context.
|
||||
|
||||
<figure>
|
||||
|
||||
<img src="generated/images/guide/architecture/compilation-context.png" alt="Component compilation context" class="left">
|
||||
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/architecture/compilation-context.png" alt="Component compilation context" class="left">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
A component and its template together define a *view*. A component can contain a *view hierarchy*, which allows you to define arbitrarily complex areas of the screen that can be created, modified, and destroyed as a unit. A view hierarchy can mix views defined in components that belong to different NgModules. This is often the case, especially for UI libraries.
|
||||
|
||||
<figure>
|
||||
|
||||
<img src="generated/images/guide/architecture/view-hierarchy.png" alt="View hierarchy" class="left">
|
||||
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/architecture/view-hierarchy.png" alt="View hierarchy" class="left">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<br class="clear">
|
||||
|
|
|
@ -70,8 +70,10 @@ When all requested services have been resolved and returned, Angular can call th
|
|||
|
||||
The process of `HeroService` injection looks something like this.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/architecture/injector-injects.png" alt="Service" class="left">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
### Providing services
|
||||
|
|
|
@ -113,8 +113,10 @@ To define navigation rules, you associate *navigation paths* with your component
|
|||
|
||||
You've learned the basics about the main building blocks of an Angular application. The following diagram shows how these basic pieces are related.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/architecture/overview2.png" alt="overview">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
* Together, a component and template define an Angular view.
|
||||
|
|
|
@ -175,8 +175,10 @@ Here's the updated directive in full:
|
|||
Run the app and confirm that the background color appears when
|
||||
the mouse hovers over the `p` and disappears as it moves out.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/attribute-directives/highlight-directive-anim.gif" alt="Second Highlight">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
{@a bindings}
|
||||
|
@ -271,8 +273,10 @@ Revise the `AppComponent.color` so that it has no initial value.
|
|||
|
||||
Here are the harness and directive in action.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/attribute-directives/highlight-directive-v2-anim.gif" alt="Highlight v.2">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
{@a second-property}
|
||||
|
@ -307,8 +311,10 @@ because you made it _public_ with the `@Input` decorator.
|
|||
|
||||
Here's how the harness should work when you're done coding.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/attribute-directives/highlight-directive-final-anim.gif" alt="Final Highlight">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
## Summary
|
||||
|
|
|
@ -50,8 +50,10 @@ and each iteration's `hero` instance to the child's `hero` property.
|
|||
The running application displays three heroes:
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/component-interaction/parent-to-child.png" alt="Parent-to-child">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -94,8 +96,10 @@ Here's the `NameParentComponent` demonstrating name variations including a name
|
|||
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/component-interaction/setter.png" alt="Parent-to-child-setter">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -152,8 +156,10 @@ The `VersionParentComponent` supplies the `minor` and `major` values and binds b
|
|||
Here's the output of a button-pushing sequence:
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/component-interaction/parent-to-child-on-changes.gif" alt="Parent-to-child-onchanges">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -206,8 +212,10 @@ The framework passes the event argument—represented by `$event`—to t
|
|||
and the method processes it:
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/component-interaction/child-to-parent.gif" alt="Child-to-parent">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -268,8 +276,10 @@ uses interpolation to display the child's `seconds` property.
|
|||
Here we see the parent and child working together.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/component-interaction/countdown-timer-anim.gif" alt="countdown timer">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -421,8 +431,10 @@ the parent `MissionControlComponent` and the `AstronautComponent` children,
|
|||
facilitated by the service:
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/component-interaction/bidirectional-service.gif" alt="bidirectional-service">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -40,8 +40,10 @@ and the framework resolves the nested dependencies.
|
|||
|
||||
When all dependencies are in place, `AppComponent` displays the user information.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection-in-action/logged-in-user.png" alt="Logged In User">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
{@a service-scope}
|
||||
|
@ -131,8 +133,10 @@ The template displays this data-bound property.
|
|||
Find this example in <live-example name="dependency-injection-in-action">live code</live-example>
|
||||
and confirm that the three `HeroBioComponent` instances have their own cached hero data.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection-in-action/hero-bios.png" alt="Bios">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
{@a qualify-dependency-lookup}
|
||||
|
@ -191,8 +195,10 @@ placing it in the `<ng-content>` slot of the `HeroBioComponent` template.
|
|||
|
||||
The result is shown below, with the hero's telephone number from `HeroContactComponent` projected above the hero description.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection-in-action/hero-bio-and-content.png" alt="bio and contact">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -221,8 +227,10 @@ When the property is marked as optional, Angular sets `loggerService` to null an
|
|||
|
||||
Here's `HeroBiosAndContactsComponent` in action.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection-in-action/hero-bios-and-contacts.png" alt="Bios with contact into">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -232,8 +240,10 @@ until it finds the logger at the `AppComponent` level.
|
|||
The logger logic kicks in and the hero display updates
|
||||
with the "!!!" marker to indicate that the logger was found.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection-in-action/hero-bio-contact-no-host.png" alt="Without @Host">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -294,8 +304,10 @@ first without a value (yielding the default color) and then with an assigned col
|
|||
|
||||
The following image shows the effect of mousing over the `<hero-bios-and-contacts>` tag.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection-in-action/highlight.png" alt="Highlighted bios">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
{@a providers}
|
||||
|
@ -347,8 +359,10 @@ You learned about some other methods in [Dependency Providers](guide/dependency-
|
|||
The following `HeroOfTheMonthComponent` example demonstrates many of the alternatives and why you need them.
|
||||
It's visually simple: a few properties and the logs produced by a logger.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection-in-action/hero-of-month.png" alt="Hero of the month">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The code behind it customizes how and where the DI framework provides dependencies.
|
||||
|
@ -460,8 +474,10 @@ The following example puts `MinimalLogger` to use in a simplified version of `He
|
|||
|
||||
The `HeroOfTheMonthComponent` constructor's `logger` parameter is typed as `MinimalLogger`, so only the `logs` and `logInfo` members are visible in a TypeScript-aware editor.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection-in-action/minimal-logger-intellisense.png" alt="MinimalLogger restricted API">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -472,8 +488,10 @@ Behind the scenes, Angular sets the `logger` parameter to the full service regis
|
|||
|
||||
This is illustrated in the following image, which displays the logging date.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection-in-action/date-logger-entry.png" alt="DateLoggerService entry">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
</div>
|
||||
|
@ -627,8 +645,10 @@ and then pass them down to the base class through the constructor.
|
|||
In this contrived example, `SortedHeroesComponent` inherits from `HeroesBaseComponent`
|
||||
to display a *sorted* list of heroes.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection-in-action/sorted-heroes.png" alt="Sorted Heroes">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The `HeroesBaseComponent` can stand on its own.
|
||||
|
|
|
@ -145,8 +145,10 @@ the same way you've done it before.
|
|||
|
||||
Here's *Alex* and family in action.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection-in-action/alex.png" alt="Alex in action">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -201,8 +203,10 @@ which *is* what parent means.
|
|||
Here's *Alice*, *Barry*, and family in action.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection-in-action/alice.png" alt="Alice in action">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -386,8 +386,10 @@ showing exactly which classes are included in the bundle.
|
|||
|
||||
Here's the output for the _main_ bundle of an example app called `cli-quickstart`.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/deployment/quickstart-sourcemap-explorer.png" alt="quickstart sourcemap explorer">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
{@a base-tag}
|
||||
|
|
|
@ -9,8 +9,10 @@ conditionally show a message below the list.
|
|||
The final UI looks like this:
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/displaying-data/final.png" alt="Final UI">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
@ -103,8 +105,10 @@ inside the `<app-root>` tag.
|
|||
|
||||
Now run the app. It should display the title and hero name:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/displaying-data/title-and-hero.png" alt="Title and Hero">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -212,8 +216,10 @@ repeat items for any [iterable](https://developer.mozilla.org/en-US/docs/Web/Jav
|
|||
Now the heroes appear in an unordered list.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/displaying-data/hero-names-list.png" alt="After ngfor">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -183,8 +183,10 @@ Here are two sample components and the `AdComponent` interface for reference:
|
|||
## Final ad banner
|
||||
The final ad banner looks like this:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dynamic-component-loader/ads-example.gif" alt="Ads">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -197,8 +197,10 @@ Saving and retrieving the data is an exercise for another time.
|
|||
|
||||
The final form looks like this:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dynamic-form/dynamic-form.png" alt="Dynamic-Form">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -42,10 +42,10 @@ After you register your configured class with the browser's custom-element regis
|
|||
|
||||
When your custom element is placed on a page, the browser creates an instance of the registered class and adds it to the DOM. The content is provided by the component's template, which uses Angular template syntax, and is rendered using the component and DOM data. Input properties in the component correspond to input attributes for the element.
|
||||
|
||||
<figure>
|
||||
|
||||
<img src="generated/images/guide/elements/customElement1.png" alt="Custom element in browser" class="left">
|
||||
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/elements/customElement1.png" alt="Custom element in browser" class="left">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<hr class="clear">
|
||||
|
@ -64,10 +64,10 @@ Use a JavaScript function, `customElements.define()`, to register the configure
|
|||
and its associated custom-element tag with the browser's `CustomElementRegistry`.
|
||||
When the browser encounters the tag for the registered element, it uses the constructor to create a custom-element instance.
|
||||
|
||||
<figure>
|
||||
|
||||
<img src="generated/images/guide/elements/createElement.png" alt="Transform a component to a custom element" class="left">
|
||||
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/elements/createElement.png" alt="Transform a component to a custom element" class="left">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
### Mapping
|
||||
|
|
|
@ -103,8 +103,10 @@ Next, in the `AppComponent`, `app.component.html`, add the tag `<app-customer-da
|
|||
Now, in addition to the title that renders by default, the `CustomerDashboardComponent` template renders too:
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/feature-modules/feature-module.png" alt="feature module component">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<hr />
|
||||
|
|
|
@ -67,8 +67,10 @@ Here's a component with an input field for a single control implemented using re
|
|||
|
||||
The source of truth provides the value and status of the form element at a given point in time. In reactive forms, the form model is the source of truth. In the example above, the form model is the `FormControl` instance.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/forms-overview/key-diff-reactive-forms.png" alt="Reactive forms key differences">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
With reactive forms, the form model is explicitly defined in the component class. The reactive form directive (in this case, `FormControlDirective`) then links the existing `FormControl` instance to a specific form element in the view using a value accessor (`ControlValueAccessor` instance).
|
||||
|
@ -82,8 +84,10 @@ Here's the same component with an input field for a single control implemented u
|
|||
|
||||
In template-driven forms, the source of truth is the template.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/forms-overview/key-diff-td-forms.png" alt="Template-driven forms key differences">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The abstraction of the form model promotes simplicity over structure. The template-driven form directive `NgModel` is responsible for creating and managing the `FormControl` instance for a given form element. It's less explicit, but you no longer have direct control over the form model.
|
||||
|
@ -98,8 +102,10 @@ When building forms in Angular, it's important to understand how the framework h
|
|||
|
||||
As described above, in reactive forms each form element in the view is directly linked to a form model (`FormControl` instance). Updates from the view to the model and from the model to the view are synchronous and aren't dependent on the UI rendered. The diagrams below use the same favorite color example to demonstrate how data flows when an input field's value is changed from the view and then from the model.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/forms-overview/dataflow-reactive-forms-vtm.png" alt="Reactive forms data flow - view to model" width="100%">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The steps below outline the data flow from view to model.
|
||||
|
@ -110,8 +116,10 @@ The steps below outline the data flow from view to model.
|
|||
1. The `FormControl` instance emits the new value through the `valueChanges` observable.
|
||||
1. Any subscribers to the `valueChanges` observable receive the new value.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/forms-overview/dataflow-reactive-forms-mtv.png" alt="Reactive forms data flow - model to view" width="100%">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The steps below outline the data flow from model to view.
|
||||
|
@ -125,8 +133,10 @@ The steps below outline the data flow from model to view.
|
|||
|
||||
In template-driven forms, each form element is linked to a directive that manages the form model internally. The diagrams below use the same favorite color example to demonstrate how data flows when an input field's value is changed from the view and then from the model.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/forms-overview/dataflow-td-forms-vtm.png" alt="Template-driven forms data flow - view to model" width="100%">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The steps below outline the data flow from view to model when the input value changes from *Red* to *Blue*.
|
||||
|
@ -140,8 +150,10 @@ The steps below outline the data flow from view to model when the input value ch
|
|||
1. Because the component template uses two-way data binding for the `favoriteColor` property, the `favoriteColor` property in the component
|
||||
is updated to the value emitted by the `ngModelChange` event (*Blue*).
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/forms-overview/dataflow-td-forms-mtv.png" alt="Template-driven forms data flow - model to view" width="100%">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The steps below outline the data flow from model to view when the `favoriteColor` changes from *Blue* to *Red*.
|
||||
|
|
|
@ -45,8 +45,10 @@ otherwise wrestle with yourself.
|
|||
|
||||
You'll learn to build a template-driven form that looks like this:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/forms/hero-form-1.png" alt="Clean Form">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The *Hero Employment Agency* uses this form to maintain personal information about heroes.
|
||||
|
@ -56,8 +58,10 @@ Two of the three fields on this form are required. Required fields have a green
|
|||
|
||||
If you delete the hero name, the form displays a validation error in an attention-grabbing style:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/forms/hero-form-2.png" alt="Invalid, Name Required">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Note that the *Submit* button is disabled, and the "required" bar to the left of the input control changes from green to red.
|
||||
|
@ -272,8 +276,10 @@ you display its name using the interpolation syntax.
|
|||
|
||||
Running the app right now would be disappointing.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/forms/hero-form-3.png" alt="Early form with no binding">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -335,8 +341,10 @@ adding and deleting characters, you'd see them appear and disappear
|
|||
from the interpolated text.
|
||||
At some point it might look like this:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/forms/ng-model-in-action.png" alt="ngModel in action">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The diagnostic is evidence that values really are flowing from the input box to the model and
|
||||
|
@ -383,8 +391,10 @@ After revision, the core of the form should look like this:
|
|||
|
||||
If you run the app now and change every hero model property, the form might display like this:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/forms/ng-model-in-action-2.png" alt="ngModel in action">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The diagnostic near the top of the form
|
||||
|
@ -483,14 +493,18 @@ Follow these steps *precisely*:
|
|||
|
||||
The actions and effects are as follows:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/forms/control-state-transitions-anim.gif" alt="Control State Transition">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
You should see the following transitions and class names:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/forms/ng-control-class-changes.png" alt="Control state transitions">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The `ng-valid`/`ng-invalid` pair is the most interesting, because you want to send a
|
||||
|
@ -504,8 +518,10 @@ To create such visual feedback, add definitions for the `ng-*` CSS classes.
|
|||
You can mark required fields and invalid data at the same time with a colored bar
|
||||
on the left of the input box:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/forms/validity-required-indicator.png" alt="Invalid Form">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
You achieve this effect by adding these class definitions to a new `forms.css` file
|
||||
|
@ -525,8 +541,10 @@ Leverage the control's state to reveal a helpful message.
|
|||
|
||||
When the user deletes the name, the form should look like this:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/forms/name-required-error.png" alt="Name required">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
To achieve this effect, extend the `<input>` tag with the following:
|
||||
|
|
|
@ -111,8 +111,10 @@ directives in `CommonModule`; they don’t need to re-install app-wide providers
|
|||
If you do import `BrowserModule` into a lazy loaded feature module,
|
||||
Angular returns an error telling you to use `CommonModule` instead.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/frequent-ngmodules/browser-module-error.gif" width=750 alt="BrowserModule error">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<hr />
|
||||
|
|
|
@ -108,8 +108,10 @@ The following diagram represents the relationship between the
|
|||
`root` `ModuleInjector` and its parent injectors as the
|
||||
previous paragraphs describe.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection/injectors.svg" alt="NullInjector, ModuleInjector, root injector">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
While the name `root` is a special alias, other `ModuleInjector`s
|
||||
|
@ -1097,8 +1099,10 @@ Each tax return component has the following characteristics:
|
|||
* Has the ability to save the changes to its tax return or cancel them.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection/hid-heroes-anim.gif" alt="Heroes in action">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Suppose that the `HeroTaxReturnComponent` had logic to manage and restore changes.
|
||||
|
@ -1168,8 +1172,10 @@ that have special capabilities suitable for whatever is going on in component (B
|
|||
Component (B) is the parent of another component (C) that defines its own, even _more specialized_ provider for `CarService`.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection/car-components.png" alt="car components">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Behind the scenes, each component sets up its own injector with zero, one, or more providers defined for that component itself.
|
||||
|
@ -1179,8 +1185,10 @@ its injector produces an instance of `Car` resolved by injector (C) with an `Eng
|
|||
`Tires` resolved by the root injector (A).
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/dependency-injection/injector-tree.png" alt="car injector tree">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -25,8 +25,10 @@ contextual possibilities and hints as you type.
|
|||
This example shows autocomplete in an interpolation. As you type it out,
|
||||
you can hit tab to complete.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/language-service/language-completion.gif" alt="autocompletion">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
There are also completions within elements. Any elements you have as a component selector will
|
||||
|
@ -37,8 +39,10 @@ show up in the completion list.
|
|||
The Angular Language Service can forewarn you of mistakes in your code.
|
||||
In this example, Angular doesn't know what `orders` is or where it comes from.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/language-service/language-error.gif" alt="error checking">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
### Quick info and navigation
|
||||
|
@ -46,8 +50,10 @@ In this example, Angular doesn't know what `orders` is or where it comes from.
|
|||
The quick-info feature allows you to hover to see where components, directives, modules, and so on come from.
|
||||
You can then click "Go to definition" or press F12 to go directly to the definition.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/language-service/language-navigation.gif" alt="navigation">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -91,8 +91,10 @@ ng serve
|
|||
|
||||
Then go to `localhost:4200` where you should see “customer-app” and three buttons.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/lazy-loading-ngmodules/three-buttons.png" width="300" alt="three buttons in the browser">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
These buttons work, because the CLI automatically added the routes to the feature modules to the `routes` array in `app.module.ts`.
|
||||
|
@ -135,23 +137,29 @@ The other feature module's routing module is configured similarly.
|
|||
|
||||
You can check to see that a module is indeed being lazy loaded with the Chrome developer tools. In Chrome, open the dev tools by pressing `Cmd+Option+i` on a Mac or `Ctrl+Shift+j` on a PC and go to the Network Tab.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/lazy-loading-ngmodules/network-tab.png" width="600" alt="lazy loaded modules diagram">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
Click on the Orders or Customers button. If you see a chunk appear, everything is wired up properly and the feature module is being lazy loaded. A chunk should appear for Orders and for Customers but will only appear once for each.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/lazy-loading-ngmodules/chunk-arrow.png" width="600" alt="lazy loaded modules diagram">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
To see it again, or to test after working in the project, clear everything out by clicking the circle with a line through it in the upper left of the Network Tab:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/lazy-loading-ngmodules/clear.gif" width="200" alt="lazy loaded modules diagram">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -291,8 +291,10 @@ The peek-a-boo exists to show how Angular calls the hooks in the expected order.
|
|||
|
||||
This snapshot reflects the state of the log after the user clicked the *Create...* button and then the *Destroy...* button.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/lifecycle-hooks/peek-a-boo.png" alt="Peek-a-boo">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The sequence of log messages follows the prescribed hook calling order:
|
||||
|
@ -349,8 +351,10 @@ Here it is attached to the repeated hero `<div>`:
|
|||
Each spy's birth and death marks the birth and death of the attached hero `<div>`
|
||||
with an entry in the *Hook Log* as seen here:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/lifecycle-hooks/spy-directive.gif' alt="Spy Directive">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Adding a hero results in a new hero `<div>`. The spy's `ngOnInit()` logs that event.
|
||||
|
@ -440,8 +444,10 @@ The host `OnChangesParentComponent` binds to them like this:
|
|||
|
||||
Here's the sample in action as the user makes changes.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/lifecycle-hooks/on-changes-anim.gif' alt="OnChanges">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The log entries appear as the string value of the *power* property changes.
|
||||
|
@ -473,8 +479,10 @@ This code inspects certain _values of interest_, capturing and comparing their c
|
|||
It writes a special message to the log when there are no substantive changes to the `hero` or the `power`
|
||||
so you can see how often `DoCheck` is called. The results are illuminating:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/lifecycle-hooks/do-check-anim.gif' alt="DoCheck">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
While the `ngDoCheck()` hook can detect when the hero's `name` has changed, it has a frightful cost.
|
||||
|
@ -527,8 +535,10 @@ for one turn of the browser's JavaScript cycle and that's just long enough.
|
|||
|
||||
Here's *AfterView* in action:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/lifecycle-hooks/after-view-anim.gif' alt="AfterView">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Notice that Angular frequently calls `AfterViewChecked()`, often when there are no changes of interest.
|
||||
|
@ -572,8 +582,10 @@ The `<ng-content>` tag is a *placeholder* for the external content.
|
|||
It tells Angular where to insert that content.
|
||||
In this case, the projected content is the `<app-child>` from the parent.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/lifecycle-hooks/projected-child-view.png' alt="Projected Content">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
|
|
@ -107,8 +107,10 @@ As you click the button, the displayed date alternates between
|
|||
"**<samp>Friday, April 15, 1988</samp>**".
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/pipes/date-format-toggle-anim.gif' alt="Date Format Toggle">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -186,8 +188,10 @@ Now you need a component to demonstrate the pipe.
|
|||
|
||||
<code-example path="pipes/src/app/power-booster.component.ts" header="src/app/power-booster.component.ts"></code-example>
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/pipes/power-booster.png' alt="Power Booster">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -230,8 +234,10 @@ your pipe and two-way data binding with `ngModel`.
|
|||
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/pipes/power-boost-calculator-anim.gif' alt="Power Boost Calculator">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -307,8 +313,10 @@ The Flying Heroes application extends the
|
|||
code with checkbox switches and additional displays to help you experience these effects.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/pipes/flying-heroes-anim.gif' alt="Flying Heroes">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -486,8 +494,10 @@ both requesting the heroes from the `heroes.json` file.
|
|||
The component renders as the following:
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/pipes/hero-list.png' alt="Hero List">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -64,8 +64,10 @@ The form control assigned to `name` is displayed when the component is added to
|
|||
|
||||
<code-example path="reactive-forms/src/app/app.component.1.html" region="app-name-editor" header="src/app/app.component.html (name editor)"></code-example>
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/reactive-forms/name-editor-1.png" alt="Name Editor">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
## Managing control values
|
||||
|
@ -108,8 +110,10 @@ Update the template with a button to simulate a name update. When you click the
|
|||
|
||||
The form model is the source of truth for the control, so when you click the button, the value of the input is changed within the component class, overriding its current value.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/reactive-forms/name-editor-2.png" alt="Name Editor Update">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
@ -188,8 +192,10 @@ To display the `ProfileEditor` component that contains the form, add it to a com
|
|||
|
||||
`ProfileEditor` allows you to manage the form control instances for the `firstName` and `lastName` controls within the form group instance.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/reactive-forms/profile-editor-1.png" alt="Profile Editor">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
## Creating nested form groups
|
||||
|
@ -214,8 +220,10 @@ Add the `address` form group containing the `street`, `city`, `state`, and `zip`
|
|||
|
||||
The `ProfileEditor` form is displayed as one group, but the model is broken down further to represent the logical grouping areas.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/reactive-forms/profile-editor-2.png" alt="Profile Editor Update">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
@ -346,8 +354,10 @@ Display the current status of `profileForm` using interpolation.
|
|||
|
||||
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="display-status" header="src/app/profile-editor/profile-editor.component.html (display status)"></code-example>
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/reactive-forms/profile-editor-3.png" alt="Profile Editor Validation">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The **Submit** button is disabled because `profileForm` is invalid due to the required `firstName` form control. After you fill out the `firstName` input, the form becomes valid and the **Submit** button is enabled.
|
||||
|
@ -412,8 +422,10 @@ Add the template HTML below after the `<div>` closing the `formGroupName` elemen
|
|||
|
||||
The `*ngFor` directive iterates over each form control instance provided by the aliases form array instance. Because form array elements are unnamed, you assign the index to the `i` variable and pass it to each control to bind it to the `formControlName` input.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/reactive-forms/profile-editor-4.png" alt="Profile Editor Aliases">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Each time a new alias instance is added, the new form array instance is provided its control based on the index. This allows you to track each individual control when calculating the status and value of the root control.
|
||||
|
|
|
@ -25,8 +25,10 @@ Let's illustrate a router transition animation by navigating between two routes,
|
|||
|
||||
</br>
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/animations/route-animation.gif" alt="Animations in action" width="440">
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/animations/route-animation.gif" alt="Animations in action" width="440">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
## Route configuration
|
||||
|
|
|
@ -765,16 +765,20 @@ Once the app warms up, you'll see a row of navigation buttons
|
|||
and the *Heroes* view with its list of heroes.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/router/hero-list.png' alt="Hero List">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
||||
Select one hero and the app takes you to a hero editing screen.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/router/hero-detail.png' alt="Crisis Center Detail">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -790,8 +794,10 @@ Angular app navigation updates the browser history as normal web navigation does
|
|||
Now click the *Crisis Center* link for a list of ongoing crises.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/router/crisis-center-list.png' alt="Crisis Center List">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -803,8 +809,10 @@ Alter the name of a crisis.
|
|||
Notice that the corresponding name in the crisis list does _not_ change.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/router/crisis-center-detail.png' alt="Crisis Center Detail">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -819,8 +827,10 @@ Click the browser back button or the "Heroes" link instead.
|
|||
Up pops a dialog box.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/router/confirm-dialog.png' alt="Confirm Dialog">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -842,8 +852,10 @@ Proceed to the first application milestone.
|
|||
Begin with a simple version of the app that navigates between two empty views.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/router/router-1-anim.gif' alt="App in action">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
{@a import}
|
||||
|
@ -928,8 +940,10 @@ Registering the `RouterModule.forRoot()` in the `AppModule` imports makes the `R
|
|||
The root `AppComponent` is the application shell. It has a title, a navigation bar with two links, and a router outlet where the router swaps components on and off the page. Here's what you get:
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/router/shell-and-outlet.png' alt="Shell">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The router outlet serves as a placeholder when the routed components will be rendered below it.
|
||||
|
@ -1363,8 +1377,10 @@ from the <live-example name="toh-pt4" title="Tour of Heroes: Services example co
|
|||
Here's how the user will experience this version of the app:
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/router/router-2-anim.gif' alt="App in action">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -1944,8 +1960,10 @@ For example, when returning to the hero-detail.component.ts list from the hero d
|
|||
it would be nice if the viewed hero was preselected in the list.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/router/selected-hero.png' alt="Selected hero">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -2129,8 +2147,10 @@ Add some styles to apply when the list item is selected.
|
|||
|
||||
When the user navigates from the heroes list to the "Magneta" hero and back, "Magneta" appears selected:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/router/selected-hero.png' alt="Selected List">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -2523,8 +2543,10 @@ to conform to the following recommended pattern for Angular applications:
|
|||
If your app had many feature areas, the app component trees might look like this:
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/router/component-tree.png' alt="Component Tree">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -2789,8 +2811,10 @@ It displays a simple form with a header, an input box for the message,
|
|||
and two buttons, "Send" and "Cancel".
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/router/contact-popup.png' alt="Contact popup">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -359,8 +359,10 @@ When you add a new named schematic to this collection, it is automatically added
|
|||
In addition to the name and description, each schematic has a `factory` property that identifies the schematic’s entry point.
|
||||
In the example, you invoke the schematic's defined functionality by calling the `helloWorld()` function in the main file, `hello-world/index.ts`.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/schematics/collection-files.gif" alt="overview">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Each named schematic in the collection has the following main parts.
|
||||
|
|
|
@ -118,8 +118,10 @@ Angular recognizes the value as unsafe and automatically sanitizes it, which rem
|
|||
tag but keeps safe content such as the `<b>` element.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/security/binding-inner-html.png' alt='A screenshot showing interpolated and bound HTML values'>
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -209,8 +211,10 @@ this, mark the URL value as a trusted URL using the `bypassSecurityTrustUrl` cal
|
|||
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/security/bypass-security-component.png' alt='A screenshot showing an alert box created from a trusted URL'>
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -74,8 +74,10 @@ To simulate a network issue, disable network interaction for your application. I
|
|||
2. Go to the **Network tab**.
|
||||
3. Check the **Offline box**.
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/service-worker/offline-checkbox.png" alt="The offline checkbox in the Network tab is checked">
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/service-worker/offline-checkbox.png" alt="The offline checkbox in the Network tab pis checked">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Now the app has no access to network interaction.
|
||||
|
@ -86,8 +88,10 @@ With the addition of an Angular service worker, the application behavior changes
|
|||
|
||||
If you look at the Network tab, you can verify that the service worker is active.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/service-worker/sw-active.png" alt="Requests are marked as from ServiceWorker">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Notice that under the "Size" column, the requests state is `(from ServiceWorker)`. This means that the resources are not being loaded from the network. Instead, they are being loaded from the service worker's cache.
|
||||
|
@ -142,8 +146,10 @@ Now look at how the browser and service worker handle the updated application.
|
|||
|
||||
1. Open http://localhost:8080 again in the same window. What happens?
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/service-worker/welcome-msg-en.png" alt="It still says Welcome to Service Workers!">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
What went wrong? Nothing, actually. The Angular service worker is doing its job and serving the version of the application that it has **installed**, even though there is an update available. In the interest of speed, the service worker doesn't wait to check for updates before it serves the application that it has cached.
|
||||
|
@ -152,8 +158,10 @@ If you look at the `http-server` logs, you can see the service worker requesting
|
|||
|
||||
2. Refresh the page.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/service-worker/welcome-msg-fr.png" alt="The text has changed to say Bienvenue à app!">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The service worker installed the updated version of your app *in the background*, and the next time the page is loaded or reloaded, the service worker switches to the latest version.
|
||||
|
|
|
@ -47,8 +47,10 @@ You can inject the `Title` service into the root `AppComponent` and expose a bin
|
|||
|
||||
Bind that method to three anchor tags and voilà!
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/set-document-title/set-title-anim.gif" alt="Set title">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Here's the complete solution:
|
||||
|
|
|
@ -104,8 +104,10 @@ to `http://localhost:4200/`.
|
|||
Your app greets you with a message:
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/setup-local/app-works.png' alt="Welcome to my-app!">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -125,8 +125,10 @@ The `ngIf` directive doesn't hide elements with CSS. It adds and removes them ph
|
|||
Confirm that fact using browser developer tools to inspect the DOM.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/structural-directives/element-not-in-dom.png' alt="ngIf=false element not in DOM">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -151,8 +153,10 @@ A directive could hide the unwanted paragraph instead by setting its `display` s
|
|||
While invisible, the element remains in the DOM.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/structural-directives/element-display-in-dom.png' alt="hidden element still in DOM">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -211,8 +215,10 @@ Internally, Angular translates the `*ngIf` _attribute_ into a `<ng-template>` _e
|
|||
The first form is not actually rendered, only the finished product ends up in the DOM.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/structural-directives/hero-div-in-dom.png' alt="hero div in DOM">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -559,8 +565,10 @@ That's the fate of the middle "Hip!" in the phrase "Hip! Hip! Hooray!".
|
|||
Angular erases the middle "Hip!", leaving the cheer a bit less enthusiastic.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/structural-directives/template-rendering.png' alt="template tag rendering">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -617,8 +625,10 @@ You also have a CSS style rule that happens to apply to a `<span>` within a `<p>
|
|||
The constructed paragraph renders strangely.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/structural-directives/bad-paragraph.png' alt="spanned paragraph with bad style">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -639,8 +649,10 @@ When you try this,
|
|||
the drop down is empty.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/structural-directives/bad-select.png' alt="spanned options don't work">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -662,8 +674,10 @@ Here's the conditional paragraph again, this time using `<ng-container>`.
|
|||
It renders properly.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/structural-directives/good-paragraph.png' alt="ngcontainer paragraph with proper style">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -678,8 +692,10 @@ Now conditionally exclude a _select_ `<option>` with `<ng-container>`.
|
|||
The drop down works properly.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/structural-directives/select-ngcontainer-anim.gif' alt="ngcontainer options work properly">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
@ -828,8 +844,10 @@ When the `condition` is falsy, the top (A) paragraph appears and the bottom (B)
|
|||
When the `condition` is truthy, the top (A) paragraph is removed and the bottom (B) paragraph appears.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/structural-directives/unless-anim.gif' alt="UnlessDirective in action">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -969,8 +969,10 @@ template statement on the right.
|
|||
The following event binding listens for the button's click events, calling
|
||||
the component's `onSave()` method whenever a click occurs:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/template-syntax/syntax-diagram.svg' alt="Syntax diagram">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
### Target event
|
||||
|
@ -1306,8 +1308,10 @@ for example, the following changes the `<input>` value to uppercase:
|
|||
|
||||
Here are all variations in action, including the uppercase version:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/built-in-directives/ng-model-anim.gif' alt="NgModel variations">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<hr/>
|
||||
|
@ -1512,8 +1516,10 @@ Here is an illustration of the `trackBy` effect.
|
|||
* With no `trackBy`, both buttons trigger complete DOM element replacement.
|
||||
* With `trackBy`, only changing the `id` triggers element replacement.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/built-in-directives/ngfor-trackby.gif" alt="Animation of trackBy">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -1538,8 +1544,10 @@ Angular puts only the selected element into the DOM.
|
|||
|
||||
<code-example path="built-in-directives/src/app/app.component.html" region="NgSwitch" header="src/app/app.component.html"></code-example>
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/built-in-directives/ngswitch.gif" alt="Animation of NgSwitch">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
`NgSwitch` is the controller directive. Bind it to an expression that returns
|
||||
|
@ -1695,8 +1703,10 @@ child component. So an `@Input()` allows data to be input _into_ the
|
|||
child component from the parent component.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/inputs-outputs/input.svg" alt="Input data flow diagram">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
To illustrate the use of `@Input()`, edit these parts of your app:
|
||||
|
@ -1742,8 +1752,10 @@ With `@Input()`, Angular passes the value for `currentItem` to the child so that
|
|||
|
||||
The following diagram shows this structure:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/inputs-outputs/input-diagram-target-source.svg" alt="Property binding diagram">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The target in the square brackets, `[]`, is the property you decorate
|
||||
|
@ -1776,8 +1788,10 @@ the child _out_ to the parent.
|
|||
An `@Output()` property should normally be initialized to an Angular [`EventEmitter`](api/core/EventEmitter) with values flowing out of the component as [events](#event-binding).
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/inputs-outputs/output.svg" alt="Output diagram">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Just like with `@Input()`, you can use `@Output()`
|
||||
|
@ -1918,8 +1932,10 @@ The target, `item`, which is an `@Input()` property in the child component class
|
|||
The following diagram is of an `@Input()` and an `@Output()` on the same
|
||||
child component and shows the different parts of each:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/inputs-outputs/input-output-diagram.svg" alt="Input/Output diagram">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
As the diagram shows, use inputs and outputs together in the same manner as using them separately. Here, the child selector is `<app-input-output>` with `item` and `deleteRequest` being `@Input()` and `@Output()`
|
||||
|
|
|
@ -41,8 +41,10 @@ It shows that Karma ran three tests that all passed.
|
|||
|
||||
A chrome browser also opens and displays the test output in the "Jasmine HTML Reporter" like this.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/testing/initial-jasmine-html-reporter.png' alt="Jasmine HTML Reporter in the browser">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Most people find this browser output easier to read than the console log.
|
||||
|
@ -2260,8 +2262,10 @@ tests with the `RouterTestingModule`.
|
|||
|
||||
The `HeroDetailComponent` is a simple view with a title, two hero fields, and two buttons.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/testing/hero-detail.component.png' alt="HeroDetailComponent in action">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
But there's plenty of template complexity even in this simple form.
|
||||
|
@ -2689,8 +2693,10 @@ A better solution is to create an artificial test component that demonstrates al
|
|||
|
||||
<code-example path="testing/src/app/shared/highlight.directive.spec.ts" region="test-component" header="app/shared/highlight.directive.spec.ts (TestComponent)"></code-example>
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/testing/highlight-directive-spec.png' alt="HighlightDirective spec in action">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
@ -2770,8 +2776,10 @@ Debug specs in the browser in the same way that you debug an application.
|
|||
1. Set a breakpoint in the test.
|
||||
1. Refresh the browser, and it stops at the breakpoint.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/testing/karma-1st-spec-debug.png' alt="Karma debugging">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<hr>
|
||||
|
|
|
@ -14,8 +14,10 @@ An asterisk `*` or *wildcard* matches any animation state. This is useful for de
|
|||
|
||||
For example, a transition of `open => *` applies when the element's state changes from open to anything else.
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/animations/wildcard-state-500.png" alt="wildcard state expressions">
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/animations/wildcard-state-500.png" alt="wildcard state expressions">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Here's another code sample using the wildcard state together with our previous example using the `open` and `closed` states. Instead of defining each state-to-state transition pair, we're now saying that any transition to `closed` takes 1 second, and any transition to `open` takes 0.5 seconds.
|
||||
|
@ -32,8 +34,10 @@ Use a double arrow syntax to specify state-to-state transitions in both directio
|
|||
|
||||
In our two-state button example, the wildcard isn't that useful because there are only two possible states, `open` and `closed`. Wildcard states are better when an element in one particular state has multiple potential states that it can change to. If our button can change from `open` to either `closed` or something like `inProgress`, using a wildcard state could reduce the amount of coding needed.
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/animations/wildcard-3-states.png" alt="wildcard state with 3 states">
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/animations/wildcard-3-states.png" alt="wildcard state with 3 states">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -217,8 +221,10 @@ In the previous section, we saw a simple two-state transition. Now we'll create
|
|||
|
||||
Angular's `keyframe()` function is similar to keyframes in CSS. Keyframes allow several style changes within a single timing segment. For example, our button, instead of fading, could change color several times over a single 2-second timespan.
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/animations/keyframes-500.png" alt="keyframes">
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/animations/keyframes-500.png" alt="keyframes">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The code for this color change might look like this.
|
||||
|
@ -231,8 +237,10 @@ Keyframes include an *offset* that defines the point in the animation where each
|
|||
|
||||
Defining offsets for keyframes is optional. If you omit them, evenly spaced offsets are automatically assigned. For example, three keyframes without predefined offsets receive offsets of 0, 0.5, and 1. Specifying an offset of 0.8 for the middle transition in the above example might look like this.
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/animations/keyframes-offset-500.png" alt="keyframes with offset">
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/animations/keyframes-offset-500.png" alt="keyframes with offset">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The code with offsets specified would be as follows.
|
||||
|
@ -252,8 +260,10 @@ Here's an example of using keyframes to create a pulse effect:
|
|||
|
||||
* A keyframes sequence inserted in the middle that causes the button to appear to pulsate irregularly over the course of that same 1-second timeframe
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/animations/keyframes-pulsation.png" alt="keyframes with irregular pulsation">
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/animations/keyframes-pulsation.png" alt="keyframes with irregular pulsation">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The code snippet for this animation might look like this.
|
||||
|
|
|
@ -266,8 +266,10 @@ everything work seamlessly:
|
|||
When you register a downgraded service, you must explicitly specify a *string token* that you want to
|
||||
use in AngularJS.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/upgrade/injectors.png" alt="The two injectors in a hybrid application">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
#### Components and the DOM
|
||||
|
@ -302,8 +304,10 @@ ways:
|
|||
bridges the related concepts of AngularJS transclusion and Angular content
|
||||
projection together.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/upgrade/dom.png" alt="DOM element ownership in a hybrid application">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Whenever you use a component that belongs to the other framework, a
|
||||
|
@ -347,8 +351,10 @@ AngularJS and Angular approaches. Here's what happens:
|
|||
every turn of the Angular zone. This also triggers AngularJS change
|
||||
detection after every event.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/upgrade/change_detection.png" alt="Change detection in a hybrid application">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
In practice, you do not need to call `$apply()`,
|
||||
|
|
|
@ -82,8 +82,10 @@ Here's what the UI displays:
|
|||
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/user-input/keyup1-anim.gif' alt="key up 1">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -161,8 +163,10 @@ and the component does nothing.
|
|||
Type something in the input box, and watch the display update with each keystroke.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/user-input/keyup-loop-back-anim.gif' alt="loop back">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -211,8 +215,10 @@ Then Angular calls the event handler only when the user presses _Enter_.
|
|||
|
||||
Here's how it works.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/user-input/keyup3-anim.gif' alt="key up 3">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -243,8 +249,10 @@ The user can add a hero by typing the hero's name in the input box and
|
|||
clicking **Add**.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/user-input/little-tour-anim.gif' alt="Little Tour of Heroes">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -105,14 +105,18 @@ When the "Buy" button is clicked, you'll use the cart service to add the current
|
|||
|
||||
1. To see the new "Buy" button, refresh the application and click on a product's name to display its details.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/start/product-details-buy.png' alt="Display details for selected product with a Buy button">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
1. Click the "Buy" button. The product is added to the stored list of items in the cart, and a message is displayed.
|
||||
1. Click the "Buy" button. The product is added to the stored list of items in the cart, and a message is displayed.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/start/buy-alert.png' alt="Display details for selected product with a Buy button">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -150,8 +154,10 @@ We'll create the cart page in two steps:
|
|||
|
||||
(Note: The "Checkout" button that we provided in the top-bar component was already configured with a `routerLink` for `/cart`.)
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/start/cart-works.png' alt="Display cart page before customizing">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -204,8 +210,10 @@ Services can be used to share data across components:
|
|||
1. Click "Checkout" to see the cart.
|
||||
1. To add another product, click "My Store" to return to the product list. Repeat the steps above.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/start/cart-page-full.png' alt="Cart page with products added">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -363,14 +371,18 @@ Now that your app can retrieve shipping data, you'll create a shipping component
|
|||
|
||||
Click on the "Checkout" button to see the updated cart. (Remember that changing the app causes the preview to refresh, which empties the cart.)
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/start/cart-empty-with-shipping-prices.png' alt="Cart with link to shipping prices">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Click on the link to navigate to the shipping prices.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/start/shipping-prices.png' alt="Display shipping prices">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -73,8 +73,10 @@ Next, you'll add a checkout form at the bottom of the "Cart" page.
|
|||
|
||||
After putting a few items in the cart, users can now review their items, enter name and address, and submit their purchase:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/start/cart-with-items-and-form.png' alt="Cart page with checkout form">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -34,8 +34,10 @@ bar—containing the store name and
|
|||
checkout icon—and the title for a product list.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/start/new-app.png" alt="Starter online store app">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -96,8 +98,10 @@ file `product-list.component.html`.
|
|||
|
||||
The preview pane immediately updates to display the name of each product in the list.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/start/template-syntax-product-names.png" alt="Product names added to list">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
1. To make each product name a link to product details, add the `<a>` element and set its title to be the product's name by using the property binding `[ ]` syntax, as follows:
|
||||
|
@ -112,8 +116,10 @@ file `product-list.component.html`.
|
|||
property value as text; property binding `[ ]` lets you
|
||||
use the property value in a template expression.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/start/template-syntax-product-anchor.png" alt="Product name anchor text is product name property">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -124,8 +130,10 @@ file `product-list.component.html`.
|
|||
|
||||
The app now displays the name and description of each product in the list. Notice that the final product does not have a description paragraph. Because the product's description property is empty, Angular doesn't create the `<p>` element—including the word "Description".
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/start/template-syntax-product-description.png" alt="Product descriptions added to list">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
1. Add a button so users can share a product with friends. Bind the button's `click` event to the `share()` method (in `product-list.component.ts`). Event binding uses a set of parentheses, `( )`, around the event, as in the following `<button>` element:
|
||||
|
@ -135,14 +143,18 @@ file `product-list.component.html`.
|
|||
|
||||
Each product now has a "Share" button:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/start/template-syntax-product-share-button.png" alt="Share button added for each product">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Test the "Share" button:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/start/template-syntax-product-share-alert.png" alt="Alert box indicating product has been shared">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The app now has a product list and sharing feature.
|
||||
|
@ -198,8 +210,10 @@ An Angular application comprises a tree of components, in which each Angular com
|
|||
|
||||
Currently, the example app has three components:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/start/app-components.png" alt="Online store with three components">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
* `app-root` (orange box) is the application shell. This is the first component to load and the parent of all other components. You can think of it as the base page.
|
||||
|
@ -228,8 +242,10 @@ The next step is to create a new alert feature that takes a product as an input.
|
|||
|
||||
1. Right click on the `app` folder and use the `Angular Generator` to generate a new component named `product-alerts`.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/start/generate-component.png" alt="StackBlitz command to generate component">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
The generator creates starter files for all three parts of the component:
|
||||
|
@ -277,11 +293,12 @@ The next step is to create a new alert feature that takes a product as an input.
|
|||
|
||||
The new product alert component takes a product as input from the product list. With that input, it shows or hides the "Notify Me" button, based on the price of the product. The Phone XL price is over $700, so the "Notify Me" button appears on that product.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/start/product-alert-button.png" alt="Product alert button added to products over $700">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
See [Component Interaction](guide/component-interaction "Components & Templates > Component Interaction") for more information about passing data from a parent to child component, intercepting and acting upon a value from the parent, and detecting and acting on changes to input property values.
|
||||
|
@ -323,8 +340,10 @@ To make the "Notify Me" button work, you need to configure two things:
|
|||
|
||||
1. Try the "Notify Me" button:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/start/product-alert-notification.png" alt="Product alert notification confirmation dialog">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -54,8 +54,10 @@ The app is already set up to use the Angular router and to use routing to naviga
|
|||
|
||||
Notice that the URL in the preview window changes. The final segment is `products/1`.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/start/product-details-works.png" alt="Product details page with updated URL">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
@ -108,8 +110,10 @@ The product details component handles the display of each product. The Angular R
|
|||
|
||||
Now, when the user clicks on a name in the product list, the router navigates you to the distinct URL for the product, swaps out the product list component for the product details component, and displays the product details.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src="generated/images/guide/start/product-details-routed.png" alt="Product details page with updated URL and full details displayed">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
||||
|
|
|
@ -49,8 +49,10 @@ After completing all tutorial steps, the final app will look like this: <live-ex
|
|||
Here's a visual idea of where this tutorial leads, beginning with the "Dashboard"
|
||||
view and the most heroic heroes:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/toh/heroes-dashboard-1.png' alt="Output of heroes dashboard">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
You can click the two links above the dashboard ("Dashboard" and "Heroes")
|
||||
|
@ -59,8 +61,10 @@ to navigate between this Dashboard view and a Heroes view.
|
|||
If you click the dashboard hero "Magneta," the router opens a "Hero Details" view
|
||||
where you can change the hero's name.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/toh/hero-details-1.png' alt="Details of hero in app">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Clicking the "Back" button returns you to the Dashboard.
|
||||
|
@ -68,8 +72,10 @@ Links at the top take you to either of the main views.
|
|||
If you click "Heroes," the app displays the "Heroes" master list view.
|
||||
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/toh/heroes-list-2.png' alt="Output of heroes list app">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
When you click a different hero name, the read-only mini detail beneath the list reflects the new choice.
|
||||
|
@ -79,12 +85,16 @@ editable details of the selected hero.
|
|||
|
||||
The following diagram captures all of the navigation options.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/toh/nav-diagram.png' alt="View navigations">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
Here's the app in action:
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/toh/toh-anim.gif' alt="Tour of Heroes in Action">
|
||||
</div>
|
||||
</figure>
|
||||
|
|
|
@ -196,10 +196,10 @@ It's difficult to identify the _selected hero_ in the list when all `<li>` eleme
|
|||
|
||||
If the user clicks "Magneta", that hero should render with a distinctive but subtle background color like this:
|
||||
|
||||
<figure>
|
||||
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/toh/heroes-list-selected.png' alt="Selected hero">
|
||||
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
That _selected hero_ coloring is the work of the `.selected` CSS class in the [styles you added earlier](#styles).
|
||||
|
|
|
@ -9,10 +9,10 @@ There are new requirements for the Tour of Heroes app:
|
|||
|
||||
When you’re done, users will be able to navigate the app like this:
|
||||
|
||||
<figure>
|
||||
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/toh/nav-diagram.png' alt="View navigations">
|
||||
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
## Add the `AppRoutingModule`
|
||||
|
|
|
@ -513,8 +513,10 @@ That's the job of the [`AsyncPipe`](#asyncpipe) in the template.
|
|||
Run the app again. In the *Dashboard*, enter some text in the search box.
|
||||
If you enter characters that match any existing hero names, you'll see something like this.
|
||||
|
||||
<figure>
|
||||
<figure class="lightbox">
|
||||
<div class="card">
|
||||
<img src='generated/images/guide/toh/toh-hero-search.png' alt="Hero Search Component">
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
## Final code review
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
@media (max-width: 1300px) {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
|
@ -40,7 +41,8 @@
|
|||
border: 1px solid $lightgray;
|
||||
padding: 32px;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
box-shadow: 2px 2px 5px 0 rgba(0, 0, 0, .2);
|
||||
margin: 16px 0;
|
||||
|
||||
|
@ -56,6 +58,11 @@
|
|||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
background-color: $white;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue