229 lines
11 KiB
Markdown
229 lines
11 KiB
Markdown
|
|
# Property binding `[property]`
|
|
|
|
Use property binding to _set_ properties of target elements or
|
|
directive `@Input()` decorators.
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
See the <live-example></live-example> for a working example containing the code snippets in this guide.
|
|
|
|
</div>
|
|
|
|
## One-way in
|
|
|
|
Property binding flows a value in one direction,
|
|
from a component's property into a target element property.
|
|
|
|
You can't use property
|
|
binding to read or pull values out of target elements. Similarly, you cannot use
|
|
property binding to call a method on the target element.
|
|
If the element raises events, you can listen to them with an [event binding](guide/event-binding).
|
|
|
|
If you must read a target element property or call one of its methods,
|
|
see the API reference for [ViewChild](api/core/ViewChild) and
|
|
[ContentChild](api/core/ContentChild).
|
|
|
|
## Examples
|
|
|
|
The most common property binding sets an element property to a component
|
|
property value. An example is
|
|
binding the `src` property of an image element to a component's `itemImageUrl` property:
|
|
|
|
<code-example path="property-binding/src/app/app.component.html" region="property-binding" header="src/app/app.component.html"></code-example>
|
|
|
|
Here's an example of binding to the `colSpan` property. Notice that it's not `colspan`,
|
|
which is the attribute, spelled with a lowercase `s`.
|
|
|
|
<code-example path="property-binding/src/app/app.component.html" region="colSpan" header="src/app/app.component.html"></code-example>
|
|
|
|
For more details, see the [MDN HTMLTableCellElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement) documentation.
|
|
|
|
For more information about `colSpan` and `colspan`, see the [Attribute binding](guide/attribute-binding#colspan) guide.
|
|
|
|
Another example is disabling a button when the component says that it `isUnchanged`:
|
|
|
|
<code-example path="property-binding/src/app/app.component.html" region="disabled-button" header="src/app/app.component.html"></code-example>
|
|
|
|
Another is setting a property of a directive:
|
|
|
|
<code-example path="property-binding/src/app/app.component.html" region="class-binding" header="src/app/app.component.html"></code-example>
|
|
|
|
Yet another is setting the model property of a custom component—a great way
|
|
for parent and child components to communicate:
|
|
|
|
<code-example path="property-binding/src/app/app.component.html" region="model-property-binding" header="src/app/app.component.html"></code-example>
|
|
|
|
## Binding targets
|
|
|
|
An element property between enclosing square brackets identifies the target property.
|
|
The target property in the following code is the image element's `src` property.
|
|
|
|
<code-example path="property-binding/src/app/app.component.html" region="property-binding" header="src/app/app.component.html"></code-example>
|
|
|
|
There's also the `bind-` prefix alternative:
|
|
|
|
<code-example path="property-binding/src/app/app.component.html" region="bind-prefix" header="src/app/app.component.html"></code-example>
|
|
|
|
|
|
In most cases, the target name is the name of a property, even
|
|
when it appears to be the name of an attribute.
|
|
So in this case, `src` is the name of the `<img>` element property.
|
|
|
|
Element properties may be the more common targets,
|
|
but Angular looks first to see if the name is a property of a known directive,
|
|
as it is in the following example:
|
|
|
|
<code-example path="property-binding/src/app/app.component.html" region="class-binding" header="src/app/app.component.html"></code-example>
|
|
|
|
Technically, Angular is matching the name to a directive `@Input()`,
|
|
one of the property names listed in the directive's `inputs` array
|
|
or a property decorated with `@Input()`.
|
|
Such inputs map to the directive's own properties.
|
|
|
|
If the name fails to match a property of a known directive or element, Angular reports an “unknown directive” error.
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
Though the target name is usually the name of a property,
|
|
there is an automatic attribute-to-property mapping in Angular for
|
|
several common attributes. These include `class`/`className`, `innerHtml`/`innerHTML`, and
|
|
`tabindex`/`tabIndex`.
|
|
|
|
</div>
|
|
|
|
|
|
## Avoid side effects
|
|
|
|
Evaluation of a template expression should have no visible side effects.
|
|
The expression language itself, or the way you write template expressions,
|
|
helps to a certain extent;
|
|
you can't assign a value to anything in a property binding expression
|
|
nor use the increment and decrement operators.
|
|
|
|
For example, you could have an expression that invoked a property or method that had
|
|
side effects. The expression could call something like `getFoo()` where only you
|
|
know what `getFoo()` does. If `getFoo()` changes something
|
|
and you happen to be binding to that something,
|
|
Angular may or may not display the changed value. Angular may detect the
|
|
change and throw a warning error.
|
|
As a best practice, stick to properties and to methods that return
|
|
values and avoid side effects.
|
|
|
|
## Return the proper type
|
|
|
|
The template expression should evaluate to the type of value
|
|
that the target property expects.
|
|
Return a string if the target property expects a string, a number if it
|
|
expects a number, an object if it expects an object, and so on.
|
|
|
|
In the following example, the `childItem` property of the `ItemDetailComponent` expects a string, which is exactly what you're sending in the property binding:
|
|
|
|
<code-example path="property-binding/src/app/app.component.html" region="model-property-binding" header="src/app/app.component.html"></code-example>
|
|
|
|
You can confirm this by looking in the `ItemDetailComponent` where the `@Input` type is set to a string:
|
|
<code-example path="property-binding/src/app/item-detail/item-detail.component.ts" region="input-type" header="src/app/item-detail/item-detail.component.ts (setting the @Input() type)"></code-example>
|
|
|
|
As you can see here, the `parentItem` in `AppComponent` is a string, which the `ItemDetailComponent` expects:
|
|
<code-example path="property-binding/src/app/app.component.ts" region="parent-data-type" header="src/app/app.component.ts"></code-example>
|
|
|
|
### Passing in an object
|
|
|
|
The previous simple example showed passing in a string. To pass in an object,
|
|
the syntax and thinking are the same.
|
|
|
|
In this scenario, `ItemListComponent` is nested within `AppComponent` and the `items` property expects an array of objects.
|
|
|
|
<code-example path="property-binding/src/app/app.component.html" region="pass-object" header="src/app/app.component.html"></code-example>
|
|
|
|
The `items` property is declared in the `ItemListComponent` with a type of `Item` and decorated with `@Input()`:
|
|
|
|
<code-example path="property-binding/src/app/item-list/item-list.component.ts" region="item-input" header="src/app/item-list.component.ts"></code-example>
|
|
|
|
In this sample app, an `Item` is an object that has two properties; an `id` and a `name`.
|
|
|
|
<code-example path="property-binding/src/app/item.ts" region="item-class" header="src/app/item.ts"></code-example>
|
|
|
|
While a list of items exists in another file, `mock-items.ts`, you can
|
|
specify a different item in `app.component.ts` so that the new item will render:
|
|
|
|
<code-example path="property-binding/src/app/app.component.ts" region="pass-object" header="src/app.component.ts"></code-example>
|
|
|
|
You just have to make sure, in this case, that you're supplying an array of objects because that's the type of `Item` and is what the nested component, `ItemListComponent`, expects.
|
|
|
|
In this example, `AppComponent` specifies a different `item` object
|
|
(`currentItems`) and passes it to the nested `ItemListComponent`. `ItemListComponent` was able to use `currentItems` because it matches what an `Item` object is according to `item.ts`. The `item.ts` file is where
|
|
`ItemListComponent` gets its definition of an `item`.
|
|
|
|
## Remember the brackets
|
|
|
|
The brackets, `[]`, tell Angular to evaluate the template expression.
|
|
If you omit the brackets, Angular treats the string as a constant
|
|
and *initializes the target property* with that string:
|
|
|
|
<code-example path="property-binding/src/app/app.component.html" region="no-evaluation" header="src/app.component.html"></code-example>
|
|
|
|
|
|
Omitting the brackets will render the string
|
|
`parentItem`, not the value of `parentItem`.
|
|
|
|
## One-time string initialization
|
|
|
|
You *should* omit the brackets when all of the following are true:
|
|
|
|
* The target property accepts a string value.
|
|
* The string is a fixed value that you can put directly into the template.
|
|
* This initial value never changes.
|
|
|
|
You routinely initialize attributes this way in standard HTML, and it works
|
|
just as well for directive and component property initialization.
|
|
The following example initializes the `prefix` property of the `StringInitComponent` to a fixed string,
|
|
not a template expression. Angular sets it and forgets about it.
|
|
|
|
<code-example path="property-binding/src/app/app.component.html" region="string-init" header="src/app/app.component.html"></code-example>
|
|
|
|
The `[item]` binding, on the other hand, remains a live binding to the component's `currentItems` property.
|
|
|
|
## Property binding vs. interpolation
|
|
|
|
You often have a choice between interpolation and property binding.
|
|
The following binding pairs do the same thing:
|
|
|
|
<code-example path="property-binding/src/app/app.component.html" region="property-binding-interpolation" header="src/app/app.component.html"></code-example>
|
|
|
|
Interpolation is a convenient alternative to property binding in
|
|
many cases. When rendering data values as strings, there is no
|
|
technical reason to prefer one form to the other, though readability
|
|
tends to favor interpolation. However, *when setting an element
|
|
property to a non-string data value, you must use property binding*.
|
|
|
|
## Content security
|
|
|
|
Imagine the following malicious content.
|
|
|
|
<code-example path="property-binding/src/app/app.component.ts" region="malicious-content" header="src/app/app.component.ts"></code-example>
|
|
|
|
In the component template, the content might be used with interpolation:
|
|
|
|
<code-example path="property-binding/src/app/app.component.html" region="malicious-interpolated" header="src/app/app.component.html"></code-example>
|
|
|
|
Fortunately, Angular data binding is on alert for dangerous HTML. In the above case,
|
|
the HTML displays as is, and the Javascript does not execute. Angular **does not**
|
|
allow HTML with script tags to leak into the browser, neither with interpolation
|
|
nor property binding.
|
|
|
|
In the following example, however, Angular [sanitizes](guide/security#sanitization-and-security-contexts)
|
|
the values before displaying them.
|
|
|
|
<code-example path="property-binding/src/app/app.component.html" region="malicious-content" header="src/app/app.component.html"></code-example>
|
|
|
|
Interpolation handles the `<script>` tags differently than
|
|
property binding but both approaches render the
|
|
content harmlessly. The following is the browser output
|
|
of the `evilTitle` examples.
|
|
|
|
<code-example language="bash">
|
|
"Template <script>alert("evil never sleeps")</script> Syntax" is the interpolated evil title.
|
|
"Template Syntax" is the property bound evil title.
|
|
</code-example>
|