Why is ngOnInit called twice?

北慕城南 提交于 2020-01-08 16:22:09

问题


I trying to create new component, ResultComponent, but its ngOnInit() method is getting called twice and I don't know why this is happening. In the code, ResultComponent inherits @Input from the parent component mcq-component.

Here is the code:

Parent Component (MCQComponent)

import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'mcq-component',
    template: `
        <div *ngIf = 'isQuestionView'>
            .....
        </div>
        <result-comp *ngIf = '!isQuestionView' [answers] = 'ansArray'><result-comp>
    `,
    styles: [
        `
            ....
        `
    ],
    providers: [AppService],
    directives: [SelectableDirective, ResultComponent]
})
export class MCQComponent implements OnInit{
      private ansArray:Array<any> = [];
    ....
    constructor(private appService: AppService){}
    ....
}

Child Component (result-comp)

import { Component, OnInit, Input } from '@angular/core';

@Component({
    selector:'result-comp',
    template: `
        <h2>Result page:</h2>

    `
})
export class ResultComponent implements OnInit{
    @Input('answers') ans:Array<any>;

    ngOnInit(){
        console.log('Ans array: '+this.ans);
    }
}

When run, console.log is showing up two times, the first time it shows the correct array but the second time it gives undefined. I've not been able to figure it out: why is ngOnInit in ResultComponent getting called twice?


回答1:


Why it is called twice

Right now, if an error happens during detecting changes of content/view children of a component, ngOnInit will be called twice (seen in DynamicChangeDetector). This can lead to follow up errors that hide the original error.

This information comes from this github issue


So it seems that your mistake might have an origin elsewhere in your code, related to this component.




回答2:


This was happening to me because of a faulty component html. I had forget to close the selector tag in the host component. So I had this <search><search>, instead of <search></search> - take note of the syntax error.

So related to @dylan answer, check your component html structure and that of its parent.




回答3:


if you used platformBrowserDynamic().bootstrapModule(AppModule); in app.module.ts comment it and try. I had the same problem. I think this helps




回答4:


Well the Problem in my case was the way I was bootstrapping the Child Components. In my @NgModule decorator’s metadata object ,I was passing ‘child component’ in the bootstap property along with ‘parent component’. Passing the child components in bootstap property was resetting my child components properties and making OnInit() fired twice.

@NgModule({
imports: [ BrowserModule,FormsModule ], // to use two-way data binding ‘FormsModule’
declarations: [ parentComponent,Child1,Child2], //all components
//bootstrap: [parentComponent,Child1,Child2] // will lead to errors in binding Inputs in Child components
bootstrap: [parentComponent] //use parent components only
})



回答5:


Putting this here in case someone wind up here. NgOnInit can also be called twice if your browser's default button type is "submit", say if you have the below, NgOnInit of NextComponent will be called twice in Chrome:

<button class="btn btn-primary" (click)="navigateToNextComponent()">

To fix it, set type:

<button class="btn btn-primary" type="button" (click)="navigateToNextComponent()">



回答6:


This may happen because you set the AppComponent as your default route

RouterModule.forRoot([
    { path: '', component: AppComponent }  // remove it
])

Note: AppComponent is called by default in angular so need not to call it




回答7:


The ngOnInit() hooks only once after all directives are instantiated. If you have subscription insidengOnInit() and it's not unsubscribed then it will run again if the subscribed data changes.

In the following Stackblitz example I have subscription inside ngOnInit() and console the result. It console twice because it loads once and data changes and it loads again.

Stackblitz




回答8:


This happens whenever there are any template errors.

In my case I was using a wrong template reference and correcting that fixed my issue..




回答9:


In my case, this is happened when Component implements both OnChanges and OnInit. Try to remove one of these classes. You can also use ngAfterViewInit method, it is triggered after the view initialized, so that it is guaranteed to called once.




回答10:


This happened to me because I had unnamed <router-outlet>s inside of an *ngFor. It loaded for each iteration in the loop.

The solution, in that case, would be to have a unique name for each outlet or make sure that there is only one in the DOM at a time (perhaps w/ an *ngIf).




回答11:


I had a similar issue myself, I was calling for a component and then referencing the same component via the router-outlet.

<layout>
  <router-outlet></router-outlet>
</layout>

And the outlet route was also pointing to Layout.




回答12:


For me, this happened because I registered same component twice in Route:

{
        path: 'meal-services',
        children: [
          {
            path: '',
            component: InitTwiceComponent,
            canActivate: [AppVendorOpsGuard],
            data: { roleWhitelist: [UserRoles.Manage] }
          },
          {
            path: ':itemID',
            component: InitTwiceComponent,
            canActivate: [AppVendorOpsGuard],
            data: { roleWhitelist: [UserRoles.Manage] }
          }]
      },
}



回答13:


In my case I did not unsubscribe to all the subscriptions that I had inside ngOnInit. I just unsubscribed from all the subscriptions within ngOnDestroy and that resolved my issue.



来源:https://stackoverflow.com/questions/38787795/why-is-ngoninit-called-twice

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!