docs: clean up formats in template syntax guide (#32197)
PR Close #32197
This commit is contained in:
parent
d953c1cee3
commit
ef2047555a
|
@ -6,8 +6,7 @@
|
|||
h4 .syntax { font-size: 100%; }
|
||||
</style>
|
||||
|
||||
The Angular application manages what the user sees and can do, achieving this through the interaction of a
|
||||
component class instance (the *component*) and its user-facing template.
|
||||
The Angular application manages what the user sees and can do, achieving this through the interaction of a component class instance (the *component*) and its user-facing template.
|
||||
|
||||
You may be familiar with the component/template duality from your experience with model-view-controller (MVC) or model-view-viewmodel (MVVM).
|
||||
In Angular, the component plays the part of the controller/viewmodel, and the template represents the view.
|
||||
|
@ -85,12 +84,10 @@ converts the expression results to strings, and links them with neighboring lite
|
|||
it assigns this composite interpolated result to an **element or directive property**.
|
||||
|
||||
You appear to be inserting the result between element tags and assigning it to attributes.
|
||||
However, interpolation is a special syntax that Angular converts into a *property binding*.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
However, interpolation is a special syntax that Angular converts into a
|
||||
property binding.
|
||||
|
||||
If you'd like to use something other than `{{` and `}}`, you can
|
||||
configure the interpolation delimiter via the
|
||||
[interpolation](api/core/Component#interpolation)
|
||||
|
@ -124,8 +121,8 @@ including:
|
|||
Other notable differences from JavaScript syntax include:
|
||||
|
||||
* No support for the bitwise operators such as `|` and `&`
|
||||
* New template expression operators, such as `|`, `?.` and `!`
|
||||
<!-- link to: guide/template-syntax#expression-operators -->
|
||||
* New [template expression operators](guide/template-syntax#expression-operators), such as `|`, `?.` and `!`
|
||||
|
||||
|
||||
### Expression context
|
||||
|
||||
|
@ -171,12 +168,29 @@ members of the expression context.
|
|||
|
||||
When using template expressions follow these guidelines:
|
||||
|
||||
* [No visible side effects](guide/template-syntax#no-visible-side-effects)
|
||||
* [Quick execution](guide/template-syntax#quick-execution)
|
||||
* [Simplicity](guide/template-syntax#simplicity)
|
||||
* [Quick execution](guide/template-syntax#quick-execution)
|
||||
* [No visible side effects](guide/template-syntax#no-visible-side-effects)
|
||||
|
||||
#### Simplicity
|
||||
|
||||
### No visible side effects
|
||||
Although it's possible to write complex template expressions, it's a better
|
||||
practice to avoid them.
|
||||
|
||||
A property name or method call should be the norm, but an occasional Boolean negation, `!`, is OK.
|
||||
Otherwise, confine application and business logic to the component,
|
||||
where it is easier to develop and test.
|
||||
|
||||
#### Quick execution
|
||||
|
||||
Angular executes template expressions after every change detection cycle.
|
||||
Change detection cycles are triggered by many asynchronous activities such as
|
||||
promise resolutions, HTTP results, timer events, key presses and mouse moves.
|
||||
|
||||
Expressions should finish quickly or the user experience may drag, especially on slower devices.
|
||||
Consider caching values when their computation is expensive.
|
||||
|
||||
#### No visible side effects
|
||||
|
||||
A template expression should not change any application state other than the value of the
|
||||
target property.
|
||||
|
@ -187,40 +201,18 @@ The view should be stable throughout a single rendering pass.
|
|||
|
||||
An [idempotent](https://en.wikipedia.org/wiki/Idempotence) expression is ideal because
|
||||
it is free of side effects and improves Angular's change detection performance.
|
||||
|
||||
In Angular terms, an idempotent expression always returns
|
||||
*exactly the same thing* until
|
||||
one of its dependent values changes.
|
||||
*exactly the same thing* until one of its dependent values changes.
|
||||
|
||||
Dependent values should not change during a single turn of the event loop.
|
||||
If an idempotent expression returns a string or a number, it returns the same string or number when called twice in a row. If the expression returns an object, including an `array`, it returns the same object *reference* when called twice in a row.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
There is one exception to this behavior that applies to `*ngFor`. `*ngFor` has `trackBy` functionality that can deal with referential inequality of objects that when iterating over them.
|
||||
|
||||
For more information, see the [*ngFor with `trackBy`](guide/template-syntax#ngfor-with-trackby) section of this guide.
|
||||
There is one exception to this behavior that applies to `*ngFor`. `*ngFor` has `trackBy` functionality that can deal with referential inequality of objects when iterating over them. See [*ngFor with `trackBy`](guide/template-syntax#ngfor-with-trackby) for details.
|
||||
|
||||
</div>
|
||||
|
||||
### Quick execution
|
||||
|
||||
Angular executes template expressions after every change detection cycle.
|
||||
Change detection cycles are triggered by many asynchronous activities such as
|
||||
promise resolutions, HTTP results, timer events, key presses and mouse moves.
|
||||
|
||||
Expressions should finish quickly or the user experience may drag, especially on slower devices.
|
||||
Consider caching values when their computation is expensive.
|
||||
|
||||
### Simplicity
|
||||
|
||||
Although it's possible to write complex template expressions, it's a better
|
||||
practice to avoid them.
|
||||
|
||||
A property name or method call should be the norm, but an occasional Boolean negation, `!`, is OK.
|
||||
Otherwise, confine application and business logic to the component,
|
||||
where it is easier to develop and test.
|
||||
|
||||
<!-- end of Interpolation doc -->
|
||||
|
||||
<hr/>
|
||||
|
@ -278,19 +270,15 @@ Template context names take precedence over component context names.
|
|||
In `deleteHero(hero)` above, the `hero` is the template input variable,
|
||||
not the component's `hero` property.
|
||||
|
||||
### Statement guidelines
|
||||
|
||||
Template statements cannot refer to anything in the global namespace. They
|
||||
can't refer to `window` or `document`.
|
||||
They can't call `console.log` or `Math.max`.
|
||||
|
||||
### Statement guidelines
|
||||
|
||||
As with expressions, avoid writing complex template statements.
|
||||
A method call or simple property assignment should be the norm.
|
||||
|
||||
Now that you have a feel for template expressions and statements,
|
||||
you're ready to learn about the varieties of data binding syntax beyond interpolation.
|
||||
|
||||
|
||||
<hr/>
|
||||
|
||||
{@a binding-syntax}
|
||||
|
@ -396,7 +384,7 @@ Every public member of a **source** directive is automatically available for bin
|
|||
You don't have to do anything special to access a directive member in a template expression or statement.
|
||||
|
||||
|
||||
## Data-binding and HTML
|
||||
### Data-binding and HTML
|
||||
|
||||
In the normal course of HTML development, you create a visual structure with HTML elements, and
|
||||
you modify those elements by setting element attributes with string constants.
|
||||
|
@ -415,10 +403,10 @@ Notice that the binding is to the `disabled` property of the button's DOM elemen
|
|||
**not** the attribute. This applies to data-binding in general. Data-binding works with *properties* of DOM elements, components, and directives, not HTML *attributes*.
|
||||
|
||||
|
||||
## HTML attribute vs. DOM property
|
||||
### HTML attribute vs. DOM property
|
||||
|
||||
The distinction between an HTML attribute and a DOM property is key to understanding
|
||||
how Angular binding works. **Attributes are defined by HTML. Properties are accessed from DOM, or the Document Object Model, nodes.**
|
||||
how Angular binding works. **Attributes are defined by HTML. Properties are accessed from DOM (Document Object Model) nodes.**
|
||||
|
||||
* A few HTML attributes have 1:1 mapping to properties; for example, `id`.
|
||||
|
||||
|
@ -426,31 +414,30 @@ how Angular binding works. **Attributes are defined by HTML. Properties are acce
|
|||
|
||||
* Some DOM properties don't have corresponding attributes; for example, `textContent`.
|
||||
|
||||
This general rule can help you build a mental model of attributes and DOM properties:
|
||||
**attributes initialize DOM properties and then they are done.
|
||||
Property values can change; attribute values can't.**
|
||||
It is important to remember that *HTML attribute* and the *DOM property* are different things, even when they have the same name.
|
||||
In Angular, the only role of HTML attributes is to initialize element and directive state.
|
||||
|
||||
**Template binding works with *properties* and *events*, not *attributes*.**
|
||||
|
||||
When you write a data-binding, you're dealing exclusively with the *DOM properties* and *events* of the target object.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
There is, of course, an exception to this rule because attributes can be changed by `setAttribute()`, which will re-initialize corresponding DOM properties again.
|
||||
This general rule can help you build a mental model of attributes and DOM properties:
|
||||
**Attributes initialize DOM properties and then they are done.
|
||||
Property values can change; attribute values can't.**
|
||||
|
||||
There is one exception to this rule.
|
||||
Attributes can be changed by `setAttribute()`, which re-initializes corresponding DOM properties.
|
||||
|
||||
</div>
|
||||
|
||||
Comparing the [`<td>` attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td)
|
||||
attributes to the [`<td>` properties](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement)
|
||||
provides a helpful
|
||||
example for differentiation. In particular, you can navigate from the attributes
|
||||
page to the properties via "DOM interface" link, and navigate the inheritance
|
||||
hierarchy up to `HTMLTableCellElement`.
|
||||
|
||||
**The HTML attribute and the DOM property are not the same thing, even when they have the same name.**
|
||||
|
||||
For more information, see the [MDN Interfaces documentation](https://developer.mozilla.org/en-US/docs/Web/API#Interfaces) which has API docs for all the standard DOM elements and their properties.
|
||||
Comparing the [`<td>` attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td) attributes to the [`<td>` properties](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement) provides a helpful example for differentiation.
|
||||
In particular, you can navigate from the attributes page to the properties via "DOM interface" link, and navigate the inheritance hierarchy up to `HTMLTableCellElement`.
|
||||
|
||||
|
||||
|
||||
|
||||
### Example 1: an `<input>`
|
||||
#### Example 1: an `<input>`
|
||||
|
||||
When the browser renders `<input type="text" value="Sarah">`, it creates a
|
||||
corresponding DOM node with a `value` property initialized to "Sarah".
|
||||
|
@ -466,7 +453,7 @@ The HTML attribute `value` specifies the *initial* value; the DOM `value` proper
|
|||
|
||||
To see attributes versus DOM properties in a functioning app, see the <live-example name="binding-syntax"></live-example> especially for binding syntax.
|
||||
|
||||
### Example 2: a disabled button
|
||||
#### Example 2: a disabled button
|
||||
|
||||
The `disabled` attribute is another example. A button's `disabled`
|
||||
*property* is `false` by default so the button is enabled.
|
||||
|
@ -479,8 +466,7 @@ so the button is disabled.
|
|||
<button disabled>Test Button</button>
|
||||
```
|
||||
|
||||
Adding and removing the `disabled` *attribute* disables and
|
||||
enables the button.
|
||||
Adding and removing the `disabled` *attribute* disables and enables the button.
|
||||
However, the value of the *attribute* is irrelevant,
|
||||
which is why you cannot enable a button by writing `<button disabled="false">Still Disabled</button>`.
|
||||
|
||||
|
@ -488,7 +474,7 @@ To control the state of the button, set the `disabled` *property*,
|
|||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Note:** Though you could technically set the `[attr.disabled]` attribute binding, the values are different in that the property binding requires to a boolean value, while its corresponding attribute binding relies on whether the value is `null` or not. Consider the following:
|
||||
Though you could technically set the `[attr.disabled]` attribute binding, the values are different in that the property binding requires to a boolean value, while its corresponding attribute binding relies on whether the value is `null` or not. Consider the following:
|
||||
|
||||
```html
|
||||
<input [disabled]="condition ? true : false">
|
||||
|
@ -499,26 +485,15 @@ Generally, use property binding over attribute binding as it is more intuitive (
|
|||
|
||||
</div>
|
||||
|
||||
**The HTML attribute and the DOM property are different things, even when they have the same name.**
|
||||
|
||||
**Template binding works with *properties* and *events*, not *attributes*.**
|
||||
|
||||
To see the `disabled` button example in a functioning app, see the <live-example name="binding-syntax"></live-example> especially for binding syntax. This example shows you how to toggle the disabled property from the component.
|
||||
|
||||
|
||||
### Angular and attributes
|
||||
|
||||
In Angular, the only role of attributes is to initialize element and directive state.
|
||||
When you write a data-binding, you're dealing exclusively with properties and events of the target object.
|
||||
|
||||
|
||||
## Binding targets
|
||||
## Binding types and targets
|
||||
|
||||
The **target of a data-binding** is something in the DOM.
|
||||
Depending on the binding type, the target can be a
|
||||
property (element, component, or directive), an
|
||||
event (element, component, or directive), or sometimes an attribute name.
|
||||
The following table summarizes:
|
||||
Depending on the binding type, the target can be a property (element, component, or directive),
|
||||
an event (element, component, or directive), or sometimes an attribute name.
|
||||
The following table summarizes the targets for the different binding types.
|
||||
|
||||
<style>
|
||||
td, th {vertical-align: top}
|
||||
|
@ -678,10 +653,9 @@ 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 target
|
||||
### Binding targets
|
||||
|
||||
An element property between enclosing square brackets identifies
|
||||
the target property.
|
||||
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>
|
||||
|
@ -847,10 +821,10 @@ 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 alert("evil never sleeps")Syntax" is the property bound evil title.
|
||||
```
|
||||
</code-example>
|
||||
|
||||
<hr/>
|
||||
{@a other-bindings}
|
||||
|
@ -898,7 +872,7 @@ If you wrote something like this:
|
|||
|
||||
You'd get this error:
|
||||
|
||||
<code-example format="nocode">
|
||||
<code-example language="bash">
|
||||
Template parse errors:
|
||||
Can't bind to 'colspan' since it isn't a known native property
|
||||
</code-example>
|
||||
|
@ -968,8 +942,8 @@ The following example conditionally sets the font size in “em” and “%”
|
|||
|
||||
<code-example path="attribute-binding/src/app/app.component.html" region="style-binding-condition" header="src/app/app.component.html"></code-example>
|
||||
|
||||
**This technique is suitable for setting a single style, but consider
|
||||
the [`NgStyle`](guide/template-syntax#ngStyle) directive when setting several inline styles at the same time.**
|
||||
This technique is suitable for setting a single style, but consider
|
||||
the [`NgStyle`](guide/template-syntax#ngStyle) directive when setting several inline styles at the same time.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
@ -1156,7 +1130,7 @@ Angular desugars the `SizerComponent` binding into this:
|
|||
The `$event` variable contains the payload of the `SizerComponent.sizeChange` event.
|
||||
Angular assigns the `$event` value to the `AppComponent.fontSizePx` when the user clicks the buttons.
|
||||
|
||||
## Two-way binding in forms
|
||||
### Two-way binding in forms
|
||||
|
||||
The two-way binding syntax is a great convenience compared to
|
||||
separate property and event bindings. It would be convenient to
|
||||
|
@ -1417,7 +1391,7 @@ efficient alternative to showing/hiding.
|
|||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Note:** For more information on `NgIf` and `ngIfElse`, see the [API documentation about NgIf](api/common/NgIf).
|
||||
For more information on `NgIf` and `ngIfElse`, see the [API documentation about NgIf](api/common/NgIf).
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1448,26 +1422,20 @@ See also the
|
|||
`NgFor` is a repeater directive—a way to present a list of items.
|
||||
You define a block of HTML that defines how a single item should be displayed
|
||||
and then you tell Angular to use that block as a template for rendering each item in the list.
|
||||
The text assigned to `*ngFor` is the instruction that guides the repeater process.
|
||||
|
||||
Here is an example of `NgFor` applied to a simple `<div>`:
|
||||
The following example shows `NgFor` applied to a simple `<div>`. (Don't forget the asterisk (`*`) in front of `ngFor`.)
|
||||
|
||||
<code-example path="built-in-directives/src/app/app.component.html" region="NgFor-1" header="src/app/app.component.html"></code-example>
|
||||
|
||||
You can also apply an `NgFor` to a component element, as in this example:
|
||||
You can also apply an `NgFor` to a component element, as in the following example.
|
||||
|
||||
<code-example path="built-in-directives/src/app/app.component.html" region="NgFor-2" header="src/app/app.component.html"></code-example>
|
||||
|
||||
<div class="alert is-critical">
|
||||
|
||||
Don't forget the asterisk (`*`) in front of `ngFor`.
|
||||
|
||||
</div>
|
||||
|
||||
The text assigned to `*ngFor` is the instruction that guides the repeater process.
|
||||
|
||||
{@a microsyntax}
|
||||
|
||||
#### `*ngFor` microsyntax
|
||||
<div class="callout is-critical">
|
||||
<header>*ngFor microsyntax</header>
|
||||
|
||||
The string assigned to `*ngFor` is not a [template expression](guide/template-syntax#template-expressions). Rather,
|
||||
it's a *microsyntax*—a little language of its own that Angular interprets.
|
||||
|
@ -1479,15 +1447,15 @@ make it available to the templated HTML for each iteration.*
|
|||
Angular translates this instruction into an `<ng-template>` around the host element,
|
||||
then uses this template repeatedly to create a new set of elements and bindings for each `item`
|
||||
in the list.
|
||||
|
||||
For more information about microsyntax, see the [Structural Directives](guide/structural-directives#microsyntax) guide.
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{@a template-input-variable}
|
||||
|
||||
{@a template-input-variables}
|
||||
|
||||
|
||||
#### Template input variables
|
||||
|
||||
The `let` keyword before `item` creates a template input variable called `item`.
|
||||
|
@ -1930,7 +1898,7 @@ in the child template UI.
|
|||
|
||||
Now, in order to see the `@Output()` working, add the following to the parent's template:
|
||||
|
||||
```
|
||||
```html
|
||||
<ul>
|
||||
<li *ngFor="let item of items">{{item}}</li>
|
||||
</ul>
|
||||
|
@ -1989,7 +1957,7 @@ 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="sh" class="code-shell">
|
||||
<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>
|
||||
|
@ -2067,7 +2035,7 @@ The generated output would look something like this:
|
|||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Note**: The pipe operator has a higher precedence than the ternary operator (`?:`),
|
||||
The pipe operator has a higher precedence than the ternary operator (`?:`),
|
||||
which means `a ? b : c | x` is parsed as `a ? b : (c | x)`.
|
||||
Nevertheless, for a number of reasons,
|
||||
the pipe operator cannot be used without parentheses in the first and second operands of `?:`.
|
||||
|
@ -2097,7 +2065,7 @@ Consider the next example, with a `nullItem`.
|
|||
|
||||
Since there is no safe navigation operator and `nullItem` is `null`, JavaScript and Angular would throw a `null` reference error and break the rendering process of Angular:
|
||||
|
||||
<code-example format="nocode">
|
||||
<code-example language="bash">
|
||||
TypeError: Cannot read property 'name' of null.
|
||||
</code-example>
|
||||
|
||||
|
@ -2151,9 +2119,9 @@ The non-null assertion operator, `!`, is optional with the exception that you mu
|
|||
|
||||
### The `$any()` type cast function
|
||||
|
||||
Sometimes a binding expression triggers a type error during [AOT compilation](guide/aot-compiler) and it is not possible or difficult
|
||||
to fully specify the type. To silence the error, you can use the `$any()` cast function to cast
|
||||
the expression to [the `any` type](http://www.typescriptlang.org/docs/handbook/basic-types.html#any) as in the following example:
|
||||
Sometimes a binding expression triggers a type error during [AOT compilation](guide/aot-compiler) and it is not possible or difficult to fully specify the type.
|
||||
To silence the error, you can use the `$any()` cast function to cast
|
||||
the expression to the [`any` type](http://www.typescriptlang.org/docs/handbook/basic-types.html#any) as in the following example:
|
||||
|
||||
<code-example path="built-in-template-functions/src/app/app.component.html" region="any-type-cast-function-1" header="src/app/app.component.html"></code-example>
|
||||
|
||||
|
@ -2183,7 +2151,7 @@ Refer to the sample code snippet below for a syntax example:
|
|||
|
||||
<code-example path="template-syntax/src/app/svg.component.ts" header="src/app/svg.component.ts"></code-example>
|
||||
|
||||
Add the below code to your `svg.component.svg` file:
|
||||
Add the following code to your `svg.component.svg` file:
|
||||
|
||||
<code-example path="template-syntax/src/app/svg.component.svg" header="src/app/svg.component.svg"></code-example>
|
||||
|
||||
|
|
Loading…
Reference in New Issue