docs: edit inputs-outputs copy and headers (#39119)

PR Close #39119
This commit is contained in:
Kapunahele Wong 2020-10-05 17:05:28 -04:00 committed by atscott
parent eea5d6b38f
commit 3f66a84e01
3 changed files with 86 additions and 227 deletions

View File

@ -1,8 +1,7 @@
# `@Input()` and `@Output()` properties # Sharing data between child and parent directives and components
`@Input()` and `@Output()` allow Angular to share data between the parent context A common pattern in Angular is sharing data between a parent component and one or more child components.
and child directives or components. An `@Input()` property is writable You can implement this pattern by using the `@Input()` and `@Output()` directives.
while an `@Output()` property is observable.
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -10,7 +9,7 @@ See the <live-example></live-example> for a working example containing the code
</div> </div>
Consider this example of a child/parent relationship: Consider the following hierarchy:
```html ```html
<parent-component> <parent-component>
@ -19,80 +18,52 @@ Consider this example of a child/parent relationship:
``` ```
Here, the `<child-component>` selector, or child directive, is embedded The `<parent-component>` serves as the context for the `<child-component>`.
within a `<parent-component>`, which serves as the child's context.
`@Input()` and `@Output()` act as `@Input()` and `@Output()` give a child component a way to communicate with its parent component.
the API, or application programming interface, of the child `@Input()` allows a parent component to update data in the child component.
component in that they allow the child to Conversely, `@Output() allows the child to send data to a parent component.
communicate with the parent. Think of `@Input()` and `@Output()` like ports
or doorways&mdash;`@Input()` is the doorway into the component allowing data
to flow in while `@Output()` is the doorway out of the component, allowing the
child component to send data out.
<div class="alert is-helpful">
#### `@Input()` and `@Output()` are independent
Though `@Input()` and `@Output()` often appear together in apps, you can use
them separately. If the nested
component is such that it only needs to send data to its parent, you wouldn't
need an `@Input()`, only an `@Output()`. The reverse is also true in that if the
child only needs to receive data from the parent, you'd only need `@Input()`.
</div>
{@a input} {@a input}
## How to use `@Input()` ## Sending data to a child component
Use the `@Input()` decorator in a child component or directive to let Angular know
that a property in that component can receive its value from its parent component.
It helps to remember that the data flow is from the perspective of the
child component. So an `@Input()` allows data to be input _into_ the
child component from the parent component.
The `@Input()` decorator in a child component or directive signifies that the property can receive its value from its parent component.
<div class="lightbox"> <div class="lightbox">
<img src="generated/images/guide/inputs-outputs/input.svg" alt="Input data flow diagram"> <img src="generated/images/guide/inputs-outputs/input.svg" alt="Input data flow diagram">
</div> </div>
To illustrate the use of `@Input()`, edit these parts of your app: To use `@Input()`, you must configure the parent and child.
* The child component class and template ### Configuring the child component
* The parent component class and template
To use the `@Input()` decorator in a child component class, first import `Input` and then decorate the property with `@Input()`, as in the following example.
### In the child
To use the `@Input()` decorator in a child component class, first import
`Input` and then decorate the property with `@Input()`:
<code-example path="inputs-outputs/src/app/item-detail/item-detail.component.ts" region="use-input" header="src/app/item-detail/item-detail.component.ts"></code-example> <code-example path="inputs-outputs/src/app/item-detail/item-detail.component.ts" region="use-input" header="src/app/item-detail/item-detail.component.ts"></code-example>
In this case, `@Input()` decorates the property <code class="no-auto-link">item</code>, which has In this case, `@Input()` decorates the property <code class="no-auto-link">item</code>, which has a type of `string`, however, `@Input()` properties can have any type, such as `number`, `string`, `boolean`, or `object`.
a type of `string`, however, `@Input()` properties can have any type, such as The value for `item` comes from the parent component.
`number`, `string`, `boolean`, or `object`. The value for `item` will come from the parent component, which the next section covers.
Next, in the child component template, add the following: Next, in the child component template, add the following:
<code-example path="inputs-outputs/src/app/item-detail/item-detail.component.html" region="property-in-template" header="src/app/item-detail/item-detail.component.html"></code-example> <code-example path="inputs-outputs/src/app/item-detail/item-detail.component.html" region="property-in-template" header="src/app/item-detail/item-detail.component.html"></code-example>
### Configuring the parent component
### In the parent
The next step is to bind the property in the parent component's template. The next step is to bind the property in the parent component's template.
In this example, the parent component template is `app.component.html`. In this example, the parent component template is `app.component.html`.
First, use the child's selector, here `<app-item-detail>`, as a directive within the 1. Use the child's selector, here `<app-item-detail>`, as a directive within the
parent component template. Then, use [property binding](guide/property-binding) parent component template.
to bind the property in the child to the property of the parent.
2. Use [property binding](guide/property-binding) to bind the `item` property in the child to the `currentItem` property of the parent.
<code-example path="inputs-outputs/src/app/app.component.html" region="input-parent" header="src/app/app.component.html"></code-example> <code-example path="inputs-outputs/src/app/app.component.html" region="input-parent" header="src/app/app.component.html"></code-example>
Next, in the parent component class, `app.component.ts`, designate a value for `currentItem`: 3. In the parent component class, designate a value for `currentItem`:
<code-example path="inputs-outputs/src/app/app.component.ts" region="parent-property" header="src/app/app.component.ts"></code-example> <code-example path="inputs-outputs/src/app/app.component.ts" region="parent-property" header="src/app/app.component.ts"></code-example>
@ -104,239 +75,127 @@ The following diagram shows this structure:
<img src="generated/images/guide/inputs-outputs/input-diagram-target-source.svg" alt="Property binding diagram"> <img src="generated/images/guide/inputs-outputs/input-diagram-target-source.svg" alt="Property binding diagram">
</div> </div>
The target in the square brackets, `[]`, is the property you decorate The target in the square brackets, `[]`, is the property you decorate with `@Input()` in the child component.
with `@Input()` in the child component. The binding source, the part The binding source, the part to the right of the equal sign, is the data that the parent component passes to the nested component.
to the right of the equal sign, is the data that the parent
component passes to the nested component.
The key takeaway is that when binding to a child component's property in a parent component&mdash;that is, what's ### Watching for `@Input()` changes
in square brackets&mdash;you must
decorate the property with `@Input()` in the child component.
<div class="alert is-helpful"> To watch for changes on an `@Input()` property, you can use `OnChanges`, one of Angular's [lifecycle hooks](guide/lifecycle-hooks).
See the [`OnChanges`](guide/lifecycle-hooks#onchanges) section of the [Lifecycle Hooks](guide/lifecycle-hooks) guide for more details and examples.
### `OnChanges` and `@Input()`
To watch for changes on an `@Input()` property, use
`OnChanges`, one of Angular's [lifecycle hooks](guide/lifecycle-hooks#onchanges).
`OnChanges` is specifically designed to work with properties that have the
`@Input()` decorator. See the [`OnChanges`](guide/lifecycle-hooks#onchanges) section of the [Lifecycle Hooks](guide/lifecycle-hooks) guide for more details and examples.
</div>
{@a output} {@a output}
## How to use `@Output()` ## Sending data to a parent component
Use the `@Output()` decorator in the child component or directive to allow data to flow from
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](guide/event-binding).
The `@Output()` decorator in a child component or directive allows data to flow from the child to the parent.
<div class="lightbox"> <div class="lightbox">
<img src="generated/images/guide/inputs-outputs/output.svg" alt="Output diagram"> <img src="generated/images/guide/inputs-outputs/output.svg" alt="Output diagram">
</div> </div>
Just like with `@Input()`, you can use `@Output()` `@Output()` marks a property in a child component as a doorway through which data can travel from the child to the parent.
on a property of the child component but its type should be
`EventEmitter`.
`@Output()` marks a property in a child component as a doorway The child component uses the `@Output()` property to raise an event to notify the parent of the change.
through which data can travel from the child to the parent. To raise an event, an `@Output()` must have the type of `EventEmitter`, which is a class in `@angular/core` that you use to emit custom events.
The child component then has to raise an event so the
parent knows something has changed. To raise an event,
`@Output()` works hand in hand with `EventEmitter`,
which is a class in `@angular/core` that you
use to emit custom events.
When you use `@Output()`, edit these parts of your app: The following example shows how to set up an `@Output()` in a child component that pushes data from an HTML `<input>` to an array in the parent component.
* The child component class and template To use `@Output()`, you must configure the parent and child.
* The parent component class and template
### Configuring the child component
The following example shows how to set up an `@Output()` in a child The following example features an `<input>` where a user can enter a value and click a `<button>` that raises an event. The `EventEmitter` then relays the data to the parent component.
component that pushes data you enter in an HTML `<input>` to an array in the
parent component.
<div class="alert is-helpful"> 1. Import `Output` and `EventEmitter` in the child component class:
The HTML element `<input>` and the Angular decorator `@Input()` ```js
are different. This documentation is about component communication in Angular as it pertains to `@Input()` and `@Output()`. For more information on the HTML element `<input>`, see the [W3C Recommendation](https://www.w3.org/TR/html5/sec-forms.html#the-input-element). import { Output, EventEmitter } from '@angular/core';
</div> ```
## In the child 1. In the component class, decorate a property with `@Output()`.
The following example `newItemEvent` `@Output()` has a type of `EventEmitter`, which means it's an event.
This example features an `<input>` where a user can enter a value and click a `<button>` that raises an event. The `EventEmitter` then relays the data to the parent component. <code-example path="inputs-outputs/src/app/item-output/item-output.component.ts" region="item-output" header="src/app/item-output/item-output.component.ts"></code-example>
First, be sure to import `Output` and `EventEmitter` The different parts of the above declaration are as follows:
in the child component class:
```js * `@Output()`&mdash;a decorator function marking the property as a way for data to go from the child to the parent
import { Output, EventEmitter } from '@angular/core'; * `newItemEvent`&mdash;the name of the `@Output()`
* `EventEmitter<string>`&mdash;the `@Output()`'s type
* `new EventEmitter<string>()`&mdash;tells Angular to create a new event emitter and that the data it emits is of type string.
``` For more information on `EventEmitter`, see the [EventEmitter API documentation](api/core/EventEmitter).
Next, still in the child, decorate a property with `@Output()` in the component class. 1. Create an `addNewItem()` method in the same component class:
The following example `@Output()` is called `newItemEvent` and its type is
`EventEmitter`, which means it's an event.
<code-example path="inputs-outputs/src/app/item-output/item-output.component.ts" region="item-output-class" header="src/app/item-output/item-output.component.ts"></code-example>
<code-example path="inputs-outputs/src/app/item-output/item-output.component.ts" region="item-output" header="src/app/item-output/item-output.component.ts"></code-example> The `addNewItem()` function uses the `@Output()`, `newItemEvent`, to raise an event with the value the user types into the `<input>`.
The different parts of the above declaration are as follows: ### Configuring the child's template
* `@Output()`&mdash;a decorator function marking the property as a way for data to go from the child to the parent The child's template has two controls.
* `newItemEvent`&mdash;the name of the `@Output()` The first is an HTML `<input>` with a [template reference variable](guide/template-reference-variables) , `#newItem`, where the user types in an item name.
* `EventEmitter<string>`&mdash;the `@Output()`'s type The `value` property of the `#newItem` variable stores what the user types into the `<input>`.
* `new EventEmitter<string>()`&mdash;tells Angular to create a new event emitter and that the data it emits is of type string. The type could be any type, such as `number`, `boolean`, and so on. For more information on `EventEmitter`, see the [EventEmitter API documentation](api/core/EventEmitter).
Next, create an `addNewItem()` method in the same component class:
<code-example path="inputs-outputs/src/app/item-output/item-output.component.ts" region="item-output-class" header="src/app/item-output/item-output.component.ts"></code-example>
The `addNewItem()` function uses the `@Output()`, `newItemEvent`,
to raise an event in which it emits the value the user
types into the `<input>`. In other words, when
the user clicks the add button in the UI, the child lets the parent know
about the event and gives that data to the parent.
### In the child's template
The child's template has two controls. The first is an HTML `<input>` with a
[template reference variable](guide/template-reference-variables) , `#newItem`,
where the user types in an item name. Whatever the user types
into the `<input>` gets stored in the `value` property of the `#newItem` variable.
<code-example path="inputs-outputs/src/app/item-output/item-output.component.html" region="child-output" header="src/app/item-output/item-output.component.html"></code-example> <code-example path="inputs-outputs/src/app/item-output/item-output.component.html" region="child-output" header="src/app/item-output/item-output.component.html"></code-example>
The second element is a `<button>` The second element is a `<button>` with a `click` [event binding](guide/event-binding).
with an [event binding](guide/event-binding). You know it's
an event binding because the part to the left of the equal
sign is in parentheses, `(click)`.
The `(click)` event is bound to the `addNewItem()` method in the child component class which The `(click)` event is bound to the `addNewItem()` method in the child component class.
takes as its argument whatever the value of `#newItem.value` property is. The `addNewItem()` method takes as its argument the value of the `#newItem.value` property.
Now the child component has an `@Output()` ### Configuring the parent component
for sending data to the parent and a method for raising an event.
The next step is in the parent.
## In the parent The `AppComponent` in this example features a list of `items` in an array and a method for adding more items to the array.
In this example, the parent component is `AppComponent`, but you could use
any component in which you could nest the child.
The `AppComponent` in this example features a list of `items`
in an array and a method for adding more items to the array.
<code-example path="inputs-outputs/src/app/app.component.ts" region="add-new-item" header="src/app/app.component.ts"></code-example> <code-example path="inputs-outputs/src/app/app.component.ts" region="add-new-item" header="src/app/app.component.ts"></code-example>
The `addItem()` method takes an argument in the form of a string The `addItem()` method takes an argument in the form of a string and then adds that string to the `items` array.
and then pushes, or adds, that string to the `items` array.
### In the parent's template ### Configuring the parent's template
Next, in the parent's template, bind the parent's 1. In the parent's template, bind the parent's method to the child's event.
method to the child's event. Put the child selector, here `<app-item-output>`,
within the parent component's
template, `app.component.html`.
<code-example path="inputs-outputs/src/app/app.component.html" region="output-parent" header="src/app/app.component.html"></code-example> 1. Put the child selector, here `<app-item-output>`, within the parent component's template, `app.component.html`.
The event binding, `(newItemEvent)='addItem($event)'`, tells <code-example path="inputs-outputs/src/app/app.component.html" region="output-parent" header="src/app/app.component.html"></code-example>
Angular to connect the event in the child, `newItemEvent`, to
the method in the parent, `addItem()`, and that the event that the child
is notifying the parent about is to be the argument of `addItem()`.
In other words, this is where the actual hand off of data takes place.
The `$event` contains the data that the user types into the `<input>`
in the child template UI.
Now, in order to see the `@Output()` working, add the following to the parent's template: The event binding, `(newItemEvent)='addItem($event)'`, connects the event in the child, `newItemEvent`, to the method in the parent, `addItem()`.
```html The `$event` contains the data that the user types into the `<input>` in the child template UI.
<ul>
<li *ngFor="let item of items">{{item}}</li> To see the `@Output()` working, you can add the following to the parent's template:
</ul>
```html
<ul>
<li *ngFor="let item of items">{{item}}</li>
</ul>
``` ```
The `*ngFor` iterates over the items in the `items` array. When you enter a value in the child's `<input>` and click the button, the child emits the event and the parent's `addItem()` method pushes the value to the `items` array and it renders in the list. The `*ngFor` iterates over the items in the `items` array.
When you enter a value in the child's `<input>` and click the button, the child emits the event and the parent's `addItem()` method pushes the value to the `items` array and new item renders in the list.
## `@Input()` and `@Output()` together ## Using `@Input()` and `@Output()` together
You can use `@Input()` and `@Output()` on the same child component as in the following: You can use `@Input()` and `@Output()` on the same child component as follows:
<code-example path="inputs-outputs/src/app/app.component.html" region="together" header="src/app/app.component.html"></code-example> <code-example path="inputs-outputs/src/app/app.component.html" region="together" header="src/app/app.component.html"></code-example>
The target, `item`, which is an `@Input()` property in the child component class, receives its value from the parent's property, `currentItem`. When you click delete, the child component raises an event, `deleteRequest`, which is the argument for the parent's `crossOffItem()` method. The target, `item`, which is an `@Input()` property in the child component class, receives its value from the parent's property, `currentItem`.
When you click delete, the child component raises an event, `deleteRequest`, which is the argument for the parent's `crossOffItem()` method.
The following diagram is of an `@Input()` and an `@Output()` on the same The following diagram shows the different parts of the `@Input()` and `@Output()` on the `<app-input-output>` child component.
child component and shows the different parts of each:
<div class="lightbox"> <div class="lightbox">
<img src="generated/images/guide/inputs-outputs/input-output-diagram.svg" alt="Input/Output diagram"> <img src="generated/images/guide/inputs-outputs/input-output-diagram.svg" alt="Input/Output diagram">
</div> </div>
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()` The child selector is `<app-input-output>` with `item` and `deleteRequest` being `@Input()` and `@Output()`
properties in the child component class. The property `currentItem` and the method `crossOffItem()` are both in the parent component class. properties in the child component class.
The property `currentItem` and the method `crossOffItem()` are both in the parent component class.
To combine property and event bindings using the banana-in-a-box To combine property and event bindings using the banana-in-a-box
syntax, `[()]`, see [Two-way Binding](guide/two-way-binding). syntax, `[()]`, see [Two-way Binding](guide/two-way-binding).
## `@Input()` and `@Output()` declarations
Instead of using the `@Input()` and `@Output()` decorators
to declare inputs and outputs, you can identify
members in the `inputs` and `outputs` arrays
of the directive metadata, as in this example:
<code-example path="inputs-outputs/src/app/in-the-metadata/in-the-metadata.component.ts" region="metadata" header="src/app/in-the-metadata/in-the-metadata.component.ts"></code-example>
While declaring `inputs` and `outputs` in the `@Directive` and `@Component`
metadata is possible, it is a better practice to use the `@Input()` and `@Output()`
class decorators instead, as follows:
<code-example path="inputs-outputs/src/app/input-output/input-output.component.ts" region="input-output" header="src/app/input-output/input-output.component.ts"></code-example>
See the [Decorate input and output properties](guide/styleguide#decorate-input-and-output-properties) section of the
[Style Guide](guide/styleguide) for details.
<div class="alert is-helpful">
If you get a template parse error when trying to use inputs or outputs, but you know that the
properties do indeed exist, double check
that your properties are annotated with `@Input()` / `@Output()` or that you've declared
them in an `inputs`/`outputs` array:
<code-example language="bash">
Uncaught Error: Template parse errors:
Can't bind to 'item' since it isn't a known property of 'app-item-detail'
</code-example>
</div>
{@a aliasing-io}
## Aliasing inputs and outputs
Sometimes the public name of an input/output property should be different from the internal name. While it is a best practice to avoid this situation, Angular does
offer a solution.
### Aliasing in the metadata
Alias inputs and outputs in the metadata using a colon-delimited (`:`) string with
the directive property name on the left and the public alias on the right:
<code-example path="inputs-outputs/src/app/aliasing/aliasing.component.ts" region="alias" header="src/app/aliasing/aliasing.component.ts"></code-example>
### Aliasing with the `@Input()`/`@Output()` decorator
You can specify the alias for the property name by passing the alias name to the `@Input()`/`@Output()` decorator. The internal name remains as usual.
<code-example path="inputs-outputs/src/app/aliasing/aliasing.component.ts" region="alias-input-output" header="src/app/aliasing/aliasing.component.ts"></code-example>

View File

@ -8,7 +8,7 @@ Angular makes use of observables as an interface to handle a variety of common a
## Transmitting data between components ## Transmitting data between components
Angular provides an `EventEmitter` class that is used when publishing values from a component through the [`@Output()` decorator](guide/inputs-outputs#how-to-use-output). Angular provides an `EventEmitter` class that is used when publishing values from a component through the [`@Output()` decorator](guide/inputs-outputs#output).
`EventEmitter` extends [RxJS `Subject`](https://rxjs.dev/api/index/class/Subject), adding an `emit()` method so it can send arbitrary values. `EventEmitter` extends [RxJS `Subject`](https://rxjs.dev/api/index/class/Subject), 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. When you call `emit()`, it passes the emitted value to the `next()` method of any subscribed observer.

View File

@ -128,7 +128,7 @@
}, },
{ {
"url": "guide/inputs-outputs", "url": "guide/inputs-outputs",
"title": "Inputs and Outputs", "title": "Sharing data between child and parent directives and components",
"tooltip": "Introductory guide to sharing data between parent and child directives or components." "tooltip": "Introductory guide to sharing data between parent and child directives or components."
}, },
{ {