Создание шаблонных фрагментов с помощью ng-template
По аналогии со стандартным элементом <template>, элемент <ng-template> позволяет объявить шаблонный фрагмент — часть содержимого, которую можно динамически или программно отобразить.
Создание шаблонного фрагмента
Шаблонный фрагмент можно создать в шаблоне любого компонента с помощью элемента <ng-template>:
<p>This is a normal element</p> <ng-template> <p>This is a template fragment</p> </ng-template>
При отображении приведённого выше примера содержимое элемента <ng-template> не появляется на странице. Вместо этого можно получить ссылку на шаблонный фрагмент и написать код для его динамического отображения.
Контекст привязки для фрагментов
Шаблонные фрагменты могут содержать привязки с динамическими выражениями:
@Component({
/* ... */,
template: `<ng-template>You've selected {{count}} items.</ng-template>`,
})
export class ItemCounter {
count: number = 0;
}
Выражения или инструкции в шаблонном фрагменте вычисляются относительно компонента, в котором объявлен фрагмент, независимо от того, где он отображается.
Получение ссылки на шаблонный фрагмент
Получить ссылку на шаблонный фрагмент можно одним из трёх способов:
- Объявить переменную-ссылку на шаблон для элемента
<ng-template> - Найти фрагмент с помощью запроса компонента или директивы
- Внедрить фрагмент в директиву, применённую непосредственно к элементу
<ng-template>.
Во всех трёх случаях фрагмент представлен объектом TemplateRef.
Ссылка на шаблонный фрагмент с помощью переменной-ссылки на шаблон
Чтобы ссылаться на шаблонный фрагмент в других частях того же файла шаблона, можно добавить переменную-ссылку на шаблон к элементу <ng-template>:
<p>This is a normal element</p> <ng-template #myFragment> <p>This is a template fragment</p> </ng-template>
Затем на этот фрагмент можно ссылаться в любом месте шаблона с помощью переменной myFragment.
Ссылка на шаблонный фрагмент с помощью запросов
Получить ссылку на шаблонный фрагмент можно с помощью любого API запросов компонентов или директив.
Можно напрямую запросить объект TemplateRef с помощью запроса viewChild.
@Component({
/* ... */,
template: `
<p>This is a normal element</p>
<ng-template>
<p>This is a template fragment</p>
</ng-template>
`,
})
export class ComponentWithFragment {
templateRef = viewChild<TemplateRef<unknown>>(TemplateRef);
}
Затем на этот фрагмент можно ссылаться в коде компонента или его шаблоне, как и на любой другой член класса.
Если шаблон содержит несколько фрагментов, каждому фрагменту можно назначить имя, добавив переменную-ссылку на шаблон к каждому элементу <ng-template> и запросив фрагменты по этим именам:
@Component({
/* ... */,
template: `
<p>This is a normal element</p>
<ng-template #fragmentOne>
<p>This is one template fragment</p>
</ng-template>
<ng-template #fragmentTwo>
<p>This is another template fragment</p>
</ng-template>
`,
})
export class ComponentWithFragment {
fragmentOne = viewChild<TemplateRef<unknown>>('fragmentOne');
fragmentTwo = viewChild<TemplateRef<unknown>>('fragmentTwo');
}
Затем на эти фрагменты можно ссылаться в коде компонента или его шаблоне, как и на любые другие члены класса.
Внедрение шаблонного фрагмента
Директива может внедрить TemplateRef, если она непосредственно применена к элементу <ng-template>:
@Directive({
selector: '[myDirective]',
})
export class MyDirective {
private fragment = inject(TemplateRef);
}
<ng-template myDirective> <p>This is one template fragment</p> </ng-template>
Затем на этот фрагмент можно ссылаться в коде директивы, как и на любой другой член класса.
Отображение шаблонного фрагмента
Получив ссылку на объект TemplateRef шаблонного фрагмента, его можно отобразить одним из двух способов: в шаблоне с помощью директивы NgTemplateOutlet или в коде TypeScript с помощью ViewContainerRef.
Использование NgTemplateOutlet
Директива NgTemplateOutlet из @angular/common принимает TemplateRef и отображает фрагмент как соседний элемент элемента с точкой вставки. Как правило, NgTemplateOutlet следует использовать с элементом <ng-container>.
Сначала импортируйте NgTemplateOutlet:
import {NgTemplateOutlet} from '@angular/common';
В следующем примере объявляется шаблонный фрагмент и отображается внутри элемента <ng-container> с помощью NgTemplateOutlet:
<p>This is a normal element</p> <ng-template #myFragment> <p>This is a fragment</p> </ng-template> <ng-container *ngTemplateOutlet="myFragment"></ng-container>
В результате этого примера получается следующая отображённая DOM-структура:
<p>This is a normal element</p> <p>This is a fragment</p>
Использование ViewContainerRef
Контейнер представления — это узел в дереве компонентов Angular, который может содержать содержимое. Любой компонент или директива могут внедрить ViewContainerRef, чтобы получить ссылку на контейнер представления, соответствующий расположению этого компонента или директивы в DOM.
Для динамического отображения шаблонного фрагмента можно использовать метод createEmbeddedView объекта ViewContainerRef. При отображении фрагмента с помощью ViewContainerRef Angular добавляет его в DOM как следующий соседний элемент компонента или директивы, внедривших ViewContainerRef.
В следующем примере показан компонент, который принимает ссылку на шаблонный фрагмент в качестве входного параметра и отображает этот фрагмент в DOM при нажатии кнопки.
@Component({
/* ... */,
selector: 'component-with-fragment',
template: `
<h2>Component with a fragment</h2>
<ng-template #myFragment>
<p>This is the fragment</p>
</ng-template>
<my-outlet [fragment]="myFragment" />
`,
})
export class ComponentWithFragment { }
@Component({
/* ... */,
selector: 'my-outlet',
template: `<button (click)="showFragment()">Show</button>`,
})
export class MyOutlet {
private viewContainer = inject(ViewContainerRef);
fragment = input<TemplateRef<unknown> | undefined>();
showFragment() {
if (this.fragment()) {
this.viewContainer.createEmbeddedView(this.fragment());
}
}
}
В приведённом выше примере нажатие кнопки «Показать» приводит к следующему результату:
<component-with-fragment>
<h2>Component with a fragment>
<my-outlet>
<button>Show</button>
</my-outlet>
<p>This is the fragment</p>
</component-with-fragment> Передача параметров при отображении шаблонного фрагмента
Объявляя шаблонный фрагмент с помощью <ng-template>, можно дополнительно указать параметры, которые он принимает. При отображении фрагмента можно передать объект context, соответствующий этим параметрам. Данные из этого объекта контекста можно использовать в выражениях привязки и инструкциях наряду с данными компонента, в котором объявлен фрагмент.
Каждый параметр записывается как атрибут с префиксом let- и значением, соответствующим имени свойства в объекте контекста:
<ng-template let-pizzaTopping="topping">
<p>You selected: {{ pizzaTopping }}</p>
</ng-template> Использование NgTemplateOutlet с параметрами
Объект контекста можно привязать ко входному параметру ngTemplateOutletContext:
<ng-template #myFragment let-pizzaTopping="topping">
<p>You selected: {{ pizzaTopping }}</p>
</ng-template>
<ng-container [ngTemplateOutlet]="myFragment" [ngTemplateOutletContext]="{topping: 'onion'}" /> Использование ViewContainerRef с параметрами
Объект контекста можно передать вторым аргументом в createEmbeddedView:
this.viewContainer.createEmbeddedView(this.myFragment, {topping: 'onion'}); Передача инъекторов шаблонным фрагментам
При отображении шаблонного фрагмента его контекст инъектора определяется местом объявления шаблона, а не местом его отображения. Это поведение можно переопределить, передав пользовательский инъектор.
Использование NgTemplateOutlet с инъекторами
Пользовательский Injector можно передать во входной параметр ngTemplateOutletInjector:
export const THEME_DATA = new InjectionToken<string>('THEME_DATA', {
factory: () => 'light',
});
@Component({
selector: 'themed-panel',
template: `<div [class]="theme">...</div>`,
})
export class ThemedPanel {
theme = inject(THEME_DATA);
}
@Component({
selector: 'root',
imports: [NgTemplateOutlet, ThemedPanel],
template: `
<ng-template #myFragment>
<themed-panel />
</ng-template>
<ng-container *ngTemplateOutlet="myFragment; injector: customInjector" />
`,
})
export class Root {
customInjector = Injector.create({
providers: [{provide: THEME_DATA, useValue: 'dark'}],
});
} Наследование инъектора точки вставки
Можно присвоить ngTemplateOutletInjector строковое значение 'outlet', чтобы внедрённое представление наследовало инъектор из расположения точки вставки в DOM, а не из места объявления шаблона.
<ng-template #node let-items>
<item-component>
@for (child of items; track $index) {
<ng-container
*ngTemplateOutlet="node; context: {$implicit: child.children}; injector: 'outlet'"
/>
}
</item-component>
</ng-template>
<ng-container *ngTemplateOutlet="node; context: {$implicit: topLevelItems}" />
Каждое рекурсивное отображение шаблона node наследует инъектор из окружающего <item-component>, позволяя каждому вложенному уровню обращаться к провайдерам, область видимости которых ограничена родительским компонентом.
ПРИМЕЧАНИЕ: Это полезно при создании рекурсивных структур и в любых ситуациях, когда отображаемому шаблону нужен доступ к провайдерам из дерева компонентов в месте размещения точки вставки.
Использование ViewContainerRef с инъекторами
Пользовательский инъектор можно передать в составе объекта параметров в createEmbeddedView:
this.viewContainer.createEmbeddedView(this.myFragment, context, {
injector: myCustomInjector,
}); Структурные директивы
Структурная директива — это любая директива, которая:
- Внедряет
TemplateRef - Внедряет
ViewContainerRefи программно отображает внедрённыйTemplateRef
Для структурных директив Angular поддерживает специальный сокращённый синтаксис. Если применить директиву к элементу и поставить перед селектором директивы символ звёздочки (*), Angular интерпретирует весь элемент и всё его содержимое как шаблонный фрагмент:
<section *myDirective> <p>This is a fragment</p> </section>
Это эквивалентно следующему:
<ng-template myDirective>
<section>
<p>This is a fragment</p>
</section>
</ng-template>
Разработчики обычно используют структурные директивы для условного отображения фрагментов или многократного отображения фрагментов.
Дополнительные сведения см. в разделе «Структурные директивы».
Дополнительные ресурсы
Примеры использования ng-template в других библиотеках см. в следующих материалах:
- Вкладки Angular Material — содержимое не добавляется в DOM, пока не активирована вкладка
- Таблица Angular Material — позволяет разработчикам определять разные способы отображения данных
Super-powered by Google ©2010–2025.
Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0.
https://angular.dev/guide/templates/ng-template