parent
eea5d6b38f
commit
3f66a84e01
|
@ -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
|
||||
and child directives or components. An `@Input()` property is writable
|
||||
while an `@Output()` property is observable.
|
||||
A common pattern in Angular is sharing data between a parent component and one or more child components.
|
||||
You can implement this pattern by using the `@Input()` and `@Output()` directives.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
@ -10,7 +9,7 @@ See the <live-example></live-example> for a working example containing the code
|
|||
|
||||
</div>
|
||||
|
||||
Consider this example of a child/parent relationship:
|
||||
Consider the following hierarchy:
|
||||
|
||||
```html
|
||||
<parent-component>
|
||||
|
@ -19,80 +18,52 @@ Consider this example of a child/parent relationship:
|
|||
|
||||
```
|
||||
|
||||
Here, the `<child-component>` selector, or child directive, is embedded
|
||||
within a `<parent-component>`, which serves as the child's context.
|
||||
The `<parent-component>` serves as the context for the `<child-component>`.
|
||||
|
||||
`@Input()` and `@Output()` act as
|
||||
the API, or application programming interface, of the child
|
||||
component in that they allow the child to
|
||||
communicate with the parent. Think of `@Input()` and `@Output()` like ports
|
||||
or doorways—`@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.
|
||||
`@Input()` and `@Output()` give a child component a way to communicate with its parent component.
|
||||
`@Input()` allows a parent component to update data in the child component.
|
||||
Conversely, `@Output() allows the child to send data to a parent component.
|
||||
|
||||
<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}
|
||||
|
||||
## How to use `@Input()`
|
||||
|
||||
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.
|
||||
## Sending data to a child 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">
|
||||
<img src="generated/images/guide/inputs-outputs/input.svg" alt="Input data flow diagram">
|
||||
</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
|
||||
* The parent component class and template
|
||||
### Configuring the child component
|
||||
|
||||
|
||||
### In the child
|
||||
|
||||
To use the `@Input()` decorator in a child component class, first import
|
||||
`Input` and then decorate the property with `@Input()`:
|
||||
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.
|
||||
|
||||
<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
|
||||
a type of `string`, however, `@Input()` properties can have any type, such as
|
||||
`number`, `string`, `boolean`, or `object`. The value for `item` will come from the parent component, which the next section covers.
|
||||
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`.
|
||||
The value for `item` comes from the parent component.
|
||||
|
||||
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>
|
||||
|
||||
|
||||
|
||||
### In the parent
|
||||
### Configuring the parent component
|
||||
|
||||
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`.
|
||||
|
||||
First, use the child's selector, here `<app-item-detail>`, as a directive within the
|
||||
parent component template. Then, use [property binding](guide/property-binding)
|
||||
to bind the property in the child to the property of the parent.
|
||||
1. Use the child's selector, here `<app-item-detail>`, as a directive within the
|
||||
parent component template.
|
||||
|
||||
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>
|
||||
|
||||
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>
|
||||
|
||||
|
@ -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">
|
||||
</div>
|
||||
|
||||
The target in the square brackets, `[]`, is the property you decorate
|
||||
with `@Input()` in the child component. The binding source, the part
|
||||
to the right of the equal sign, is the data that the parent
|
||||
component passes to the nested component.
|
||||
The target in the square brackets, `[]`, is the property you decorate with `@Input()` in the child component.
|
||||
The binding source, the part 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—that is, what's
|
||||
in square brackets—you must
|
||||
decorate the property with `@Input()` in the child component.
|
||||
### Watching for `@Input()` changes
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
### `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>
|
||||
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.
|
||||
|
||||
{@a output}
|
||||
|
||||
## How to use `@Output()`
|
||||
|
||||
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).
|
||||
## Sending data to a parent component
|
||||
|
||||
The `@Output()` decorator in a child component or directive allows data to flow from the child to the parent.
|
||||
|
||||
<div class="lightbox">
|
||||
<img src="generated/images/guide/inputs-outputs/output.svg" alt="Output diagram">
|
||||
</div>
|
||||
|
||||
Just like with `@Input()`, you can use `@Output()`
|
||||
on a property of the child component but its type should be
|
||||
`EventEmitter`.
|
||||
`@Output()` marks a property in a child component as a doorway through which data can travel from the child to the parent.
|
||||
|
||||
`@Output()` marks a property in a child component as a doorway
|
||||
through which data can travel from the child to the parent.
|
||||
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.
|
||||
The child component uses the `@Output()` property to raise an event to notify the parent of the change.
|
||||
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.
|
||||
|
||||
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
|
||||
* The parent component class and template
|
||||
To use `@Output()`, you must configure the parent and child.
|
||||
|
||||
### Configuring the child component
|
||||
|
||||
The following example shows how to set up an `@Output()` in a child
|
||||
component that pushes data you enter in an HTML `<input>` to an array in the
|
||||
parent component.
|
||||
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.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
1. Import `Output` and `EventEmitter` in the child component class:
|
||||
|
||||
The HTML element `<input>` and the Angular decorator `@Input()`
|
||||
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).
|
||||
```js
|
||||
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`
|
||||
in the child component class:
|
||||
The different parts of the above declaration are as follows:
|
||||
|
||||
```js
|
||||
import { Output, EventEmitter } from '@angular/core';
|
||||
* `@Output()`—a decorator function marking the property as a way for data to go from the child to the parent
|
||||
* `newItemEvent`—the name of the `@Output()`
|
||||
* `EventEmitter<string>`—the `@Output()`'s type
|
||||
* `new EventEmitter<string>()`—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.
|
||||
The following example `@Output()` is called `newItemEvent` and its type is
|
||||
`EventEmitter`, which means it's an event.
|
||||
1. 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>
|
||||
|
||||
<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()`—a decorator function marking the property as a way for data to go from the child to the parent
|
||||
* `newItemEvent`—the name of the `@Output()`
|
||||
* `EventEmitter<string>`—the `@Output()`'s type
|
||||
* `new EventEmitter<string>()`—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.
|
||||
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.
|
||||
The `value` property of the `#newItem` variable stores what the user types into the `<input>`.
|
||||
|
||||
<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>`
|
||||
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 second element is a `<button>` with a `click` [event binding](guide/event-binding).
|
||||
|
||||
The `(click)` event is bound to the `addNewItem()` method in the child component class which
|
||||
takes as its argument whatever the value of `#newItem.value` property is.
|
||||
The `(click)` event is bound to the `addNewItem()` method in the child component class.
|
||||
The `addNewItem()` method takes as its argument the value of the `#newItem.value` property.
|
||||
|
||||
Now the child component has an `@Output()`
|
||||
for sending data to the parent and a method for raising an event.
|
||||
The next step is in the parent.
|
||||
### Configuring the parent component
|
||||
|
||||
## In the parent
|
||||
|
||||
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.
|
||||
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>
|
||||
|
||||
The `addItem()` method takes an argument in the form of a string
|
||||
and then pushes, or adds, that string to the `items` array.
|
||||
The `addItem()` method takes an argument in the form of a string and then 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
|
||||
method to the child's event. Put the child selector, here `<app-item-output>`,
|
||||
within the parent component's
|
||||
template, `app.component.html`.
|
||||
1. In the parent's template, bind the parent's method to the child's event.
|
||||
|
||||
<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
|
||||
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.
|
||||
<code-example path="inputs-outputs/src/app/app.component.html" region="output-parent" header="src/app/app.component.html"></code-example>
|
||||
|
||||
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.
|
||||
|
||||
To see the `@Output()` working, you can add the following to the parent's template:
|
||||
|
||||
```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>
|
||||
|
||||
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
|
||||
child component and shows the different parts of each:
|
||||
The following diagram shows the different parts of the `@Input()` and `@Output()` on the `<app-input-output>` child component.
|
||||
|
||||
<div class="lightbox">
|
||||
<img src="generated/images/guide/inputs-outputs/input-output-diagram.svg" alt="Input/Output diagram">
|
||||
</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()`
|
||||
properties in the child component class. The property `currentItem` and the method `crossOffItem()` are both in the parent component class.
|
||||
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.
|
||||
|
||||
To combine property and event bindings using the banana-in-a-box
|
||||
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>
|
||||
|
|
|
@ -8,7 +8,7 @@ Angular makes use of observables as an interface to handle a variety of common a
|
|||
|
||||
## 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.
|
||||
When you call `emit()`, it passes the emitted value to the `next()` method of any subscribed observer.
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@
|
|||
},
|
||||
{
|
||||
"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."
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue