Я пытаюсь обновить загрузчик динамических компонентов с RC4 до RC5, поскольку ComponentResolver устарел. Я обновил загрузчик до следующего

@Component({
    selector: 'component-dispatcher',
    template: `<div #container></div>` // Define the template here because of its brevity
})
export class ComponentDispatcherComponent implements OnInit, OnDestroy {
    @Input() component:any; // Some dynamic component to render
    @Input() options:any;   // Component configuration, optional
    @Input() data:any;      // Data to render within the component

    // Inject the dynamic component onto the DOM
    @ViewChild("container", {read: ViewContainerRef}) container:ViewContainerRef;

    private componentReference:ComponentRef<any>;

    constructor(private resolver:ComponentFactoryResolver) {
    }

    ngOnInit() {
        // Create our component now we're initialised
        let componentFactory = this.resolver.resolveComponentFactory(this.component);
        this.componentReference = this.container.createComponent(componentFactory);
        this.componentReference.instance.data = this.data;
        this.componentReference.instance.options = this.options;
    }

    ngOnDestroy() {
        // If we have a component, make sure we destroy it when we lose our owner
        if (this.componentReference) {
            this.componentReference.destroy();
        }
    }
}

И попытайтесь динамически загрузить следующий компонент в DOM

@Component({
    selector: 'text-cell',
    pipes: [IterableObjectPipe],
    templateUrl: './text-cell.component.html',
    styles: ['.fieldName { font-weight: bold; }']
})
export class TextCellComponent implements OnInit {
    // Data to render within the component
    @Input() data: any;
    @Input() record: any;

    // Configuration of what data to display
    @Input() options: {
        excludeFieldNames: boolean,
        translation: string
    };

    constructor() {
    }

    ngOnInit() {
        setTimeout(() => {
            //console.log('***************************** ngOnInit...textCell ***********************');
            this.options.translation = '' + (_.get(this.options, 'translation') || 'fields');
        });
    }
}

Но когда я делаю это с помощью TextCellComponent или любого другого компонента в приложении, я получаю следующую ошибку

ORIGINAL EXCEPTION: No component factory found for TextCellComponent
ORIGINAL STACKTRACE:
Error: No component factory found for TextCellComponent
at NoComponentFactoryError.BaseException [as constructor]      
(webpack:///./~/@angular/core/src/facade/exceptions.js?:27:23)
at new NoComponentFactoryError 

Я выполнил шаги в

https://angular.io/docs/ts/latest/cookbook/rc4-to-rc5.html

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

ИЗМЕНИТЬ

Добавление определения модуля

@NgModule({
    imports: [
        BrowserModule, 
        HttpModule, 
        FormsModule, 
        ReactiveFormsModule, 
        ...MATERIAL_MODULES
    ],
    declarations: [
        ...APPLICATION_PIPES, 
        ...APPLICATION_COMPONENTS, 
        ...APPLICATION_DIRECTIVES, 
        CygnusComponent,
        // Component declarations
        // TODO: refactor to appropriate modules
        ...
        ComponentDispatcherComponent,
        TextCellComponent,
        ...
    ],
    bootstrap: [
        ApplicationComponent
    ],
    providers: [
        ...APPLICATION_PROVIDERS, 
        AppStore
    ]
})
export class ApplicationComponent {}
41
JME 7 Сен 2016 в 18:30

5 ответов

Лучший ответ

Все компоненты, которые будут загружаться «динамически», необходимо объявить в разделе entryComponents вашего модуля. Другими словами, у вас должно получиться что-то вроде:

@NgModule({
    imports: [BrowserModule, HttpModule, FormsModule, ReactiveFormsModule, ...MATERIAL_MODULES],
    declarations: [...APPLICATION_PIPES, ...APPLICATION_COMPONENTS, ...APPLICATION_DIRECTIVES, CygnusComponent,
        // Component declarations
        // TODO: refactor to appropriate modules
        ...
        ComponentDispatcherComponent,
        TextCellComponent,
        ...
    entryComponents: [TextCellComponent]
    bootstrap: [ApplicationComponent],
    providers: [...APPLICATION_PROVIDERS, AppStore]
})
export class ApplicationComponent{

Обратите внимание, что вам необходимо указать TextCellComponent в обоих разделах declarations и entryComponents.

98
pkozlowski.opensource 7 Сен 2016 в 18:28

Вы можете проверить свои пути импорта. В моем случае при импорте одного файла использовались прописные буквы, а в другом - строчные.

//file 1
import { IRComponent } from "./components/IR/IR.component";
//file 2
import { IRComponent } from "./components/ir/ir.component";

Раздача была на вкладке сети Chrome, я заметил, что файл загружался дважды (один раз для каждого написания).

1
Alan 11 Окт 2016 в 01:15

Допустим, TextCellComponent объявлен в FooModule, а ваш компонент, отвечающий за создание динамического контента, находится в модуле BarModule.

В таком случае FooModule необходимо импортировать в BarModule

@NgModule({
 imports: [FooModule],
declarations: [ComponentDispatcherComponent]
})
export class BarModule {}

На мой взгляд, это как бы компрометирует идею о том, что вещи динамические . Мне просто нужен компонент, который создаст любой компонент, на который я отправлю его по ссылке на класс. Если у кого-то есть достойное решение, я был бы рад его услышать.

1
George Knap 14 Янв 2020 в 08:03

Вам необходимо импортировать {{X0}} в {{X1}}, чтобы он знал о {{X2}} там.…

В таких ситуациях вам просто нужно ввести это имя компонента (здесь TextCellComponent) над всеми другими компонентами, как показано ниже:

declarations: [ 
        TextCellComponent // Declared above
        CygnusComponent,
        ComponentDispatcherComponent,
        ...
    ]

Это также нужно сделать в entryComponents.

Надеюсь, это поможет.

0
gsthina 4 Янв 2018 в 04:19

Объект 'dict' не имеет атрибута 'aggregate'…

-1
Nebojsa Sapic 1 Авг 2019 в 15:56