Angular - 使用自定义指令加载多个组件返回未定义
Angular - Using custom directive to load several components is returning undefined
我正在开发一个应用程序,现在,我有一个动态网格生成器,它在屏幕上划分 space 以动态适应多个组件。因此,负责此的组件必须在 angular 呈现页面后呈现组件。为了实现这一点,我遵循了 angular 动态组件加载器指南 (https://angular.io/guide/dynamic-component-loader)。
所以我现在确实有一个必须渲染其他组件的组件,我有我的自定义指令来渲染这些组件。
指令
@Directive({
selector: '[componentLoader]'
})
export class ComponentLoaderDirective {
constructor (
public ViewContainerRef: ViewContainerRef
) {}
}
现在组件(网格组件)
grid.component.ts
// ... Stuff above
export class GridComponent implements OnInit {
@Input() public items: gridItem[] = [];
@ViewChild(ComponentLoaderDirective) componentLoader: ComponentLoaderDirective | undefined;
constructor(
private sanitizer: DomSanitizer,
private componentFactoryResolver: ComponentFactoryResolver
) {}
ngOnInit(): void { this.processRow(this.items) }
processRow( row: gridItem[] ) {
// Some grid related stuff ...
for ( let item of row ) {
// Stuff performed over every item in each grid row
this.renderComponentIfNeeded(item)
}
}
renderComponentIfNeeded( item: gridItem ):void {
if ( item.components ) {
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
let viewContainerRef = this.componentLoader.ViewContainerRef;
viewContainerRef.clear();
let componentRef = viewContainerRef.createComponent<any>(componentFactory);
componentRef.instance.data = item;
console.log('Directive ', this.componentLoader, 'ComponentRef: ', componentRef);
}
}
而组件的HTML:
<!-- Dynamic grid generation using ng-template and ng-content. This is generated several times using the *ngFor, for every item in the items array we will have a componentLoader -->
<ng-template componentLoader>
</ng-template>
这些文件中还有很多内容,但为了简单起见,我只会 post 这个,如果您需要更多代码,请告诉我。
好的,所以我的问题是当我访问 this.contentLoader
时返回的值只是未定义的,所以 this.componentLoader.viewContainerRef
导致错误,因为 componentLoader 未定义。
我已经尝试将 exportAs 属性 添加到指令的装饰器中,但它给出了完全相同的错误。
我也尝试在模块声明中添加指令但没有成功,并将 <ng-template componentLoader>
更改为 <ng-template #loader=componentLoader>
这会导致不同的错误(没有指令具有 'componentLoader' exportAs或类似的东西 )
PS: 在´´´this.componentFacotryResolver.resolveComponentFactory(component)```中我成功地拥有了每个已经被赋予网格的组件。
I prefer you not to solve my issue but to point me in the right direction and help me see what am I doing wrong in order to improve myself.
任何帮助将不胜感激:)
我已经设法以一种非常简单的方式解决了这个问题。
我试图在网格组件中做太多事情,所以我删除了与组件加载器相关的代码,并将其移动到一个名为 ComponentLoaderComponent 的组件中。
在组件内部,我以与在网格组件中相同的方式设置了所有逻辑。所以现在我有一个像这样的新 ts 文件:
import { Component, ComponentFactoryResolver, Input, OnInit, ViewChild } from '@angular/core';
import { ComponentLoaderDirective } from 'src/app/shared/directives/componentLoader.directive';
@Component({
selector: 'component-loader',
templateUrl: './component-loader.component.html',
styleUrls: ['./component-loader.component.css']
})
export class ComponentLoaderComponent implements OnInit {
@Input() public component: any;
@ViewChild(ComponentLoaderDirective, { static: true }) componentLoader!: ComponentLoaderDirective;
constructor(
private componentFactoryResolver: ComponentFactoryResolver
) { }
ngOnInit(): void {
this.loadComponent();
}
loadComponent():void {
if (this.component) {
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.component);
let viewContainerRef = this.componentLoader.viewContainerRef;
viewContainerRef.clear();
let componentRef = viewContainerRef.createComponent<any>(componentFactory);
}
}
还有一个 HTML 这样的:
<ng-template componentLoader>
</ng-template>
现在,在网格组件中,我只需为要添加到网格中的每个组件调用 ComponentLoader,因此网格 html 将如下所示:
<div
*ngIf=" gridItem.components && gridItem.components.length > 0"
class="component-container"
>
<component-loader
*ngFor="let component of gridItem.components"
[component]="component">
</component-loader>
</div >
现在组件正在正确加载,无论如何我仍然不知道我之前错过了什么。
我正在开发一个应用程序,现在,我有一个动态网格生成器,它在屏幕上划分 space 以动态适应多个组件。因此,负责此的组件必须在 angular 呈现页面后呈现组件。为了实现这一点,我遵循了 angular 动态组件加载器指南 (https://angular.io/guide/dynamic-component-loader)。
所以我现在确实有一个必须渲染其他组件的组件,我有我的自定义指令来渲染这些组件。
指令
@Directive({
selector: '[componentLoader]'
})
export class ComponentLoaderDirective {
constructor (
public ViewContainerRef: ViewContainerRef
) {}
}
现在组件(网格组件) grid.component.ts
// ... Stuff above
export class GridComponent implements OnInit {
@Input() public items: gridItem[] = [];
@ViewChild(ComponentLoaderDirective) componentLoader: ComponentLoaderDirective | undefined;
constructor(
private sanitizer: DomSanitizer,
private componentFactoryResolver: ComponentFactoryResolver
) {}
ngOnInit(): void { this.processRow(this.items) }
processRow( row: gridItem[] ) {
// Some grid related stuff ...
for ( let item of row ) {
// Stuff performed over every item in each grid row
this.renderComponentIfNeeded(item)
}
}
renderComponentIfNeeded( item: gridItem ):void {
if ( item.components ) {
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
let viewContainerRef = this.componentLoader.ViewContainerRef;
viewContainerRef.clear();
let componentRef = viewContainerRef.createComponent<any>(componentFactory);
componentRef.instance.data = item;
console.log('Directive ', this.componentLoader, 'ComponentRef: ', componentRef);
}
}
而组件的HTML:
<!-- Dynamic grid generation using ng-template and ng-content. This is generated several times using the *ngFor, for every item in the items array we will have a componentLoader -->
<ng-template componentLoader>
</ng-template>
这些文件中还有很多内容,但为了简单起见,我只会 post 这个,如果您需要更多代码,请告诉我。
好的,所以我的问题是当我访问 this.contentLoader
时返回的值只是未定义的,所以 this.componentLoader.viewContainerRef
导致错误,因为 componentLoader 未定义。
我已经尝试将 exportAs 属性 添加到指令的装饰器中,但它给出了完全相同的错误。
我也尝试在模块声明中添加指令但没有成功,并将 <ng-template componentLoader>
更改为 <ng-template #loader=componentLoader>
这会导致不同的错误(没有指令具有 'componentLoader' exportAs或类似的东西 )
PS: 在´´´this.componentFacotryResolver.resolveComponentFactory(component)```中我成功地拥有了每个已经被赋予网格的组件。
I prefer you not to solve my issue but to point me in the right direction and help me see what am I doing wrong in order to improve myself.
任何帮助将不胜感激:)
我已经设法以一种非常简单的方式解决了这个问题。
我试图在网格组件中做太多事情,所以我删除了与组件加载器相关的代码,并将其移动到一个名为 ComponentLoaderComponent 的组件中。
在组件内部,我以与在网格组件中相同的方式设置了所有逻辑。所以现在我有一个像这样的新 ts 文件:
import { Component, ComponentFactoryResolver, Input, OnInit, ViewChild } from '@angular/core';
import { ComponentLoaderDirective } from 'src/app/shared/directives/componentLoader.directive';
@Component({
selector: 'component-loader',
templateUrl: './component-loader.component.html',
styleUrls: ['./component-loader.component.css']
})
export class ComponentLoaderComponent implements OnInit {
@Input() public component: any;
@ViewChild(ComponentLoaderDirective, { static: true }) componentLoader!: ComponentLoaderDirective;
constructor(
private componentFactoryResolver: ComponentFactoryResolver
) { }
ngOnInit(): void {
this.loadComponent();
}
loadComponent():void {
if (this.component) {
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.component);
let viewContainerRef = this.componentLoader.viewContainerRef;
viewContainerRef.clear();
let componentRef = viewContainerRef.createComponent<any>(componentFactory);
}
}
还有一个 HTML 这样的:
<ng-template componentLoader>
</ng-template>
现在,在网格组件中,我只需为要添加到网格中的每个组件调用 ComponentLoader,因此网格 html 将如下所示:
<div
*ngIf=" gridItem.components && gridItem.components.length > 0"
class="component-container"
>
<component-loader
*ngFor="let component of gridItem.components"
[component]="component">
</component-loader>
</div >
现在组件正在正确加载,无论如何我仍然不知道我之前错过了什么。