Spec-Zone.ru › Angular

Структурные директивы

Структурные директивы — это директивы, применяемые к элементу <ng-template> и условно или многократно отображающие содержимое этого <ng-template>.

Пример использования

В этом руководстве вы создадите структурную директиву, которая получает данные из указанного источника и отображает свой шаблон, когда эти данные становятся доступны. Эта директива называется SelectDirective — в честь ключевого слова SQL SELECT — и использует селектор атрибута [select].

У SelectDirective будет входной параметр, указывающий используемый источник данных; назовём его selectFrom. Префикс select для этого входного параметра важен для сокращённого синтаксиса. Директива создаст свой <ng-template> с контекстом шаблона, предоставляющим выбранные данные.

Пример использования этой директивы непосредственно на <ng-template> выглядит так:

<ng-template select let-data [selectFrom]="source">
  <p>The data is: {{ data }}</p>
</ng-template>

Структурная директива может дождаться появления данных, а затем отобразить свой <ng-template>.

ПОЛЕЗНО: Обратите внимание: элемент <ng-template> в Angular определяет шаблон, который по умолчанию ничего не отображает. Если просто обернуть элементы в <ng-template>, не применяя структурную директиву, эти элементы отображаться не будут.

Дополнительные сведения см. в документации API ng-template.

Сокращённый синтаксис структурных директив

Angular поддерживает сокращённый синтаксис для структурных директив, который позволяет не указывать элемент <ng-template> явно.

Структурные директивы можно применять непосредственно к элементу, добавив перед селектором директивы в атрибуте звёздочку (*), например *select. Angular преобразует звёздочку перед структурной директивой в <ng-template>, который содержит директиву и оборачивает элемент вместе с его потомками.

Например, SelectDirective можно использовать так:

<p *select="let data; from: source">The data is: {{ data }}</p>

Этот пример демонстрирует гибкость сокращённого синтаксиса структурных директив, который иногда называют микросинтаксисом.

При таком использовании к <ng-template> применяются только структурная директива и её привязки. Все остальные атрибуты и привязки тега <p> остаются без изменений. Например, следующие две формы эквивалентны:

<!-- Shorthand syntax: -->
<p class="data-view" *select="let data; from: source">The data is: {{ data }}</p>

<!-- Long-form syntax: -->
<ng-template select let-data [selectFrom]="source">
  <p class="data-view">The data is: {{ data }}</p>
</ng-template>

Сокращённый синтаксис раскрывается с помощью набора соглашений. Ниже приведена более подробная грамматика, а преобразование в примере выше можно объяснить следующим образом:

Первая часть выражения *select — это let data, которая объявляет переменную шаблона data. Поскольку за ней не следует присваивание, переменная шаблона связывается со свойством контекста шаблона $implicit.

Вторая часть синтаксиса — пара «ключ-выражение»: from source. from — это ключ привязки, а source — обычное выражение шаблона. Ключи привязки сопоставляются со свойствами: они преобразуются в PascalCase, после чего к ним добавляется селектор структурной директивы. Ключ from сопоставляется с selectFrom, который затем связывается с выражением source. Именно поэтому входные параметры многих структурных директив имеют префикс, совпадающий с селектором структурной директивы.

Одна структурная директива на элемент

При использовании сокращённого синтаксиса к одному элементу можно применить только одну структурную директиву. Это связано с тем, что существует только один элемент <ng-template>, в который разворачивается эта директива. Для нескольких директив потребовалось бы несколько вложенных элементов <ng-template>, и было бы неясно, какая директива должна идти первой. <ng-container> можно использовать для создания уровней-обёрток, когда вокруг одного и того же физического элемента DOM или компонента необходимо применить несколько структурных директив. Это позволяет пользователю задать вложенную структуру.

Создание структурной директивы

В этом разделе описано, как создать SelectDirective.

  1. Создание директивы

    Выполните следующую команду Angular CLI, указав в качестве select имя директивы:

    ng generate directive select

    Angular создаёт класс директивы и задаёт CSS-селектор [select], который идентифицирует директиву в шаблоне.

  2. Преобразование директивы в структурную

    Импортируйте TemplateRef, ViewContainerRef и input. Внедрите в директиву TemplateRef и ViewContainerRef в качестве закрытых свойств.

    import {Directive, TemplateRef, ViewContainerRef, inject, input} from '@angular/core';
    
    export interface DataSource<T> {
      load(): Promise<T>;
    }
    
    @Directive({
      selector: '[select]',
    })
    export class SelectDirective {
      private templateRef = inject(TemplateRef);
      private viewContainerRef = inject(ViewContainerRef);
    }
  3. Добавление входного параметра 'selectFrom'

    Добавьте свойство selectFrom input().

    export class SelectDirective {
      // ...
      selectFrom = input.required<DataSource<unknown>>();
    }
  4. Добавление бизнес-логики

    Теперь, когда SelectDirective создана как структурная директива с входным параметром, можно добавить логику для получения данных и отображения шаблона с этими данными:

    export class SelectDirective {
      // ...
      async ngOnInit() {
        const data = await this.selectFrom().load();
        this.viewContainerRef.createEmbeddedView(this.templateRef, {
          // Create the embedded view with a context object that contains
          // the data via the key `$implicit`.
          $implicit: data,
        });
      }
    }

Готово — SelectDirective работает. В качестве следующего шага можно добавить поддержку проверки типов шаблонов.

Справочник по синтаксису структурных директив

При создании собственных структурных директив используйте следующий синтаксис:

_: prefix = "( :let | :expression ) (';' | ',')? ( :let | :as | :keyExp )_";

Следующие шаблоны описывают отдельные части грамматики структурных директив:

as = :export "as" :local ";"?
keyExp = :key ":"? :expression ("as" :local)? ";"?
let = "let" :local "=" :export ";"?
Ключевое слово Подробности
prefix Ключ атрибута HTML
key Ключ атрибута HTML
local Имя локальной переменной, используемой в шаблоне
export Значение, экспортируемое директивой под заданным именем
expression Стандартное выражение Angular

Как Angular преобразует сокращённый синтаксис

Angular преобразует сокращённый синтаксис структурных директив в обычный синтаксис привязки следующим образом:

Сокращённый синтаксис Преобразование
prefix и expression без ключевого слова [prefix]="expression"
keyExp [prefixKey]="expression" (prefix добавляется к key)
let local let-local="export"

Примеры сокращённого синтаксиса

В следующей таблице приведены примеры сокращённого синтаксиса:

Сокращённый синтаксис Как Angular интерпретирует синтаксис
*myDir="let item of [1,2,3]" <ng-template myDir let-item [myDirOf]="[1, 2, 3]">
*myDir="let item of [1,2,3] as items; trackBy: myTrack; index as i" <ng-template myDir let-item [myDirOf]="[1,2,3]" let-items="myDirOf" [myDirTrackBy]="myTrack" let-i="index">
*ngComponentOutlet="componentClass"; <ng-template [ngComponentOutlet]="componentClass">
*ngComponentOutlet="componentClass; inputs: myInputs"; <ng-template [ngComponentOutlet]="componentClass" [ngComponentOutletInputs]="myInputs">
*myDir="exp as value" <ng-template [myDir]="exp" let-value="myDir">

Улучшение проверки типов шаблонов для пользовательских директив

Проверку типов шаблонов для пользовательских директив можно улучшить, добавив в определение директивы защитные проверки шаблонов. Они помогают средству проверки типов шаблонов Angular обнаруживать ошибки в шаблоне во время компиляции и тем самым предотвращать ошибки во время выполнения. Возможны два вида защитных проверок:

  • ngTemplateGuard_(input) позволяет управлять сужением типа выражения входного параметра на основе типа конкретного входного параметра.
  • ngTemplateContextGuard используется для определения типа объекта контекста шаблона на основе типа самой директивы.

В этом разделе приведены примеры обоих видов защитных проверок. Дополнительные сведения см. в руководстве по проверке типов шаблонов.

Сужение типов с помощью защитных проверок шаблонов

Структурная директива в шаблоне определяет, будет ли этот шаблон отображаться во время выполнения. Некоторые структурные директивы выполняют сужение типа на основе типа выражения входного параметра.

Защитные проверки входных параметров позволяют выполнять сужение типов двумя способами:

  • Сужение типа выражения входного параметра на основе функции утверждения типа TypeScript.
  • Сужение типа выражения входного параметра на основе его истинности.

Чтобы сузить тип выражения входного параметра, определив функцию утверждения типа:

// This directive only renders its template if the actor is a user.
// You want to assert that within the template, the type of the `actor`
// expression is narrowed to `User`.
@Directive(...)
class ActorIsUser {
  actor = input<User | Robot>();

  static ngTemplateGuard_actor(dir: ActorIsUser, expr: User | Robot): expr is User {
    // The return statement is unnecessary in practice, but included to
    // prevent TypeScript errors.
    return true;
  }
}

В шаблоне проверка типов будет выполняться так, как если бы для выражения, связанного с входным параметром, было выполнено утверждение ngTemplateGuard_actor.

Некоторые директивы отображают свои шаблоны, только если значение входного параметра истинно. Полную семантику истинности невозможно выразить с помощью функции утверждения типа, поэтому вместо этого можно использовать литеральный тип 'binding', чтобы указать средству проверки типов шаблонов, что в качестве защитной проверки следует использовать само выражение привязки:

@Directive(...)
class CustomIf {
  condition = input.required<boolean>();

  static ngTemplateGuard_condition: 'binding';
}

Средство проверки типов шаблонов будет считать, что выражение, связанное с condition, истинно в шаблоне.

Типизация контекста директивы

Если структурная директива предоставляет контекст для создаваемого шаблона, его тип можно корректно указать внутри шаблона, добавив статическую функцию утверждения типа ngTemplateContextGuard. Эта функция может использовать тип директивы для определения типа контекста. Это полезно, когда тип директивы является обобщённым.

Для описанного выше SelectDirective можно реализовать ngTemplateContextGuard, чтобы правильно указать тип данных, даже если источник данных является обобщённым.

// Declare an interface for the template context:
export interface SelectTemplateContext<T> {
  $implicit: T;
}

@Directive(...)
export class SelectDirective<T> {
  // The directive's generic type `T` will be inferred from the `DataSource` type
  // passed to the input.
  selectFrom = input.required<DataSource<T>>();

  // Narrow the type of the context using the generic type of the directive.
  static ngTemplateContextGuard<T>(dir: SelectDirective<T>, ctx: any): ctx is SelectTemplateContext<T> {
    // As before the guard body is not used at runtime, and included only to avoid
    // TypeScript errors.
    return true;
  }
}

Super-powered by Google ©2010–2025.
Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0.
https://angular.dev/guide/directives/structural-directives

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API