使用 Angular 元素调用组件构造函数两次
Posted
技术标签:
【中文标题】使用 Angular 元素调用组件构造函数两次【英文标题】:Component constructor is getting called twice with Angular elements 【发布时间】:2019-07-05 01:45:06 【问题描述】:我正在开发一个递归查询构建器表单,它类似于 this,在 angular 7 中,具有反应式表单。也就是说,用户可以通过点击Add rule
继续添加并行规则,并且可以通过点击Add group
添加组。
我创建了两个组件,QueryDesignerComponent
和 QueryComponent
。 QueryDesignerComponent
保存外部容器,AND
和 OR
条件和 QueryComponent
保存行输入,即 LHS
、operator
和 RHS
。
-
当用户单击
Add rule
时,我只是通过在QueryDesignerComponent
内再推一个带有QueryComponent
的条目来扩展规则。我用*ngFor
重复这个。
当用户单击Add group
时,我在QueryComponent
中调用QueryDesignerComponent
,这使其递归。我用*ngFor
重复这个。
我已经完成了实现及其在 Angular 应用程序中的正常工作,该应用程序具有 Angular 环境。
现在,我正在尝试将此流程移植到angular elements,以使其可重复使用,而不管环境如何。
这就是我将第一行 [QueryComponent
] 放在 QueryDesignerComponent
中的方式,
<div class="qd--criteria">
<div class="row qd--body qd--clear-margin-lr">
<div class="col-md-12 qd--condition-container">
<query [data]="data" [operators]="operators" [(queryForm)]="queryForm"></query>
</div>
</div>
</div>
这样我就可以管理QueryComponent
中的并行查询和组,
<!--Top level container for query view | everything related should go here: start-->
<div class="qd--query-container" [formGroup]="queryForm" *ngIf="queryForm">
<div class="row" formArrayName="queries">
<!--Repeat the dynamically added/removed queries: start-->
<div class="col-md-12 qd--query-inputs-container" *ngFor="let query of currentQueries.controls; let queryIndex = index">
<div class="row qd--query-inputs" [formGroupName]="queryIndex">
<!--Actual query inputs: start-->
<div class="col-md-10 qd--condition-holder">
<div class="row no-gutter">
<!--Left hand side input: start-->
<!--Left hand side input: end-->
<!--Operator: start-->
<!--Operator: end-->
<!--Right hand side input: start-->
<!--Right hand side input: end-->
</div>
</div>
<!--Actual query inputs: start-->
<!--Group options: start-->
<!--Group options: end-->
<!--Group query: start-->
<div *ngIf="query !== undefined" class="ai--query-groups">
<div *ngFor="let group of getGroups(query).controls; let groupIndex=index" class="ai--query-group">
<query-designer
[data]="data"
[operators]="operators"
[queryForm]="group"
(removeQueryGroup)="removeQueryGroupHandler($event)"
[queryIndex]="queryIndex"
[groupIndex]="groupIndex"></query-designer>
</div>
</div>
<!--Group query: end-->
</div>
</div>
<!--Repeat the dynamically added/removed queries: end-->
</div>
</div>
<!--Top level container for query view: start-->
<!--Repeat the dynamically added/removed queries: start-->
<div class="col-md-12 qd--query-inputs-container" *ngFor="let query of currentQueries.controls; let queryIndex = index">
<div class="row qd--query-inputs" [formGroupName]="queryIndex">
<!--Actual query inputs: start-->
<div class="col-md-10 qd--condition-holder">
<div class="row no-gutter">
<!--Left hand side input: start-->
<!--Left hand side input: end-->
<!--Operator: start-->
<!--Operator: end-->
<!--Right hand side input: start-->
<!--Right hand side input: end-->
</div>
</div>
<!--Actual query inputs: start-->
<!--Group options: start-->
<!--Group options: end-->
<!--Group query: start-->
<div *ngIf="query !== undefined" class="ai--query-groups">
<div *ngFor="let group of getGroups(query).controls; let groupIndex=index" class="ai--query-group">
<query-designer
[data]="data"
[operators]="operators"
[queryForm]="group"
(removeQueryGroup)="removeQueryGroupHandler($event)"
[queryIndex]="queryIndex"
[groupIndex]="groupIndex"></query-designer>
</div>
</div>
<!--Group query: end-->
</div>
</div>
<!--Repeat the dynamically added/removed queries: end-->
这就是我创建自定义角度元素的方式,
@NgModule(
imports: [
CommonModule,
BrowserModule,
NgSelectModule,
FormsModule,
ReactiveFormsModule,
CoreModule
],
declarations: [
AppComponent,
QueryComponent,
QueryDesignerComponent
],
entryComponents: [QueryDesignerComponent],
providers: []
)
export class AppModule
constructor(private injector: Injector)
const strategyFactory = new ElementZoneStrategyFactory(QueryDesignerComponent, injector);
const customElement = createCustomElement(QueryDesignerComponent, injector, strategyFactory );
customElements.define('query-designer', customElement);
ngDoBootstrap()
在第一次渲染中,它工作正常,我可以添加n
并行行数。但是,当我单击Add group
时,QueryDesignerComponent
的构造函数被调用了两次!这使得QueryDesignerComponent
的第一个实例接收undefined
,第二个实例接收正确的值。
我关注了why ngOnInit called twice?,相关的github issue 和ngOnInit and Constructor are called twice 但是,我没有找到运气!!
有谁知道我怎样才能摆脱这个问题?任何帮助/指导将不胜感激!
【问题讨论】:
请提供更多代码以使此问题可重现。 您是否尝试使用延迟加载来加载此模块? angular.io/guide/lazy-loading-ngmodulesgithub.com/angular/angular/issues/12869 @web.dev,添加了更多代码。请看一下 @JoelGarciaNuño,让我检查一下。在跳转实际链接之前,这是一个非常快速的问题,但它对角度元素有帮助吗? 这有助于加载一次组件,可能不会再次调用构造函数。使用延迟加载,在你的路由器路径上使用#angular.io/guide/lazy-loading-ngmodules#routes-at-the-app-level,但是休息一下,可能是一个简单的问题,当你按下按钮超过两次时,调用了多少次构造函数? 【参考方案1】:我也遇到了同样的问题,Angular Elements 也是。
问题是我在 Angular7 组件中调用了 Angular7 组件,并且在 app.module.ts 上我引导了与 Angular7 组件名称相同名称的子组件。
当父级调用 my-child-component 时,它同时调用了 Angular7 和自定义元素。
因此,解决方法是在这种情况下使用不同的名称。
【讨论】:
【参考方案2】:另一种可能性可能是 app.module.ts 中的以下代码
platformBrowserDynamic().bootstrapModule(AppModule).catch(err => console.error(err) );
【讨论】:
您能否进一步解释这是如何导致问题的。 这实际上对我有用!第一次加载页面时,我看到我的组件被加载了两次。删除该行解决了问题,但我仍然不确定为什么。【参考方案3】:我试过这个并为 Angular 元素工作。 从 @NgModule 中移除 Bootstrap 并在 ngDoBootstrap 中添加自定义元素定义而不是构造函数。
请参考以下代码。
@NgModule(
declarations: [
MyComponent
],
imports: [
BrowserModule,
HttpClientModule
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
],
providers: [MyService]
)
export class AppModule implements DoBootstrap
constructor(private injector: Injector)
ngDoBootstrap(appRef: ApplicationRef)
const el = createCustomElement(MyComponent, injector: this.injector );
customElements.define('my-widget', el);
【讨论】:
以上是关于使用 Angular 元素调用组件构造函数两次的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Angular 2 中调用其构造函数之前将数据发送或绑定到子组件?
为啥不应该在Angular中组件的构造函数中进行数据初始化?
从 Angular2 路由中的子组件调用 router.parent.navigate 方法时未触发组件构造函数和路由器生命周期挂钩