javascript - 动态加载的 Angular 10 组件无法访问 CommonModule
问题描述
我目前正在开发一个 Angular 应用程序。在我的一种方法中,我动态创建了一个组件,但是我无法使用ngClass
,ngIf
以及来自组件中的其他此类指令CommonModule
。
以下是错误示例:
在动态加载的徽标组件中使用 ngIf 或 ngClass 时出错
我已经做了什么:
- 我在我的项目 app.module.ts 中导入了 commonModule
- 我已经在我的显示组件中导入了 commonModule,它可以正常工作,因为我可以在每个其他组件中使用 ngIf 和 ngClass 而没有任何问题
- 此外,只要我没有在我的 html 中使用 CommonModule 中的任何指令,我就可以毫无错误地导入任何组件
- 我尝试通过组件工厂 createComponent 函数导入 NgModule 的实例,如角度文档中所示:
快速查看组件工厂 createcomponent 的角度文档
我已经为此花费了几个小时,并相信这与我使用该createComponent
方法有关。
请帮忙!
这是我的 app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule, HammerGestureConfig, HammerModule,
HAMMER_GESTURE_CONFIG } from '@angular/platform-browser';
import { GoogleAnalyticsService } from
'./shared/services/googleanalytics'; // import our Google Analytics
service
import { BrowserAnimationsModule } from '@angular/platform-
browser/animations';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { CommonModule } from '@angular/common';
@NgModule({
declarations: [AppComponent],
imports: [
CommonModule,
BrowserModule,
AppRoutingModule,
HttpClientModule,
BrowserAnimationsModule,
],
providers: [GoogleAnalyticsService],
bootstrap: [AppComponent],
})
export class AppModule {}
这是我的显示组件 (Bdoc-a.component.ts)
import {
Component, OnInit, Input, Output, Renderer2, AfterViewInit,
AfterContentChecked, ViewChild, ElementRef,
ComponentFactoryResolver, ViewContainerRef, ViewChildren, QueryList
} from '@angular/core';
import { StorageService } from
'../../../../shared/services/storage.service';
import { AuthService } from '../../../../auth/auth.service';
@Component({
selector: 'app-bdoc-a',
templateUrl: './bdoc-a.component.html',
styleUrls: ['./bdoc-a.component.scss'],
})
export class BdocAComponent implements OnInit, AfterViewInit,
AfterContentChecked {
@Input() docConfig = { aspectRatio: '4:3', width: 800, height: 500 };
@Input() bgStyles = { shadow: true, bgClr: '#ffcc00' };
@Input() showBtns = false;
fWidth = this.docConfig.width;
fMaxWidth = this.docConfig.width;
fHeight = this.docConfig.height;
fMaxHeight = this.docConfig.height;
@Input() url = '';
@Input() settings = { ... };
...
@ViewChildren('loadDynAssetElEditItms', { read: ViewContainerRef })
biEditEls: QueryList<ViewContainerRef>;
@ViewChildren('loadDynAssetElViewItms', { read: ViewContainerRef })
biViewEls: QueryList<ViewContainerRef>;
loadDynAssetEl: any;
@ViewChild('bieditorFloat', { read: ElementRef }) bieditorFloat:
ElementRef;
@ViewChild('bieditorFloatViewer', { read: ElementRef })
bieditorFloatViewer: ElementRef;
// variable to hold all document page elements
allDocPages: any;
allDocPageComp = [];
constructor(private storage: StorageService,
private resolver: ComponentFactoryResolver,
private authService: AuthService,
private elmRef: ElementRef) {
this.url = 'templates/logo/1/logo1a/logo1a.component';
}
ngAfterViewInit(): void {
this.initBrandAsset();
}
initBrandAsset(): void {
this.allDocPageComp = [];
setTimeout(() => {
for (let i = 0; i < this.pages; i++) {
this.loadDynAsset(this.url, i);
}
this.setDocPageVar();
}, 200);
}
async loadDynAsset(url, pgIndex) {
const impEl = await import( 'src/app/' + url);
const allKeys = Object.keys(impEl);
this.biEditEls.forEach((itm, i) => {
if (i === pgIndex) {
itm.clear();
const newComp = itm.createComponent(
this.resolver.resolveComponentFactory(impEl[allKeys[0]]));
newComp.instance['bol']['test'] = 'LOGO TEST TEXT HERE... ' + pgIndex;
this.allDocPageComp.push(newComp.instance);
}
});
}
}
这是我的 Logo1a.component.html
<div class="baItem biLogo logo1a edit">
<div class="null bilNull">
<ng-container>
<div class="bilSymb">
<div class="null">
<div #forTxtLogo class="forTxtLogo" *ngIf="config.symb.mode ===
'txt'">
<div class="symbItm"><div class="nl">B</div></div><div
class="symbItm"><div class="nl">S</div></div>
</div>
<div #forImgSvgLogo class="forImgSvgLogo" *ngIf="config.symb.mode
=== 'svg' || config.symb.mode === 'img'">
<div class="symbItm"><div class="nl"></div></div>
</div>
</div>
</div><!-- end of bilSymb -->
</ng-container>
<ng-container *ngIf="config.body.show">
<div class="bilBody">
<div class="null">
<ng-container *ngIf="config.body.txt.show">
<div #forTxtArea class="forTxtArea">
<div class="null">Logo Body Text Area</div>
</div>
</ng-container>
<ng-container *ngIf="config.body.tag.show">
<div #forTagArea class="forTagArea"><div class="null">Logo Tag
Area...</div></div>
</ng-container>
</div>
</div><!-- end of bilBody -->
</ng-container>
</div><!-- end of biNull -->
</div><!-- end of biLogo-->
这是我的 Logo1a.component.ts
import { NgModule, Component, OnInit, Input, Output, Renderer2,
AfterViewInit, AfterContentChecked, ViewChild, ElementRef,
ComponentFactoryResolver, ViewContainerRef, ViewChildren, QueryList
} from '@angular/core';
import { StorageService } from
'../../../../shared/services/storage.service';
import { AuthService } from '../../../../auth/auth.service';
@Component({
selector: "app-logo1a",
templateUrl: "./logo1a.component.html",
styleUrls: ["./logo1a.component.scss"],
})
export class Logo1aComponent implements OnInit, AfterViewInit {
@ViewChild('loadExtra', { read: ViewContainerRef }) loadExtra:
ViewContainerRef;
@Input() bol = { test: 'LOGO 1A LOADED!' }; // breadth of life
public config = {
symb: {
show: true,
mode: 'txt', // 'txt', 'symb', 'img'
},
body: {
show: true,
txt: { show: true },
tag: { show: true }
}
}
constructor(private storage: StorageService,
private resolver: ComponentFactoryResolver,
private vcRef: ViewContainerRef,
private authService: AuthService,
private elmRef: ElementRef) { }
ngOnInit(): void {}
ngAfterViewInit() {}
}
这是我的 Logo1a.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Logo1aComponent } from './logo1a.component';
@NgModule({
imports: [CommonModule],
declarations: [Logo1aComponent],
exports: [Logo1aComponent]
})
export class Logo1aModule {}
但这是我在我的 Angular 10 应用程序中动态导入模块而不是组件后引发的错误,正如@jburtondev 建议的那样:
错误错误:未捕获(在承诺中):错误:断言错误:传入的类型不是 ComponentType,它没有“ɵcmp”属性。……
解决方案
所以我终于有了一个不太干净的工作方法来解决我的问题。
我创建了一个新模块 LogoModules,我在其中导入了将在显示组件中显示的所有徽标模块
从'@angular/core'导入{ NgModule };从'../templates/logo/1/logo1a/logo1a.module'导入{ Logo1aModule };从'../templates/logo/2/logo2a/logo2a.module'导入{ Logo2aModule };从'../templates/logo/3/logo3a/logo3a.module'导入{ Logo3aModule };
@NgModule({ // 导入:[], // 导出:[], })
导出类 LogoModules {}
这从@jburtondev 的建议中进行了一些修改,以预先导入所有模块,但我仍然认为应该有一种更简洁的方法来完成这部分。在不预先导入模块的情况下动态加载模块和组件仍然有效,但有时也会失败。我认为这是由于 tsconfig 中的编译器和 webpack 的一些设置。我需要更多的研究来澄清这一点。
我在显示组件中导入了 LogoModules 模块
从'../templates/logo/logos.module'导入{ LogoModules };...
但是......所以我能够将每个徽标模板的相对路径存储在我的数据库中并根据用户点击动态显示它们,我在我的显示组件(Bdoc-a.component.ts)中更新了我的动态组件加载器,如图所示以下:
....
async loadDynAsset(url, pgIndex) {
const mObj = await import('src/app/' + url2);
const mKeys = Object.keys(mObj);
const mName = mKeys[0];
this.compiler.compileModuleAndAllComponentsAsync(mObj[mName])
.then((factories) => {
const f = factories.componentFactories[0];
const newComp = this.testDynComp.createComponent(f);
newComp.instance['bol']['test'] = 'LOGO TEST TEXT HERE... ' + pgIndex;
});
....
}
....
然后我能够得到一致的结果而没有错误。再次感谢@jburtondev 的一些建议。一旦我发现更好的方法来解决我的问题,我会立即更新我的答案。
推荐阅读
- excel - 隐藏工作表时,VBA Excel将元素复制到整个工作簿
- python - 如何使用 pynput.keyboard 模块输入 UTF-8 表情符号
- api - 在 NiFi 中使用报告任务提取摘要报告以进行监控
- javascript - 为什么`function test(){} + 1;`的输出是1?
- java - Tomcat上的Spring Boot War部署不起作用
- java - java编译失败,其中带有jar文件的类路径
- php - 如何使用 jQuery AJAX 将数组发送到 Codeigniter
- mysql - 按查询分组 - 选择具有最大日期的行
- python - Keras ValueError:logits 和标签必须具有相同的形状 ((None, 32, 17) vs (None, 17))
- python - Python根据时间戳对文件内容进行排序并将其写入新文件?