ngOnInit n'est pas appelé lorsque la classe Injectable est instanciée

215

Pourquoi n'est-il pas ngOnInit()appelé lorsqu'une Injectableclasse est résolue?

Code

import {Injectable, OnInit} from 'angular2/core';
import { RestApiService, RestRequest } from './rest-api.service';

@Injectable()
export class MovieDbService implements OnInit {

    constructor(private _movieDbRest: RestApiService){
        window.console.log('FROM constructor()');
    }

    ngOnInit() {
         window.console.log('FROM ngOnInit()');
    }

}

Sortie de la console

FROM constructor()
Levi Fuller
la source

Réponses:

328

Crochets de cycle de vie , comme le OnInit()travail avec les directives et les composants. Ils ne fonctionnent pas avec d'autres types, comme un service dans votre cas. À partir de la documentation:

Un composant a un cycle de vie géré par Angular lui-même. Angular le crée, le rend, crée et rend ses enfants, le vérifie lorsque ses propriétés liées aux données changent et le détruit avant de le supprimer du DOM.

Les instances de directive et de composant ont un cycle de vie car Angular les crée, les met à jour et les détruit.

Sasxa
la source
39
Alors déplacez simplement ma ngOnInitlogique vers le constructeur pour les Injectableclasses? Je me souviens juste d'avoir lu que vous devriez garder toute logique hors du constructeur pour une raison quelconque.
Levi Fuller le
49
@LeviFuller Oui, pour les services, vous pouvez effectuer l'initialisation dans le constructeur, ou mieux créer la méthode init et l'appeler depuis le constructeur (au cas où vous auriez besoin de réinitialiser un service plus tard).
Sasxa
9
Pas exactement, OnInit a à voir avec la liaison. Vous l'utilisez lorsque vous souhaitez attendre que les valeurs d'entrée soient résolues, car elles ne sont pas disponibles dans le constructeur. Le constructeur peut être appelé plusieurs fois. Par exemple, lorsque vous changez d'itinéraire et chargez différents composants, ils sont «construits» et détruits à chaque fois ...
Sasxa
5
Il convient également de noter ici que les services peuvent être instanciés plusieurs fois, en fonction de l'endroit où vous les incluez dans les providerstableaux. Si vous voulez un service singleton, placez-le dans votre module principal providers, et si vous voulez des services par composant, ajoutez-les directement au composant.
Askdesigners
4
Ce n'est pas tout à fait incorrect, car @ SBD580 points dans sa réponse, ngOnDestroyest appelé pour des services injectés
shusson
54

Je ne connais pas tous les hooks du cycle de vie, mais en ce qui concerne la destruction, je suis en ngOnDestroyfait appelé sur Injectable lorsque son fournisseur est détruit (par exemple un Injectable fourni par un composant).

Du docs :

Crochet de cycle de vie appelé lorsqu'une directive, un canal ou un service est détruit.

Juste au cas où quelqu'un serait intéressé par la destruction, vérifiez cette question:

SBD580
la source
4
une telle honte ngOnInitn'est pas appelée :-( Je voulais vraiment faire de la magie d'initialisation retardée transparente. Si ngOnDestroypeut être appelée, je ne vois pas pourquoi init ne peut pas
Simon_Weaver
3

J'ai dû appeler une fonction une fois mon dataService initialisé, à la place, je l'ai appelée dans le constructeur, cela a fonctionné pour moi.

Eduardo A EDUARDO Fernandez Di
la source
2

Remarque: cette réponse s'applique uniquement aux composants et directives angulaires, PAS aux services.

J'ai eu ce même problème lorsque ngOnInit(et d'autres hooks de cycle de vie) ne tiraient pas pour mes composants, et la plupart des recherches m'ont conduit ici.

Le problème est que j'utilisais la syntaxe de la fonction de flèche ( =>) comme ceci:

class MyComponent implements OnInit {
    // Bad: do not use arrow function
    public ngOnInit = () => {
        console.log("ngOnInit");
    }
}

Apparemment, cela ne fonctionne pas dans Angular 6. L'utilisation d'une syntaxe de fonction sans flèche résout le problème:

class MyComponent implements OnInit {
    public ngOnInit() {
        console.log("ngOnInit");
    }
}
AJ Richardson
la source
1
Les classes injectables sont des services, pas des composants. OP demande un service. Bien que votre réponse puisse être correcte à partir d'un PDV de langue, elle ne répond pas à cette question. Vous devriez le supprimer.
Andrew Philips
@AndrewPhilips alors que mon cas d'utilisation est légèrement différent de celui des OP, une recherche google pour "ngOnInit not called" conduit les gens ici. Mon objectif avec cette réponse n'est pas d'aider l'OP, mais d'aider l'un des 70 000 autres téléspectateurs qui pourraient avoir des problèmes similaires ngOnInit.
AJ Richardson
C'est suffisant. Je crois avoir vu SO Q&A dans lequel un auteur pose puis répond à sa propre question. En tant que nouveau programmeur Angular, votre réponse m'aurait confondu il y a deux semaines. Du point de vue SO et NG, je pense que votre réponse est digne de sa propre Question, donc non supprimée mais «recatégorisée». Qui sait? Peut-être que cela pourrait toucher un public encore plus large. À votre santé.
Andrew Philips
1
Cela a du sens - j'ai modifié ma réponse pour indiquer clairement que ce n'est pas pour les services.
AJ Richardson
0
import {Injectable, OnInit} from 'angular2/core';
import { RestApiService, RestRequest } from './rest-api.service';
import {Service} from "path/to/service/";

@Injectable()
export class MovieDbService implements OnInit {

userId:number=null;

constructor(private _movieDbRest: RestApiService,
            private instanceMyService : Service ){

   // do evreything like OnInit just on services

   this._movieDbRest.callAnyMethod();

   this.userId = this.instanceMyService.getUserId()


}
hassan khademi
la source