Передайте @Input, поскольку параметры срабатывают. Тип «строка» не имеет общих свойств с типом.

Я создаю компоненты на основе динамических вкладок и передаю необходимые свойства компонента для создания компонента через объект.

Как передать @Input в качестве параметра, а затем использовать ввод с ComponentFactoryResolver и создать ввод.

Вот объект для хранения необходимых свойств компонента вкладки,

Вот StackBlitz

вкладка-item.ts

import { Type, Input } from '@angular/core';

export class TabItem {

    componentLoaded = false;

    constructor(public title: string, public active: boolean, public component: Type<object>, public inputs: Input[] = []) {

    }
}

вкладка-component.ts

import { Component, OnInit, Input, ComponentFactoryResolver, ComponentFactory, Injector, ApplicationRef, ElementRef } from '@angular/core';
import { TabItem } from 'src/app/models/tab-item';

@Component({
    selector: 'app-tab',
    template: `
              <div class="row">
                <div class="col-2">
                   <ul class="nav flex-column">
                      <li class="nav-item" *ngFor="let tab of tabItems">
                         <a class="nav-link" (click)="setActiveTabItem(tab)" [class.active]="tab.active" [id]="tab.title+'-tab'"
                           data-toggle="tab" [href]="'#' + tab.title" role="tab" [attr.aria-controls]="tab.title"
                           aria-selected="true">{{tab.title}}</a>
                      </li>
                  </ul>
              </div>
             <div class="col-10">
                <div id="tab-container" class="tab-content">
               </div>
             </div>
           </div>`,
    styleUrls: ['./tab.component.scss']
})
export class TabComponent implements OnInit {

    @Input() tabItems: TabItem[];
    componentsCreated: ComponentFactory<object>[] = [];

    constructor(private componentFactorResolver: ComponentFactoryResolver, private injector: Injector,
                private app: ApplicationRef,
                private elementRef: ElementRef) { }

    loadTabContent(selectedIndex: number, isHome: boolean = false): void {
        const tabItem = this.tabItems[selectedIndex];
        const componentFactory = 
        this.componentFactorResolver.resolveComponentFactory(tabItem.component);

        // Assign Inputs
        if (tabItem.inputs) {
            tabItem.inputs.forEach((item: Input) => {
                 componentFactory.inputs.push(item);
            });
        }

        const newNode = document.createElement('div');
        newNode.id = tabItem.title;
        document.getElementById('tab-container').appendChild(newNode);

        const ref = componentFactory.create(this.injector, [], newNode);
        this.app.attachView(ref.hostView);
    }
}

Здесь, в приведенном выше коде, я получаю следующую ошибку с componentFactory.inputs.push(item);

Аргумент типа «Ввод» нельзя присвоить параметру типа «{ propName: string; имя_шаблона: строка; }'.

В типе «Ввод» отсутствуют следующие свойства из типа «{ propName: string; имя_шаблона: строка; }': propName, templateNamets(2345)

Наконец, создание элементов вкладки, как показано ниже, и передача их из родительского компонента.

<app-tab [tabItems]="tabItems"></app-tab>


@Input() header = 'Test';
tabItems = [
            new TabItem('Home', true, HomeComponent),
            new TabItem('Profile', false, ProfileComponent),
            new TabItem('Employee', false,  EmployeeComponent, [this.header])
        ];

Здесь ошибка,

Тип 'string' не имеет общих свойств с типом 'Input'.ts(2559)

Это правильный способ передачи входных данных? Если да, то что с этим не так?


person Hary    schedule 25.06.2020    source источник
comment
создайте скрипт для вашего вопроса, чтобы воспроизвести проблему.   -  person Amirhossein Mehrvarzi    schedule 25.06.2020
comment
добавил скрипку   -  person Hary    schedule 25.06.2020
comment
Близкий избиратель. Предложенный вами ответ полностью отличается от этого. Пожалуйста, внимательно прочитайте вопрос и код, прежде чем голосовать за закрытие. Спасибо.   -  person Hary    schedule 25.06.2020


Ответы (2)


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

Используется оператор rest для аргументов без указания типа Input

import { Type, Input } from '@angular/core';

export class TabItem {

    componentLoaded = false;
    args;

    constructor(public title: string, public active: boolean, public component: Type<object>, ...args) {

    }
}

вкладка-component.ts

loadTabContent(selectedIndex: number, isHome: boolean = false): void {
    const tabItem = this.tabItems[selectedIndex];
    const componentFactory = 
    this.componentFactorResolver.resolveComponentFactory(tabItem.component);

    const newNode = document.createElement('div');
    newNode.id = tabItem.title;
    document.getElementById('tab-container').appendChild(newNode);

    const ref = componentFactory.create(this.injector, [], newNode);
    this.app.attachView(ref.hostView);

    if (tabItem.args) {
        tabItem.args.forEach((item) => {
             Object.keys(item).forEach(key => {
                 const value = item[key];
                 
                 ref.instance[key] = value; //Here it works!
             });
        });
    }

}

При создании здесь не обязательно иметь тип Input, достаточно пары key:value

<app-tab [tabItems]="tabItems"></app-tab>

tabItems = [
            new TabItem('Home', true, HomeComponent),
            new TabItem('Employee', false,  EmployeeComponent, {'header': 'Test data'})
        ];
person Hary    schedule 25.06.2020

Согласно ComponentFactory docs, он имеет inputs свойство, которое ожидает Array из { propName: string; templateName: string; }.

Ваша проблема возникает из-за 2 нарушений:

  1. Внутри app.component.ts, где вы пытаетесь рассматривать директиву @Input как тип Input, в то время как вы устанавливаете ее как string!

  2. Внутри tab.component.ts, где вы пытаетесь вставить Input как тип inputs ComponentFactory!

Мои изменения в Stackblitz могут помочь вам написать лучший код.

person Amirhossein Mehrvarzi    schedule 25.06.2020
comment
Который из? вы можете отправить последний stackblitz? - person Amirhossein Mehrvarzi; 25.06.2020
comment
Я обновил так же. Даже это не сработает. @Input() header: string = 'Test' as Input; Это ненужное приведение от sometype к Input. - person Hary; 25.06.2020
comment
Кроме того, это универсальный компонент. Нет смысла явно приводить к Input из любого места, где оно вызывается. - person Hary; 25.06.2020
comment
@Hary В любом случае, ваша проблема изменилась на 'app-tab' is not a known element:, что является ошибкой конфигурации модуля, основанной на моих изменениях. По крайней мере, вы должны удалить это, чтобы продолжить! - person Amirhossein Mehrvarzi; 25.06.2020
comment
Я уже удалил его и исправил необходимый импорт - person Hary; 25.06.2020
comment
@Hary Я полностью изменил свой ответ. - person Amirhossein Mehrvarzi; 25.06.2020
comment
Я уже определил проблемы и добавил ответ :) Это поддерживает только строковые входы. А другие? Однако у меня уже есть рабочая деталь. Спасибо! - person Hary; 25.06.2020