Component constructor is getting called twice with

2019-08-19 15:47发布

I am working on a recursive query builder form, which is something similar to this, in angular 7, with reactive form. Means, the user can keep adding a parallel rule by clicking on Add rule and can add a group by clicking on Add group. I have created two components, QueryDesignerComponent and QueryComponent. QueryDesignerComponent holds the outer container, with AND and OR condition and QueryComponent holds the row input, that's LHS, operator and RHS.

  1. When user clicks Add rule I am growing the rule just by pushing one more entry with QueryComponent inside QueryDesignerComponent. I am repeating this with *ngFor.
  2. When the user clicks Add group I am callings the QueryDesignerComponent inside QueryComponent, which makes it recursive. I am repeating this with *ngFor.

I am done with the implementation and its working fine within angular app, which has an angular environment.

Now, I am trying to port this flow in angular elements, to make it reusable, regardless of the environment.

this is how I am placing first row [ QueryComponent ] inside 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>

and this way I am managing the parallel query and groups inside 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-->

This is how I am creating a custom angular element,

@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() { }
}

In the first render, it's working fine and I am able to add n number of parallel rows. But, when I click the Add group, QueryDesignerComponent's constructor is getting called twice! This makes the first instance of QueryDesignerComponent to receive undefined and second instance to receive correct values.

I followed why ngOnInit called twice?, related github issue and ngOnInit and Constructor are called twice but, I found no luck!!

Does anyone know how can I get rid of this issue? Any help/guidance would be much appreciated!

2条回答
疯言疯语
2楼-- · 2019-08-19 15:51

Another possibility might be the following piece of code in app.module.ts

platformBrowserDynamic().bootstrapModule(AppModule).catch(err => { console.error(err) });
查看更多
放我归山
3楼-- · 2019-08-19 16:04

I just had the same issue, with Angular Elements too.

Problem was that I was calling an Angular7 component inside an Angular7 component, and on app.module.ts I had bootstrapped the child component with the same name as the Angular7 component name.

When parent called my-child-component it was calling both the Angular7 one and the Custom Element one.

So, the fix is to use different names in this case.

查看更多
登录 后发表回答