diff --git a/aio/angular.json b/aio/angular.json
index 28e22467a8..222b569341 100644
--- a/aio/angular.json
+++ b/aio/angular.json
@@ -5,7 +5,8 @@
"packageManager": "yarn",
"warnings": {
"typescriptMismatch": false
- }
+ },
+ "analytics": false
},
"newProjectRoot": "projects",
"projects": {
@@ -192,4 +193,4 @@
}
},
"defaultProject": "site"
-}
+}
\ No newline at end of file
diff --git a/aio/content/examples/attribute-binding/e2e/src/app.e2e-spec.ts b/aio/content/examples/attribute-binding/e2e/src/app.e2e-spec.ts
index c02fa87e1b..95281656a9 100644
--- a/aio/content/examples/attribute-binding/e2e/src/app.e2e-spec.ts
+++ b/aio/content/examples/attribute-binding/e2e/src/app.e2e-spec.ts
@@ -25,23 +25,12 @@ describe('Attribute binding example', function () {
});
it('should display a blue div with a red border', function () {
- expect(element.all(by.css('div')).get(4).getCssValue('border')).toEqual('2px solid rgb(212, 30, 46)');
+ expect(element.all(by.css('div')).get(1).getCssValue('border')).toEqual('2px solid rgb(212, 30, 46)');
});
- it('should display a div with replaced classes', function () {
- expect(element.all(by.css('div')).get(5).getAttribute('class')).toEqual('new-class');
- });
-
- it('should display four buttons', function() {
- let redButton = element.all(by.css('button')).get(1);
- let saveButton = element.all(by.css('button')).get(2);
- let bigButton = element.all(by.css('button')).get(3);
- let smallButton = element.all(by.css('button')).get(4);
-
- expect(redButton.getCssValue('color')).toEqual('rgba(255, 0, 0, 1)');
- expect(saveButton.getCssValue('background-color')).toEqual('rgba(0, 255, 255, 1)');
- expect(bigButton.getText()).toBe('Big');
- expect(smallButton.getText()).toBe('Small');
+ it('should display a div with many classes', function () {
+ expect(element.all(by.css('div')).get(1).getAttribute('class')).toContain('special');
+ expect(element.all(by.css('div')).get(1).getAttribute('class')).toContain('clearance');
});
});
diff --git a/aio/content/examples/attribute-binding/src/app/app.component.html b/aio/content/examples/attribute-binding/src/app/app.component.html
index 20f7ca2add..69f82857fd 100644
--- a/aio/content/examples/attribute-binding/src/app/app.component.html
+++ b/aio/content/examples/attribute-binding/src/app/app.component.html
@@ -27,43 +27,41 @@
This class binding is special.
-
+
+Some text.
-
+
+Some text.
+
-This class binding is special too.
-
+
+Some text.
-Some text.
-
-` will be `"item clearance special"` if `isSpecial` is truthy, and only `"item clearance"` if it is falsy.
+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.
-You can also use the alternative class binding syntax that replaces square brackets with the `bind-` keyword:
-
-
-
-If there are multiple classes you'd like to toggle, you can bind to the `[class]` property directly.
-Binding to `[class]` is additive, so it shouldn't overwrite other class bindings or static classes unless the class names are duplicated*.
-
-
-
-The expression attached to the `[class]` binding is most often a string list of class names like `"clearance special"`.
-
-You can also format the expression as an object with class names as the keys and truthy/falsy expressions as the values, like `{clearance: true, special: false}`.
-In this case, Angular will add a class only if its associated value is truthy.
-It's important to note that with object format, the identity of the object must change for the class list to be updated.
+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.
-*This is true for Angular version 9 and later. For Angular version 8, see
v8.angular.io
+If there are multiple bindings to the same class name, conflicts are resolved using [styling precedence](#styling-precedence).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Binding Type
+ |
+
+ Syntax
+ |
+
+ Input Type
+ |
+
+ Example Input Values
+ |
+
+
+ Single class binding |
+ [class.foo]="hasFoo" |
+ boolean | undefined | null |
+ true , false |
+
+
+ Multi-class binding |
+ [class]="classExpr" |
+ string |
+ "my-class-1 my-class-2 my-class-3" |
+
+
+ {[key: string]: boolean | undefined | null} |
+ {foo: true, bar: false} |
+
+
+ Array <string > |
+ ['foo', 'bar'] |
+
+
+
+
+The [NgClass](#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.
+
### Style binding
-Here's how to set the style attribute without a binding in plain HTML:
+Here's how to set the `style` attribute without a binding in plain HTML:
```html
-
Item clearance special
+
Some text
```
-You can set styles dynamically with a **style binding**.
+You can also set styles dynamically with a **style binding**.
-Style binding syntax resembles property binding.
-Instead of an element property between brackets, start with the prefix `style`,
-followed by a dot (`.`) and the name of a CSS style property: `[style.style-property]`.
-
-
-
-Some style binding styles have a unit extension.
-The following example conditionally sets the font size in “em” and “%” units.
-
-
+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.
@@ -963,22 +992,140 @@ Note that a _style property_ name can be written in either
-If there are multiple styles you'd like to toggle, you can bind to the `[style]` property directly.
-Binding to `[style]` is additive, so it shouldn't overwrite other style bindings or static styles unless the same style property is duplicated.
-
-
-
+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 object format, the identity of the object must change for the styles to be updated.
+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.
-*This is true for Angular version 9 and later. For Angular version 8, see
v8.angular.io
+If there are multiple bindings to the same style property, conflicts are resolved using [styling precedence rules](#styling-precedence).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Binding Type
+ |
+
+ Syntax
+ |
+
+ Input Type
+ |
+
+ Example Input Values
+ |
+
+
+ Single style binding |
+ [style.width]="width" |
+ string | undefined | null |
+ "100px" |
+
+
+
+ Single style binding with units |
+ [style.width.px]="width" |
+ number | undefined | null |
+ 100 |
+
+
+ Multi-style binding |
+ [style]="styleExpr" |
+ string |
+ "width: 100px; height: 100px" |
+
+
+ {[key: string]: string | undefined | null} |
+ {width: '100px', height: '100px'} |
+
+
+ Array <string > |
+ ['width', '100px'] |
+
+
+
+The [NgStyle](#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.
+{@a styling-precedence}
+### Styling Precedence
+
+A single HTML element can have its CSS class list and style values bound to a 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.
+
+
+
Styling precedence (highest to lowest)
+
+1. Template bindings
+ 1. Property binding (for example, `
` or `
`)
+ 1. Map binding (for example, `
` or `
`)
+ 1. Static value (for example, `
` or `
`)
+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'}`)
+
+
+
+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.
+
+
+
+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.
+
+
+
+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.
+
+
+
+{@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:
+
+
+
+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.
+
+
{@a event-binding}
## Event binding `(event)`