Как вызвать компонент с таким же, как строка «имя компонента» в HTML, используя угловой 7 - PullRequest
2 голосов
/ 02 апреля 2019

Я пытаюсь вызывать компоненты со строковыми ключами в angular 7. Потому что мой сервис дает мне ключи, которые фильтр компонентов собирается показывать на странице для каждого пользователя. Могу ли я сделать этот фильтр, особенно в формате HTML?

<pg-tab *ngFor="let tab of tabs; let index = index">
  <ng-template #TabHeading>
    {{tab.headerText}}
  <a (click)="removeTab(index)" style="padding: 5px;"><i class="fa fa-times fa-lg" style="color:orangered;"></i></a>
  </ng-template>
  <div class="row column-seperation" *ngIf="tab.componentName === 'grid-sample'">
    <app-grid-sample></app-grid-sample>
  </div>

  <div class="row column-seperation" *ngIf="tab.componentName === 'pdf-export-sample'">
    <app-pdf-export-sample></app-pdf-export-sample>
  </div>
  <div class="row column-seperation" *ngIf="tab.componentName === 'notify-sample'">
    <app-notify-sample></app-notify-sample>
  </div>
  <div class="row column-seperation" *ngIf="tab.componentName === 'loader-sample'">
    <app-loader-sample></app-loader-sample>
  </div>
  <div class="row column-seperation" *ngIf="tab.componentName === 'tt-form-elements'">
    <app-tt-form-elements></app-tt-form-elements>
  </div>
  <div class="row column-seperation" *ngIf="tab.componentName === 'tt-layouts'">
    <app-tt-layouts></app-tt-layouts>
  </div>
</pg-tab>

Я искал атрибут innerHtml, но он не работает для угловых компонентов, как в этом примере.

HTML

<div [innerHTML]="pageDetail"></div>

машинопись

private _pageDetail: string = '<app-tab-page1 [tab]="tab" [tabsLength]="tabs.length" [tabs]="tabs"></app-tab-page1><button>Naber</button>';

public get pageDetail(): SafeHtml {
  return this._sanitizer.bypassSecurityTrustHtml(this._pageDetail);
}

Вы можете догадаться, что сейчас это выглядит не очень хорошо. Если это возможно, я хочу сделать короче и очистить атрибуты "* ngIf" в html.

У вас есть идеи по этому поводу?

как то так

<div class="row column-seperation" tab.componentName>
  <app-tab.componentName></app-tab.componentName>
</div>

Примечание: извините за мои грамматические ошибки.

Ответы [ 3 ]

1 голос
/ 10 июля 2019

Вы можете создать динамический компонент с именем, подобным этому:

Элемент табуляции является директивой:

@ViewChildren('tabItem', {read: ViewContainerRef} ) tabItem:  QueryList<ViewContainerRef>;

Здесь создайте динамический компонент:

    const factories = Array.from(this.componentFactoryResolver['_factories'].keys());
    const factoryClass = <Type<any>>factories.find((x: any) => x.name === dynamicComponentName);
    if (factoryClass !== undefined) {
      const factory = this.componentFactoryResolver.resolveComponentFactory(factoryClass);
      const ref = this.tabItem.viewContainerRef;
      ref.createComponent(factory);
    }

Также вы можете посмотреть угловые документы: Динамический компонент

0 голосов
/ 02 апреля 2019

Вы можете просто использовать ngSwitch, который сделает его короче, но имя динамического компонента, как я знаю, невозможно,

<div class="row column-seperation" *ngSwitch="tab.componentName">
    <app-grid-sample *ngSwitchCase="'grid-sample'"></app-grid-sample>
    <app-pdf-export-sample *ngSwitchCase="'pdf-export-sample''"></app-pdf-export-sample>
     //etc ...
  </div>
0 голосов
/ 02 апреля 2019

Существует два способа:

  1. Использование ngSwitch не сильно поможет в уменьшении HTML-кода.
  2. Использование ngComponentOutlet отображаемого компонента может быть предоставлено из родительского элемента.код компонента вместо шаблона.

Пример для # 2:

шаблон:

<div>
... some other code
 <ng-template matTabContent>
     <ng-container *ngComponentOutlet="screen.component; injector: screen.injector">
     </ng-container>
 </ng-template>
</div>

Код родительского компонента:

export class TabsContainerComponent implements OnInit {

  // make sure these component are also added to entryComponents
  private components = [
    GridSampleComponent,
    NotifySampleComponent,
    LoaderSampleComponent,
    TTLayoutComponent,
    ...
  ];

  screen: any; // reference to be used by the ngComponentOutlet in the template

  constructor(
    private injector: Injector,
  ) {}

  async ngOnInit() {
    const tabs = await this.someApiService.getComponentFilters().toPromise();
    const injector = Injector.create({
        providers: [any providers you want to pass to the component],
        parent: this.injector
    })

    switch (tabs.componentName) {
        case 'grid-sample':
            screen = { component: GridSampleComponent, injector };
            break;
        case 'notify-sample':
            screen = { component: NotifySampleComponent, injector };
            break;
        case 'loader-sample':
            screen = { component: LoaderSampleComponent, injector };
            break;
        case 'tt-layout':
            screen = { component: TTLayoutComponent, injector };
            break;
    }
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...