304 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			304 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
|  | # Attribute, class, and style bindings
 | ||
|  | 
 | ||
|  | The template syntax provides specialized one-way bindings for scenarios less well-suited to property binding. | ||
|  | 
 | ||
|  | <div class="alert is-helpful"> | ||
|  | 
 | ||
|  | See the <live-example></live-example> for a working example containing the code snippets in this guide. | ||
|  | 
 | ||
|  | </div> | ||
|  | 
 | ||
|  | 
 | ||
|  | ## Attribute binding
 | ||
|  | 
 | ||
|  | Set the value of an attribute directly with an **attribute binding**. This is the only exception to the rule that a binding sets a target property and the only binding that creates and sets an attribute. | ||
|  | 
 | ||
|  | Usually, setting an element property with a [property binding](guide/property-binding) | ||
|  | is preferable to setting the attribute with a string. However, sometimes | ||
|  | there is no element property to bind, so attribute binding is the solution. | ||
|  | 
 | ||
|  | Consider the [ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA) and | ||
|  | [SVG](https://developer.mozilla.org/en-US/docs/Web/SVG). They are purely attributes, don't correspond to element properties, and don't set element properties. In these cases, there are no property targets to bind to. | ||
|  | 
 | ||
|  | Attribute binding syntax resembles property binding, but | ||
|  | instead of an element property between brackets, start with the prefix `attr`, | ||
|  | followed by a dot (`.`), and the name of the attribute. | ||
|  | You then set the attribute value, using an expression that resolves to a string, | ||
|  | or remove the attribute when the expression resolves to `null`. | ||
|  | 
 | ||
|  | One of the primary use cases for attribute binding | ||
|  | is to set ARIA attributes, as in this example: | ||
|  | 
 | ||
|  | <code-example path="attribute-binding/src/app/app.component.html" region="attrib-binding-aria" header="src/app/app.component.html"></code-example> | ||
|  | 
 | ||
|  | {@a colspan} | ||
|  | 
 | ||
|  | <div class="alert is-helpful"> | ||
|  | 
 | ||
|  | #### `colspan` and `colSpan`
 | ||
|  | 
 | ||
|  | Notice the difference between the `colspan` attribute and the `colSpan` property. | ||
|  | 
 | ||
|  | If you wrote something like this: | ||
|  | 
 | ||
|  | <code-example language="html"> | ||
|  |   <tr><td colspan="{{1 + 1}}">Three-Four</td></tr> | ||
|  | </code-example> | ||
|  | 
 | ||
|  | You'd get this error: | ||
|  | 
 | ||
|  | <code-example language="bash"> | ||
|  |   Template parse errors: | ||
|  |   Can't bind to 'colspan' since it isn't a known native property | ||
|  | </code-example> | ||
|  | 
 | ||
|  | As the message says, the `<td>` element does not have a `colspan` property. This is true | ||
|  | because `colspan` is an attribute—`colSpan`, with a capital `S`, is the | ||
|  | corresponding property. Interpolation and property binding can set only *properties*, not attributes. | ||
|  | 
 | ||
|  | Instead, you'd use property binding and write it like this: | ||
|  | 
 | ||
|  | <code-example path="attribute-binding/src/app/app.component.html" region="colSpan" header="src/app/app.component.html"></code-example> | ||
|  | 
 | ||
|  | </div> | ||
|  | 
 | ||
|  | <hr/> | ||
|  | 
 | ||
|  | {@a class-binding} | ||
|  | 
 | ||
|  | ## Class binding
 | ||
|  | 
 | ||
|  | Here's how to set the `class` attribute without a binding in plain HTML: | ||
|  | 
 | ||
|  | ```html | ||
|  | <!-- standard class attribute setting --> | ||
|  | <div class="foo bar">Some text</div> | ||
|  | ``` | ||
|  | 
 | ||
|  | You can also add and remove CSS class names from an element's `class` attribute with a **class binding**. | ||
|  | 
 | ||
|  | To create a single class binding, start with the prefix `class` followed by a dot (`.`) and the name of the CSS class (for example, `[class.foo]="hasFoo"`). | ||
|  | Angular adds the class when the bound expression is truthy, and it removes the class when the expression is falsy (with the exception of `undefined`, see [styling delegation](#styling-delegation)). | ||
|  | 
 | ||
|  | To create a binding to multiple classes, use a generic `[class]` binding without the dot (for example, `[class]="classExpr"`). | ||
|  | The expression can be a space-delimited string of class names, or you can format it as an object with class names as the keys and truthy/falsy expressions as the values. | ||
|  | With object format, Angular will add a class only if its associated value is truthy. | ||
|  | 
 | ||
|  | It's important to note that with any object-like expression (`object`, `Array`, `Map`, `Set`, etc), the identity of the object must change for the class list to be updated. | ||
|  | Updating the property without changing object identity will have no effect. | ||
|  | 
 | ||
|  | If there are multiple bindings to the same class name, conflicts are resolved using [styling precedence](#styling-precedence). | ||
|  | 
 | ||
|  | <style> | ||
|  |   td, th {vertical-align: top} | ||
|  | </style> | ||
|  | 
 | ||
|  | <table width="100%"> | ||
|  |   <col width="15%"> | ||
|  |   </col> | ||
|  |   <col width="20%"> | ||
|  |   </col> | ||
|  |   <col width="35%"> | ||
|  |   </col> | ||
|  |   <col width="30%"> | ||
|  |   </col> | ||
|  |   <tr> | ||
|  |     <th> | ||
|  |       Binding Type | ||
|  |     </th> | ||
|  |     <th> | ||
|  |       Syntax | ||
|  |     </th> | ||
|  |     <th> | ||
|  |       Input Type | ||
|  |     </th> | ||
|  |     <th> | ||
|  |       Example Input Values | ||
|  |     </th> | ||
|  |   </tr> | ||
|  |   <tr> | ||
|  |     <td>Single class binding</td> | ||
|  |     <td><code>[class.foo]="hasFoo"</code></td> | ||
|  |     <td><code>boolean | undefined | null</code></td> | ||
|  |     <td><code>true</code>, <code>false</code></td> | ||
|  |   </tr> | ||
|  |   <tr> | ||
|  |     <td rowspan=3>Multi-class binding</td> | ||
|  |     <td rowspan=3><code>[class]="classExpr"</code></td> | ||
|  |     <td><code>string</code></td> | ||
|  |     <td><code>"my-class-1 my-class-2 my-class-3"</code></td> | ||
|  |   </tr> | ||
|  |   <tr> | ||
|  |     <td><code>{[key: string]: boolean | undefined | null}</code></td> | ||
|  |     <td><code>{foo: true, bar: false}</code></td> | ||
|  |   </tr> | ||
|  |   <tr> | ||
|  |     <td><code>Array</code><<code>string</code>></td> | ||
|  |     <td><code>['foo', 'bar']</code></td> | ||
|  |   </tr> | ||
|  | </table> | ||
|  | 
 | ||
|  | 
 | ||
|  | The [NgClass](guide/built-in-directives/#ngclass) directive can be used as an alternative to direct `[class]` bindings. | ||
|  | However, using the above class binding syntax without `NgClass` is preferred because due to improvements in class binding in Angular, `NgClass` no longer provides significant value, and might eventually be removed in the future. | ||
|  | 
 | ||
|  | 
 | ||
|  | <hr/> | ||
|  | 
 | ||
|  | ## Style binding
 | ||
|  | 
 | ||
|  | Here's how to set the `style` attribute without a binding in plain HTML: | ||
|  | 
 | ||
|  | ```html | ||
|  | <!-- standard style attribute setting --> | ||
|  | <div style="color: blue">Some text</div> | ||
|  | ``` | ||
|  | 
 | ||
|  | You can also set styles dynamically with a **style binding**. | ||
|  | 
 | ||
|  | To create a single style binding, start with the prefix `style` followed by a dot (`.`) and the name of the CSS style property (for example, `[style.width]="width"`). | ||
|  | The property will be set to the value of the bound expression, which is normally a string. | ||
|  | Optionally, you can add a unit extension like `em` or `%`, which requires a number type. | ||
|  | 
 | ||
|  | <div class="alert is-helpful"> | ||
|  | 
 | ||
|  | Note that a _style property_ name can be written in either | ||
|  | [dash-case](guide/glossary#dash-case), as shown above, or | ||
|  | [camelCase](guide/glossary#camelcase), such as `fontSize`. | ||
|  | 
 | ||
|  | </div> | ||
|  | 
 | ||
|  | If there are multiple styles you'd like to toggle, you can bind to the `[style]` property directly without the dot (for example, `[style]="styleExpr"`). | ||
|  | The expression attached to the `[style]` binding is most often a string list of styles like `"width: 100px; height: 100px;"`. | ||
|  | 
 | ||
|  | You can also format the expression as an object with style names as the keys and style values as the values, like `{width: '100px', height: '100px'}`. | ||
|  | It's important to note that with any object-like expression (`object`, `Array`, `Map`, `Set`, etc), the identity of the object must change for the class list to be updated. | ||
|  | Updating the property without changing object identity will have no effect. | ||
|  | 
 | ||
|  | If there are multiple bindings to the same style property, conflicts are resolved using [styling precedence rules](#styling-precedence). | ||
|  | 
 | ||
|  | <style> | ||
|  |   td, th {vertical-align: top} | ||
|  | </style> | ||
|  | 
 | ||
|  | <table width="100%"> | ||
|  |   <col width="15%"> | ||
|  |   </col> | ||
|  |   <col width="20%"> | ||
|  |   </col> | ||
|  |   <col width="35%"> | ||
|  |   </col> | ||
|  |   <col width="30%"> | ||
|  |   </col> | ||
|  |   <tr> | ||
|  |     <th> | ||
|  |       Binding Type | ||
|  |     </th> | ||
|  |     <th> | ||
|  |       Syntax | ||
|  |     </th> | ||
|  |     <th> | ||
|  |       Input Type | ||
|  |     </th> | ||
|  |     <th> | ||
|  |       Example Input Values | ||
|  |     </th> | ||
|  |   </tr> | ||
|  |   <tr> | ||
|  |     <td>Single style binding</td> | ||
|  |     <td><code>[style.width]="width"</code></td> | ||
|  |     <td><code>string | undefined | null</code></td> | ||
|  |     <td><code>"100px"</code></td> | ||
|  |   </tr> | ||
|  |   <tr> | ||
|  |   <tr> | ||
|  |     <td>Single style binding with units</td> | ||
|  |     <td><code>[style.width.px]="width"</code></td> | ||
|  |     <td><code>number | undefined | null</code></td> | ||
|  |     <td><code>100</code></td> | ||
|  |   </tr> | ||
|  |     <tr> | ||
|  |     <td rowspan=3>Multi-style binding</td> | ||
|  |     <td rowspan=3><code>[style]="styleExpr"</code></td> | ||
|  |     <td><code>string</code></td> | ||
|  |     <td><code>"width: 100px; height: 100px"</code></td> | ||
|  |   </tr> | ||
|  |   <tr> | ||
|  |     <td><code>{[key: string]: string | undefined | null}</code></td> | ||
|  |     <td><code>{width: '100px', height: '100px'}</code></td> | ||
|  |   </tr> | ||
|  |   <tr> | ||
|  |     <td><code>Array</code><<code>string</code>></td> | ||
|  |     <td><code>['width', '100px']</code></td> | ||
|  |   </tr> | ||
|  | </table> | ||
|  | 
 | ||
|  | The [NgStyle](guide/built-in-directives/#ngstyle) directive can be used as an alternative to direct `[style]` bindings. | ||
|  | However, using the above style binding syntax without `NgStyle` is preferred because due to improvements in style binding in Angular, `NgStyle` no longer provides significant value, and might eventually be removed in the future. | ||
|  | 
 | ||
|  | 
 | ||
|  | <hr/> | ||
|  | 
 | ||
|  | {@a styling-precedence} | ||
|  | 
 | ||
|  | ## Styling Precedence
 | ||
|  | 
 | ||
|  | A single HTML element can have its CSS class list and style values bound to multiple sources (for example, host bindings from multiple directives). | ||
|  | 
 | ||
|  | When there are multiple bindings to the same class name or style property, Angular uses a set of precedence rules to resolve conflicts and determine which classes or styles are ultimately applied to the element. | ||
|  | 
 | ||
|  | <div class="alert is-helpful"> | ||
|  | <h4>Styling precedence (highest to lowest)</h4> | ||
|  | 
 | ||
|  | 1. Template bindings | ||
|  |     1. Property binding (for example, `<div [class.foo]="hasFoo">` or `<div [style.color]="color">`) | ||
|  |     1. Map binding (for example, `<div [class]="classExpr">` or `<div [style]="styleExpr">`) | ||
|  |     1. Static value (for example, `<div class="foo">` or `<div style="color: blue">`) | ||
|  | 1. Directive host bindings | ||
|  |     1. Property binding (for example, `host: {'[class.foo]': 'hasFoo'}` or `host: {'[style.color]': 'color'}`) | ||
|  |     1. Map binding (for example, `host: {'[class]': 'classExpr'}` or `host: {'[style]': 'styleExpr'}`) | ||
|  |     1. Static value (for example, `host: {'class': 'foo'}` or `host: {'style': 'color: blue'}`) | ||
|  | 1. Component host bindings | ||
|  |     1. Property binding (for example, `host: {'[class.foo]': 'hasFoo'}` or `host: {'[style.color]': 'color'}`) | ||
|  |     1. Map binding (for example, `host: {'[class]': 'classExpr'}` or `host: {'[style]': 'styleExpr'}`) | ||
|  |     1. Static value (for example, `host: {'class': 'foo'}` or `host: {'style': 'color: blue'}`) | ||
|  | 
 | ||
|  | </div> | ||
|  | 
 | ||
|  | The more specific a class or style binding is, the higher its precedence. | ||
|  | 
 | ||
|  | A binding to a specific class (for example, `[class.foo]`) will take precedence over a generic `[class]` binding, and a binding to a specific style (for example, `[style.bar]`) will take precedence over a generic `[style]` binding. | ||
|  | 
 | ||
|  | <code-example path="attribute-binding/src/app/app.component.html" region="basic-specificity" header="src/app/app.component.html"></code-example> | ||
|  | 
 | ||
|  | Specificity rules also apply when it comes to bindings that originate from different sources. | ||
|  | It's possible for an element to have bindings in the template where it's declared, from host bindings on matched directives, and from host bindings on matched components. | ||
|  | 
 | ||
|  | Template bindings are the most specific because they apply to the element directly and exclusively, so they have the highest precedence. | ||
|  | 
 | ||
|  | Directive host bindings are considered less specific because directives can be used in multiple locations, so they have a lower precedence than template bindings. | ||
|  | 
 | ||
|  | Directives often augment component behavior, so host bindings from components have the lowest precedence. | ||
|  | 
 | ||
|  | <code-example path="attribute-binding/src/app/app.component.html" region="source-specificity" header="src/app/app.component.html"></code-example> | ||
|  | 
 | ||
|  | In addition, bindings take precedence over static attributes. | ||
|  | 
 | ||
|  | In the following case, `class` and `[class]` have similar specificity, but the `[class]` binding will take precedence because it is dynamic. | ||
|  | 
 | ||
|  | <code-example path="attribute-binding/src/app/app.component.html" region="dynamic-priority" header="src/app/app.component.html"></code-example> | ||
|  | 
 | ||
|  | {@a styling-delegation} | ||
|  | ### Delegating to styles with lower precedence
 | ||
|  | 
 | ||
|  | It is possible for higher precedence styles to "delegate" to lower precedence styles using `undefined` values. | ||
|  | Whereas setting a style property to `null` ensures the style is removed, setting it to `undefined` will cause Angular to fall back to the next-highest precedence binding to that style. | ||
|  | 
 | ||
|  | For example, consider the following template: | ||
|  | 
 | ||
|  | <code-example path="attribute-binding/src/app/app.component.html" region="style-delegation" header="src/app/app.component.html"></code-example> | ||
|  | 
 | ||
|  | Imagine that the `dirWithHostBinding` directive and the `comp-with-host-binding` component both have a `[style.width]` host binding. | ||
|  | In that case, if `dirWithHostBinding` sets its binding to `undefined`, the `width` property will fall back to the value of the `comp-with-host-binding` host binding. | ||
|  | However, if `dirWithHostBinding` sets its binding to `null`, the `width` property will be removed entirely. |