От автора: динамические компоненты в любом фреймворке/библиотеке упрощают в Angular создание приложения больших масштабов. Давайте посмотрим, как мы можем создавать динамические компоненты в Angular 6.
Начало работы с Angular
Во-первых, создайте новый Angular проект. Если в вашей системе не установлен Angular, или если вы все еще используете старую версию Angular, выполните следующую команду на своем терминале:
$ npm install -g @ angular / cli
Ради этого поста я создал простое приложение с Angular выражением. Клонируйте его в свою систему.
$ git clone https://github.com/rajatgeekyants/hero.git $ cd hero $ yarn install $ ng serve --open
Это запустит приложение, а флаг —open автоматически откроет браузер по http://localhost:4200/.
Создание шаблона в шаблоне
Angular поставляется с компонентом ng-template который позволяет нам объявлять любую часть шаблона Angular. Это отличный способ придавать нашему шаблону динамичность, предоставляя нам возможность использовать наш код и передавать его другим компонентам.
В файле app.component.ts напишите новый компонент ng-template в конце template.
<ng-template #hello> Hello, World </ng-template>
Если вы сейчас откроете приложение, вы увидите, что новый текст приложения не отображается. Это потому, что вещи, которые находятся внутри компонента ng-template можно только захватить и использовать где-то еще позже.
Чтобы иметь возможность захватить этот шаблон, я дал ему переменную hello. Теперь перейдите в код Component этого файла и добавьте переменную hello внутри ViewChild. Импортируйте ViewChild из @angular/core.
export class AppComponent implements OnInit, AfterViewInit { @ViewChild('hello') helloTemplate; heroes; }
Теперь нам нужно иметь доступ к коду, который захвачен ViewChild. Для этого мы будем использовать хук жизненного цикла AfterViewInit. Убедитесь, что вы импортируете AfterViewInit из @angular/core. Напишите следующий код внутри Component:
ngAfterViewInit() { console.log(this.helloTemplate); }
Откройте инструменты разработчика. Вы заметите, что там есть TemplateRef, в котором есть несколько свойств. Мы рассмотрим их позже.
Передача ссылки шаблона компоненту
Если вы посмотрите файл tab.component.ts, вы увидите, что он использует компонент ng-content для рендеринга контента, предоставленного разработчиком. Давайте посмотрим, как мы можем сделать одну из вкладок для отображения переменной hello, которую мы определили ранее, используя ng-template и визуализировать ее с помощью ng-container и ngTemplateOutlet.
Сначала удалите текст, который передается на вкладке Hero. Мы хотим, чтобы эта вкладка отображала text внутри переменной hello.
<ngx-tab tabTitle="Hero" [template]="hello"></ngx-tab>
Затем перейдите в файл tab.component.ts и объявите template как входной TabComponent внутри TabComponent:
export class TabComponent { @Input() tabTitle: string; @Input() active = false; @Input() template; // new line }
Внутри @Component у нас есть компонент ng-content, который ничего не делает. Добавьте к компоненту ng-content условие, согласно которому ng-content должен отображать пустое пространство, если нет template.
<ng-content * ngIf = "! template"> </ ng-content>
Ниже этой строки создайте компонент ng-container, который будет отображать template.
<ng-container * ngIf = "template" [ngTemplateOutlet] = "template"> </ ng-container>
Обновите свой браузер, и вы увидите, что вторая вкладка отображает переменную hello.
Передача данных в динамический ng-template
Теперь наши вкладки работают достаточно хорошо, но мы действительно хотим сделать некоторые данные извне и сделать их динамически. Для этого мы можем использовать ngTemplateOutletContext для передачи данных в ng-template.
Сначала перейдите в файл tab.component.ts и добавьте новый Input() внутри задачи TabComponent. Этот Input() будет проходить через данные извне.
export class TabComponent { @Input() tabTitle: string; @Input() active = false; @Input() template; @Input() dataContext; }
Теперь нам нужно передать эти данные в наш шаблон. Это делается с использованием свойства ngtemplateOutletContext в компоненте ng-container.
<ng-container *ngIf="template" [ngTemplateOutlet]="template" [ngTemplateOutletContext]="{data: dataContext}" ></ng-container>
Причина, по которой я использую объект для передачи dataContext свойству, заключается в том, что я получаю выбор расширения этого свойства, чтобы он мог использовать другие типы данных.
Теперь перейдите в файл app.component.ts и используйте dataContext во втором компоненте ngx-tab.
<ngx-tab tabTitle="Hero" [template]="hello" [dataContext="heroes[0]"] ></ngx-tab>
У нас есть только одна запись внутри массива heroes. Эти данные передаются, а затем внутри компонента ngx-tab мы передадим его нашему шаблону, который в этом случае находится здесь.
Теперь мы можем использовать этот объект данных и использовать его внутри нашего компонента. Я хочу визуализировать имя этого человека, поэтому я бы сделал что-то вроде hero?.name. ? размещается здесь, если hero не определен. Нам также необходимо определить hero как data.
<ng-template #hello let-hero="data"> Hello, {{hero?.name}} </ng-template>
Как только ваш браузер обновится, перейдите на вторую вкладку, и вы увидите, что имя правильно отображается.
Якорная точка
При динамическом создании компонента мы должны знать, где разместить компонент в шаблоне другого компонента.
Чтобы сделать это, мы можем использовать пользовательскую директиву, которая выставляет ViewContainerRef и служит нам в качестве точки привязки, которую мы можем ссылаться в дальнейшем.
Сначала перейдите на tabs.component.ts и создайте новый компонент ng-template внутри ng-template @Component.
<ng-template appDynamicTabAnchor> </ ng-template>
Это область, в которой мы собираемся ввести динамические компоненты позже. Во-первых, нам нужно иметь возможность ссылаться на компонент ng-template. Нам также нужен доступ к ViewContainerRef, который позволит нам динамически создавать компоненты.
Используйте Angular CLI и создайте новую директиву, которая будет служить нам в качестве точки привязки:
$ ng gd tabs / dynamicTabAnchor --flat --spec false
Это создаст новый файл внутри папки tabs именем dynamic-tab-anchor.directive.ts. Напишите в нем следующий код:
import { Directive, ViewContainerRef } from '@angular/core'; @Directive({ selector: '[appDynamicTabAnchor]' }) export class DynamicTabAnchorDirective { constructor(public viewContainer: ViewContainerRef) { } }
Нам также нужно импортировать этот файл в файл tabs.component.ts.
import {DynamicTabAnchorDirective} from './dynamic-tab-anchor.directive.ts';
Теперь мы можем использовать @ViewChild внутри класса TabsComponent и захватить все экземпляры директив динамической привязки вкладок внутри dynamicTabPlaceholder.
@ViewChild(DynamicTabAnchorDirective) dynamicTabPlaceholder; DynamicTabAnchorDirective
Теперь мы можем создать метод openTab. Затем этот метод будет вызван извне. Я залогирую ViewContainerRef.
openTab() { console.log(this.dynamicTabPlaceholder.viewContainer) }
Перейдите в файл app.components.ts и подключите метод openTab к компоненту app-heroes-list:
<app-heroes-list [heroes] = "heroes" (addPerson) = "onAddPerson ()"> </ app-heroes-list>
Мы должны реализовать это в классе AppComponent. Здесь мы будем называть функцию openTab, которую мы создали внутри tabComponent.
onAddPerson() { this.tabsComponent.openTab(); }
Теперь, если вы нажмете кнопку «Add new button», вы увидите, что ViewContainerRef распечатан в DevTools.
Заключение
Динамические компоненты являются многоразовыми и упрощают создание крупномасштабных приложений. Этот пост является всего лишь шагом вперед для обеспечения динамичности для компонентов Angular.
Я надеюсь, что этот пост помог вам лучше разобраться в динамичности в Angular. Следите за новыми постами в Angluar, Vue, React и других популярных фреймворках/библиотеках.
Автор: Rajat S
Источник: https://blog.bitsrc.io/
Редакция: Команда webformyself.