docs: smooth out directives guide narrative flow (#69822)

PR Close #69822
This commit is contained in:
Ben Hong
2026-06-08 13:48:32 -04:00
committed by Alex Rickabaugh
parent 433276b12d
commit fe35cbd320
2 changed files with 149 additions and 191 deletions
@@ -1,38 +1,95 @@
# Attribute directives
Change the appearance or behavior of DOM elements and Angular components with attribute directives.
Attribute directives change the appearance or behavior of DOM elements and Angular components.
## Built-in attribute directives
Angular includes several built-in attribute directives for common tasks:
| Common directives | Details |
| :----------------------------------------------------- | :------------------------------------------------- |
| [`NgClass`](#adding-and-removing-classes-with-ngclass) | Adds and removes a set of CSS classes. |
| [`NgStyle`](#setting-inline-styles-with-ngstyle) | Adds and removes a set of HTML styles. |
| [`NgModel`](guide/forms/template-driven-forms) | Adds two-way data binding to an HTML form element. |
HELPFUL: Built-in directives use only public APIs. They do not have special access to any private APIs that other directives can't access.
### Adding and removing classes with `NgClass`
Add or remove multiple CSS classes simultaneously by binding `[ngClass]` to an expression. To use `NgClass`, add it to the component's `imports` list:
```angular-ts
import {NgClass} from '@angular/common';
@Component({
/* ... */
imports: [NgClass],
})
export class AppComponent {}
```
To toggle a single class, bind `[ngClass]` to a conditional expression that returns the class name. In this example, `ngClass` applies the `special` class when `isSpecial` is `true`:
<docs-code header="app.component.html" path="adev/src/content/examples/built-in-directives/src/app/app.component.html" region="special-div"/>
To toggle several classes at once, bind `[ngClass]` to an object. Each key is a class name, and Angular adds the class when its value is truthy and removes it when its value is falsy:
```angular-html
<div [ngClass]="{'saveable': canSave, 'modified': !isUnchanged, 'special': isSpecial}">
This div's classes reflect the current component state.
</div>
```
HELPFUL: To add or remove a _single_ class, use [class binding](/guide/templates/binding#css-class-and-style-property-bindings) rather than `NgClass`.
### Setting inline styles with `NgStyle`
Set multiple inline styles simultaneously by binding `[ngStyle]` to an object. To use `NgStyle`, add it to the component's `imports` list:
```angular-ts
import {NgStyle} from '@angular/common';
@Component({
/* ... */
imports: [NgStyle],
})
export class AppComponent {}
```
Each key in the object is a CSS property name and each value is the style to apply:
```angular-html
<div
[ngStyle]="{
'font-style': canSave ? 'italic' : 'normal',
'font-weight': !isUnchanged ? 'bold' : 'normal',
'font-size': isSpecial ? '24px' : '12px',
}"
>
This div's styles reflect the current component state.
</div>
```
HELPFUL: To add or remove a _single_ style, use [style bindings](guide/templates/binding#css-class-and-style-property-bindings) rather than `NgStyle`.
## Building an attribute directive
This section walks you through creating a highlight directive that sets the background color of the host element to yellow.
A custom attribute directive is a class with the `@Directive()` decorator. The decorator's `selector` defines the attribute that applies the directive. By convention, custom selectors use a prefix such as `app` and wrap the name in square brackets to form an attribute selector:
1. To create a directive, use the CLI command [`ng generate directive`](tools/cli/schematics).
```angular-ts
import {Directive} from '@angular/core';
```shell
ng generate directive highlight
```
@Directive({
selector: '[appHighlight]',
})
export class HighlightDirective {}
```
The CLI creates `src/app/highlight.directive.ts`, a corresponding test file `src/app/highlight.directive.spec.ts`.
HELPFUL: The CLI command [`ng generate directive`](tools/cli/schematics) scaffolds a directive along with its test file.
```angular-ts
import {Directive} from '@angular/core';
To change the host element, a directive needs a reference to it. Inject [`ElementRef`](guide/di) to reach the element through its `nativeElement` property. This directive sets the background to yellow when Angular creates it:
@Directive({
selector: '[appHighlight]',
})
export class HighlightDirective {}
```
The `@Directive()` decorator's configuration property specifies the directive's CSS attribute selector, `[appHighlight]`.
1. Import `ElementRef` and `inject` from `@angular/core`.
`ElementRef` grants direct access to the host DOM element through its `nativeElement` property.
1. Use [`inject`](guide/di) to obtain a reference to the host DOM element, the element to which you apply `appHighlight`.
1. Add logic to the `HighlightDirective` class that sets the background to yellow.
<docs-code header="highlight.directive.ts" path="adev/src/content/examples/attribute-directives/src/app/highlight.directive.1.ts"/>
<docs-code header="highlight.directive.ts" path="adev/src/content/examples/attribute-directives/src/app/highlight.directive.1.ts"/>
IMPORTANT: Directives _do not_ support namespaces.
@@ -42,104 +99,43 @@ IMPORTANT: Directives _do not_ support namespaces.
## Applying an attribute directive
To use the `HighlightDirective`, add a `<p>` element to the HTML template with the directive as an attribute.
To apply the directive, add its selector as an attribute on an element:
<docs-code header="app.component.html" path="adev/src/content/examples/attribute-directives/src/app/app.component.1.html" region="applied"/>
Angular creates an instance of the `HighlightDirective` class, which uses `inject(ElementRef)` to get a reference to the `<p>` element and set its background style to yellow.
Angular creates an instance of `HighlightDirective` for that `<p>` element, injects a reference to the element, and sets its background to yellow.
## Handling user events
This section shows you how to detect when a user mouses into or out of the element and to respond by setting or clearing the highlight color.
1. Configure host event bindings using the `host` property in the `@Directive()` decorator.
<docs-code header="src/app/highlight.directive.ts (decorator)" path="adev/src/content/examples/attribute-directives/src/app/highlight.directive.2.ts" region="decorator"/>
1. Add two event handler methods, and map host element events to them via the `host` property.
<docs-code header="highlight.directive.ts (mouse-methods)" path="adev/src/content/examples/attribute-directives/src/app/highlight.directive.2.ts" region="mouse-methods"/>
Subscribe to events of the DOM element that hosts an attribute directive (the `<p>` in this case) by configuring event listeners on the directive's [`host` property](guide/components/host-elements#binding-to-the-host-element).
HELPFUL: The handlers delegate to a helper method, `highlight()`, that sets the color on the host DOM element, `el`.
The complete directive is as follows:
To respond to user interaction, bind host element events to handler methods through the `host` property of the `@Directive()` decorator. The following directive highlights the host element while the pointer is over it and clears the highlight when the pointer leaves:
<docs-code header="highlight.directive.ts" path="adev/src/content/examples/attribute-directives/src/app/highlight.directive.2.ts"/>
The background color appears when the pointer hovers over the paragraph element and disappears as the pointer moves out.
The `host` property maps the `mouseenter` and `mouseleave` events to the `onMouseEnter()` and `onMouseLeave()` methods, which delegate to a `highlight()` helper that sets the background color on the host element. For more on host event bindings, see [binding to the host element](guide/components/host-elements#binding-to-the-host-element).
<img alt="Second Highlight" src="assets/images/guide/attribute-directives/highlight-directive-anim.gif">
## Passing values into an attribute directive
## Accepting input values
This section walks you through setting the highlight color while applying the `HighlightDirective`.
Like components, directives accept inputs through the [`input()`](guide/components/inputs) function. Give an input the same name as the selector so that a single binding both applies the directive and passes a value to it:
1. In `highlight.directive.ts`, import `input` from `@angular/core`.
<docs-code header="highlight.directive.ts" path="adev/src/content/examples/attribute-directives/src/app/highlight.directive.3.ts" region="input"/>
<docs-code header="highlight.directive.ts (imports)" path="adev/src/content/examples/attribute-directives/src/app/highlight.directive.3.ts" region="imports"/>
Read the input by calling its signal, and fall back to a default when no value is bound:
1. Add an `appHighlight` `input` property.
<docs-code header="highlight.directive.ts" path="adev/src/content/examples/attribute-directives/src/app/highlight.directive.3.ts" region="mouse-enter"/>
<docs-code header="highlight.directive.ts" path="adev/src/content/examples/attribute-directives/src/app/highlight.directive.3.ts" region="input"/>
In the template, bind the value to the selector. Because the input shares the selector's name, `[appHighlight]` both applies the directive and sets its value:
The `input()` function adds metadata to the class that makes the directive's `appHighlight` property available for binding.
<docs-code header="app.component.html" path="adev/src/content/examples/attribute-directives/src/app/app.component.html" region="color"/>
1. In `app.component.ts`, add a `color` property to the `AppComponent`.
A directive can declare more than one input. The following directive adds a `defaultColor` input, then falls back through `appHighlight`, `defaultColor`, and finally `red`:
<docs-code header="app.component.ts (class)" path="adev/src/content/examples/attribute-directives/src/app/app.component.1.ts" region="class"/>
<docs-code header="highlight.directive.ts" path="adev/src/content/examples/attribute-directives/src/app/highlight.directive.ts"/>
1. To simultaneously apply the directive and the color, use property binding with the `appHighlight` directive selector, setting it equal to `color`.
Bind both inputs on the same element. Because `defaultColor` takes a static string rather than a dynamic expression, it doesn't need square brackets:
<docs-code header="app.component.html (color)" path="adev/src/content/examples/attribute-directives/src/app/app.component.html" region="color"/>
The `[appHighlight]` attribute binding performs two tasks:
- Applies the highlighting directive to the `<p>` element
- Sets the directive's highlight color with a property binding
### Setting the value with user input
This section guides you through adding radio buttons to bind your color choice to the `appHighlight` directive.
1. Add markup to `app.component.html` for choosing a color as follows:
<docs-code header="app.component.html (v2)" path="adev/src/content/examples/attribute-directives/src/app/app.component.html" region="v2"/>
2. Revise the `AppComponent.color` so that it has no initial value.
<docs-code header="app.component.ts (class)" path="adev/src/content/examples/attribute-directives/src/app/app.component.ts" region="class"/>
3. In `highlight.directive.ts`, revise `onMouseEnter` method so that it first tries to highlight with `appHighlight` and falls back to `red` if `appHighlight` is `undefined`.
<docs-code header="highlight.directive.ts (mouse-enter)" path="adev/src/content/examples/attribute-directives/src/app/highlight.directive.3.ts" region="mouse-enter"/>
4. Serve your application to verify that the user can choose the color with the radio buttons.
<img alt="Animated gif of the refactored highlight directive changing color according to the radio button the user selects" src="assets/images/guide/attribute-directives/highlight-directive-v2-anim.gif">
## Binding to a second property
This section guides you through configuring your application so the developer can set the default color.
1. Add a second `input()` property to `HighlightDirective` called `defaultColor`.
<docs-code header="highlight.directive.ts (defaultColor)" path="adev/src/content/examples/attribute-directives/src/app/highlight.directive.ts" region="defaultColor"/>
2. Revise the directive's `onMouseEnter` so that it first tries to highlight with the `appHighlight`, then with the `defaultColor`, and falls back to `red` if both properties are `undefined`.
<docs-code header="highlight.directive.ts (mouse-enter)" path="adev/src/content/examples/attribute-directives/src/app/highlight.directive.ts" region="mouse-enter"/>
3. To bind to the `AppComponent.color` and fall back to "violet" as the default color, add the following HTML.
In this case, the `defaultColor` binding doesn't use square brackets, `[]`, because the value is a static string, not a dynamic expression.
<docs-code header="app.component.html (defaultColor)" path="adev/src/content/examples/attribute-directives/src/app/app.component.html" region="defaultColor"/>
As with components, you can add multiple directive property bindings to a host element.
The default color is red if there is no default color binding.
When the user chooses a color the selected color becomes the active highlight color.
<img alt="Animated gif of final highlight directive that shows red color with no binding and violet with the default color set. When user selects color, the selection takes precedence." src="assets/images/guide/attribute-directives/highlight-directive-final-anim.gif">
<docs-code header="app.component.html" path="adev/src/content/examples/attribute-directives/src/app/app.component.html" region="defaultColor"/>
## Deactivating Angular processing with `NgNonBindable`
@@ -157,3 +153,10 @@ In the following example, the `appHighlight` directive is still active but Angul
<docs-code header="app.component.html" path="adev/src/content/examples/attribute-directives/src/app/app.component.html" region="ngNonBindable-with-directive"/>
If you apply `ngNonBindable` to a parent element, Angular disables interpolation and binding of any sort, such as property binding or event binding, for the element's children.
## What's next
<docs-pill-row>
<docs-pill href="guide/directives/structural-directives" title="Structural directives"/>
<docs-pill href="guide/directives/directive-composition-api" title="Directive composition API"/>
</docs-pill-row>
+45 -90
View File
@@ -1,118 +1,73 @@
<docs-decorative-header title="Built-in directives" imgSrc="adev/src/assets/images/directives.svg"> <!-- markdownlint-disable-line -->
Directives are classes that add additional behavior to elements in your Angular applications.
<docs-decorative-header title="Directives" imgSrc="adev/src/assets/images/directives.svg"> <!-- markdownlint-disable-line -->
Directives add behavior to elements and components in your Angular applications.
</docs-decorative-header>
Use Angular's built-in directives to manage forms, lists, styles, and what users see.
A directive can change how an element looks, how it behaves, or how it fits into the DOM. Angular ships with several built-in directives, and you can write your own.
The different types of Angular directives are as follows:
## When to use a directive
| Directive Types | Details |
| :--------------------------------------------------------------- | :-------------------------------------------------------------------------------- |
| [Components](guide/components) | Used with a template. This type of directive is the most common directive type. |
| [Attribute directives](#built-in-attribute-directives) | Change the appearance or behavior of an element, component, or another directive. |
| [Structural directives](/guide/directives/structural-directives) | Change the DOM layout by adding and removing DOM elements. |
Directives are most effective when they encapsulate **reusable** behavior that you want to apply to an existing element or component.
This guide covers built-in [attribute directives](#built-in-attribute-directives).
Common examples include:
## Built-in attribute directives
- Applying the same appearance or behavior across many elements, such as autofocus or a tooltip.
- Reading from or writing to the host element's DOM, attributes, or classes.
- Adding behavior to a component you don't own without changing its source.
Attribute directives listen to and modify the behavior of other HTML elements, attributes, properties, and components.
If you need to render your own markup or manage a piece of UI with its own template, reach for a [component](guide/components) rather than a directive.
The most common attribute directives are as follows:
## A quick example
| Common directives | Details |
| :----------------------------------------------------- | :------------------------------------------------- |
| [`NgClass`](#adding-and-removing-classes-with-ngclass) | Adds and removes a set of CSS classes. |
| [`NgStyle`](#setting-inline-styles-with-ngstyle) | Adds and removes a set of HTML styles. |
| [`NgModel`](guide/forms/template-driven-forms) | Adds two-way data binding to an HTML form element. |
Suppose you want elements to highlight when the user hovers over them, changing their background color to yellow. Rather than repeat the same event-handling logic on every element, you can package that behavior in a directive and apply it wherever you need it.
HELPFUL: Built-in directives use only public APIs. They do not have special access to any private APIs that other directives can't access.
## Adding and removing classes with `NgClass`
Add or remove multiple CSS classes simultaneously with `ngClass`.
HELPFUL: To add or remove a _single_ class, use [class binding](/guide/templates/binding#css-class-and-style-property-bindings) rather than `NgClass`.
### Import `NgClass` in the component
To use `NgClass`, add it to the component's `imports` list.
The following `appHighlight` directive sets the host element's background color when the pointer enters and clears it when the pointer leaves:
```angular-ts
import {NgClass} from '@angular/common';
import {Directive, ElementRef, inject} from '@angular/core';
@Component({
/* ... */
imports: [NgClass],
@Directive({
selector: '[appHighlight]',
host: {
'(mouseenter)': 'onMouseEnter()',
'(mouseleave)': 'onMouseLeave()',
},
})
export class AppComponent {}
export class HighlightDirective {
private el = inject(ElementRef);
onMouseEnter() {
this.el.nativeElement.style.backgroundColor = 'yellow';
}
onMouseLeave() {
this.el.nativeElement.style.backgroundColor = '';
}
}
```
### Using `NgClass` with an expression
Apply the directive by adding its selector as an attribute on an element:
On the element you'd like to style, add `[ngClass]` and set it equal to an expression.
In this case, `isSpecial` is a boolean set to `true` in `app.component.ts`.
Because `isSpecial` is true, `ngClass` applies the class of `special` to the `<div>`.
<docs-code header="app.component.html" path="adev/src/content/examples/built-in-directives/src/app/app.component.html" region="special-div"/>
### Using `NgClass` with a method
1. To use `NgClass` with a method, add the method to the component class.
In the following example, `setCurrentClasses()` sets the property `currentClasses` with an object that adds or removes three classes based on the `true` or `false` state of three other component properties.
Each key of the object is a CSS class name.
If a key is `true`, `ngClass` adds the class.
If a key is `false`, `ngClass` removes the class.
<docs-code header="app.component.ts" path="adev/src/content/examples/built-in-directives/src/app/app.component.ts" region="setClasses"/>
1. In the template, add the `ngClass` property binding to `currentClasses` to set the element's classes:
<docs-code header="app.component.html" path="adev/src/content/examples/built-in-directives/src/app/app.component.html" region="NgClass-1"/>
For this use case, Angular applies the classes on initialization and in case of changes caused by reassigning the `currentClasses` object.
The full example calls `setCurrentClasses()` initially with `ngOnInit()` when the user clicks on the `Refresh currentClasses` button.
These steps are not necessary to implement `ngClass`.
## Setting inline styles with `NgStyle`
HELPFUL: To add or remove a _single_ style, use [style bindings](guide/templates/binding#css-class-and-style-property-bindings) rather than `NgStyle`.
### Import `NgStyle` in the component
To use `NgStyle`, add it to the component's `imports` list.
```angular-ts
import {NgStyle} from '@angular/common';
@Component({
/* ... */
imports: [NgStyle],
})
export class AppComponent {}
```angular-html
<p appHighlight>Highlight me!</p>
```
Use `NgStyle` to set multiple inline styles simultaneously, based on the state of the component.
Every element that carries the `appHighlight` attribute gains the same hover behavior, with the logic defined in one place.
1. To use `NgStyle`, add a method to the component class.
## Types of directives
In the following example, `setCurrentStyles()` sets the property `currentStyles` with an object that defines three styles, based on the state of three other component properties.
Angular has two primary types of directives:
<docs-code header="app.component.ts" path="adev/src/content/examples/built-in-directives/src/app/app.component.ts" region="setStyles"/>
1. To set the element's styles, add an `ngStyle` property binding to `currentStyles`.
<docs-code header="app.component.html" path="adev/src/content/examples/built-in-directives/src/app/app.component.html" region="NgStyle-2"/>
For this use case, Angular applies the styles upon initialization and in case of changes.
To do this, the full example calls `setCurrentStyles()` initially with `ngOnInit()` and when the dependent properties change through a button click.
However, these steps are not necessary to implement `ngStyle` on its own.
| Directive type | Details |
| :-------------------------------------------------------------- | :-------------------------------------------------------------------------------- |
| [Attribute directives](guide/directives/attribute-directives) | Change the appearance or behavior of an element, component, or another directive. |
| [Structural directives](guide/directives/structural-directives) | Change the DOM layout by adding and removing DOM elements. |
## What's next
Learn more about each type of directive in the following guides.
<docs-pill-row>
<docs-pill href="guide/directives/attribute-directives" title="Attribute Directives"/>
<docs-pill href="guide/directives/structural-directives" title="Structural Directives"/>
<docs-pill href="guide/directives/attribute-directives" title="Attribute directives"/>
<docs-pill href="guide/directives/structural-directives" title="Structural directives"/>
<docs-pill href="guide/directives/directive-composition-api" title="Directive composition API"/>
</docs-pill-row>