web-dev-qa-db-fra.com

Pourquoi appelle-t-on deux fois ngOnInit?

J'essaie de créer un nouveau composant, ResultComponent, mais sa méthode ngOnInit() est appelée deux fois et je ne sais pas pourquoi cela se produit. Dans le code, ResultComponent hérite de @Input du composant parent mcq-component.

Voici le code:

Composant parent (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){}
    ....
}

Composant enfant (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);
    }
}

Lorsqu'il est exécuté, console.log apparaît deux fois, la première fois, il affiche le tableau correct, mais la deuxième fois, il donne undefined. Je n'ai pas été capable de comprendre: pourquoi ngOnInit dans ResultComponent est-il appelé deux fois?

42
Shree

Pourquoi on l'appelle deux fois

À l'heure actuelle, si une erreur survient lors de la détection des modifications des enfants de contenu/vue d'un composant, ngOnInit sera appelé deux fois (visible dans DynamicChangeDetector). Cela peut entraîner des erreurs de suivi qui cachent l'erreur d'origine.

Cette information provient de ceci numéro de github


Il semble donc que votre erreur pourrait avoir une origine ailleurs dans votre code, liée à ce composant.

37
Dylan Meeus

Cela m'arrivait à cause d'un composant HTML défectueux. J'avais oublié de fermer la balise de sélection dans le composant Host. Alors j'ai eu ce <search><search>, au lieu de <search></search> - notez l'erreur de syntaxe.

Relativement lié à @dylan answer, vérifiez la structure html de votre composant et celle de son parent.

16
orsonady

Eh bien, le problème dans mon cas était la façon dont je bootais les composants enfants. Dans mon @ NgModule objet de métadonnées du décorateur, je passais 'composant enfant' dans la propriété bootstap avec 'composant parent '. Le passage des composants enfants dans la propriété bootstap était réinitialisation mes composants enfants propriétés et rendant OnInit () déclenché deux fois.

@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
})
14
Amardeep Kohli

si vous avez utilisé platformBrowserDynamic().bootstrapModule(AppModule); dans app.module.ts, commentez-le et essayez. J'ai eu le même problème. Je pense que cela aide

12
Scott Machlovski

Mettre ceci ici au cas où quelqu'un finirait par là. NgOnInit peut également être appelé deux fois si le type de bouton par défaut de votre navigateur est "submit". Par exemple, si vous avez le texte ci-dessous, NgOnInit de NextComponent sera appelé deux fois dans Chrome:

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

Pour résoudre ce problème, définissez le type:

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

Cela peut arriver parce que vous avez défini le AppComponent comme itinéraire par défaut.

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

Remarque: AppComponent est appelé par défaut dans angular alors vous n'avez pas besoin de l'appeler

7
WasiF

La ngOnInit() ne raccroche qu'une seule fois après l'instanciation de toutes les directives. Si vous avez un abonnement insidengOnInit() et qu'il n'est pas désabonné, il s'exécutera à nouveau si les données souscrites changent.

Dans l'exemple suivant de Stackblitz, j'ai souscrit un abonnement dans ngOnInit() et je console le résultat. Il console deux fois parce qu'il charge une fois et que les données changent et se chargent à nouveau.

Stackblitz

3
Maihan Nijat

Cela se produit chaque fois qu'il y a des erreurs de modèle.

Dans mon cas, j’utilisais un mauvais modèle de référence et je corrigeais le problème.

3
Bharat Raj

Cela m'est arrivé parce que j'avais non nommé <router-outlet>s à l'intérieur d'un *ngFor. Il a chargé pour chaque itération dans la boucle.

La solution, dans ce cas, consisterait à attribuer un nom unique à chaque sortie ou à s’assurer qu’il n’en existe qu’un dans le DOM à la fois (peut-être avec un *ngIf).

1
Kevin Beal

Dans mon cas, cela se produit lorsque Component implémente à la fois OnChanges et OnInit. Essayez de supprimer l'une de ces classes. Vous pouvez également utiliser la méthode ngAfterViewInit, elle est déclenchée après l’initialisation de la vue, de sorte qu’elle soit garantie une fois appelée.

1
Cem Mutlu

Pour moi, cela est dû au fait que j'ai enregistré le même composant deux fois dans Route:

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

J'avais moi-même un problème similaire: je demandais un composant, puis je faisais référence au même composant via le routeur-prise.

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

Et la voie de sortie pointait également vers Layout.

0
CodeMylife

Dans mon cas, je ne me suis pas désabonné de tous les abonnements que j'avais à l'intérieur de ngOnInit. Je viens désabonné de tous les abonnements au sein de ngOnDestroy et cela a résolu mon problème.

0
Sudharsan Prabu