Angular.js: Ordre des hooks des contrôleurs ($onChanges appelé avant $onInit)

Créé le 16 déc. 2016  ·  9Commentaires  ·  Source: angular/angular.js

Vous souhaitez demander une fonctionnalité ou signaler un bug ?
Je ne sais pas si c'est voulu ou si c'est un bug

Quel est le comportement actuel ?
Le premier appel $onChanges est effectué avant le $onInit .
Avec la configuration par défaut angulaire 1.6 (preassign = false), il est préférable d'initialiser les états du contrôleur dans la fonction $onInit , étant donné que les liaisons ne sont pas encore accessibles dans le constructeur.

Quel est le comportement attendu ?
Je pense qu'il serait plus logique d'appeler $onInit premier.
Angular ne devrait rien faire tant que le contrôleur n'est pas complètement initialisé.

Quelle est la motivation / le cas d'utilisation pour changer le comportement ?
Si nous utilisons des objets qui sont censés être créés dans la fonction $onInit dans la fonction $onChanges ; nous aurons une erreur au premier appel, car le contrôleur n'a pas encore été initialisé.
Une solution pourrait être d'initialiser ces objets à l'intérieur du constructeur, mais nous initialiserons le contrôleur à deux endroits différents...

Quelles versions d'Angular et quel navigateur / système d'exploitation sont concernés par ce problème ? Veuillez également tester avec les dernières versions stable et instantanée (https://code.angularjs.org/snapshot/).
version 1.6 angulaire

works as expected

Commentaire le plus utile

Ceci est destiné (principalement pour correspondre au comportement Angular 2+). Au cas où vous l'auriez manqué, vous pouvez vérifier s'il s'agit du premier appel (pré-$onInit) de $onChanges , en vérifiant la valeur de retour de la méthode isFirstChange() de l'un des SimpleChange Objets

{
  ...
  bindings: {foo: '<'},
  controller: function SomeController() {
    this.$onChanges = function(changes) {
      if (changes.foo.isFirstChange()) {
        // `$onInit()` has not been called yet...
      }
    };
  }
}

#

J'avoue que ma première réaction a été la même. Du point de vue du modèle mental, il est plus facile de penser que $onInit() est la première chose qui se passe dans le contrôleur ; puis $onChanges() , $onChanges() , $onChanges() et enfin $onDestroy() .

Mais si vous y réfléchissez, les liaisons doivent être évaluées et affectées à l'instance du contrôleur avant d'appeler $onInit . Et ce faisant, un changement dans les valeurs (auparavant non définies) est détecté, qui à son tour doit être signalé via $onChanges .

Fermeture, car cela fonctionne comme prévu (ou au moins comme prévu :wink:).

Tous les 9 commentaires

Ceci est destiné (principalement pour correspondre au comportement Angular 2+). Au cas où vous l'auriez manqué, vous pouvez vérifier s'il s'agit du premier appel (pré-$onInit) de $onChanges , en vérifiant la valeur de retour de la méthode isFirstChange() de l'un des SimpleChange Objets

{
  ...
  bindings: {foo: '<'},
  controller: function SomeController() {
    this.$onChanges = function(changes) {
      if (changes.foo.isFirstChange()) {
        // `$onInit()` has not been called yet...
      }
    };
  }
}

#

J'avoue que ma première réaction a été la même. Du point de vue du modèle mental, il est plus facile de penser que $onInit() est la première chose qui se passe dans le contrôleur ; puis $onChanges() , $onChanges() , $onChanges() et enfin $onDestroy() .

Mais si vous y réfléchissez, les liaisons doivent être évaluées et affectées à l'instance du contrôleur avant d'appeler $onInit . Et ce faisant, un changement dans les valeurs (auparavant non définies) est détecté, qui à son tour doit être signalé via $onChanges .

Fermeture, car cela fonctionne comme prévu (ou au moins comme prévu :wink:).

Merci beaucoup pour ta réponse, c'est plus clair maintenant :)

Je comprends que c'est intentionnel, que diriez-vous si nous enregistrons la définition de la fonction $onChanges() dans $onInit().

@bharatpatil , cela devrait fonctionner dans AngularJS (1.x.) mais pas dans Angular (2+).

if (changes.foo.isFirstChange()) {
// $onInit() n'a pas encore été appelé...
}

@gkalpak Je pense que cet argument est faux. binding.isFirstChange() méthode controller.$onInit doit être appelée avant la méthode controller.$onChanges . Ai-je tort?

Une liaison a toujours une valeur au début (peut être undefined ), qui est toujours différente de sa valeur pré-initialisée. Ainsi, $onChanges() sera toujours appelé avec changes.foo avant d'appeler $onInit() .

Il n'est pas logique qu'une liaison puisse avoir une valeur avant d' avoir été initialisée. C'est la définition du dictionnaire du mot initialiser (définir les valeurs initiales). Vous ne pouvez pas changer quelque chose s'il n'avait pas de valeur initiale. Je pense que le nom est tout faux ici et contre nature.

Je ne me souviens pas d'une situation où je n'ai pas été obligé d'écrire quelque chose comme ce code :

$onChanges(changesObj: { [index: string]: angular.IChangesObject; })  {
   if (!this.isInitialized) return;
   ...
}

Appeler "changes" avant "initialisation" n'a aucun sens.

Par pour le cours avec Angular... pourquoi quelqu'un s'attendrait-il à ce que l'initialisation se produise avant les changements ?

Cette page vous a été utile?
0 / 5 - 0 notes