Angular.js: Controller-Hooks-Reihenfolge ($onChanges, aufgerufen vor $onInit)

Erstellt am 16. Dez. 2016  ·  9Kommentare  ·  Quelle: angular/angular.js

Möchten Sie eine Funktion anfordern oder einen Fehler melden?
Ich weiß nicht ob es gewollt ist oder ob es ein Bug ist

Wie ist das aktuelle Verhalten?
Der erste $onChanges Aufruf wird vor dem $onInit Aufruf ausgeführt.
Bei der Standardkonfiguration von Angular 1.6 (preassign = false) ist es vorzuziehen, Controller-Zustände in der $onInit Funktion zu initialisieren, da die Bindungen im Konstruktor noch nicht zugänglich sind.

Was ist das erwartete Verhalten?
Ich denke, es wäre logischer, zuerst $onInit anzurufen.
Angular sollte nichts tun, solange der Controller nicht vollständig initialisiert ist.

Was ist die Motivation / der Anwendungsfall für die Verhaltensänderung?
Wenn wir Objekte verwenden, die in der Funktion $onInit erstellt werden sollen, in der Funktion $onChanges ; Wir werden beim ersten Aufruf einen Fehler haben, da der Controller noch nicht initialisiert wurde.
Eine Lösung könnte darin bestehen, diese Objekte innerhalb des Konstruktors zu initialisieren, aber wir werden den Controller an zwei verschiedenen Stellen initialisieren ...

Welche Angular-Versionen und welche Browser/Betriebssysteme sind von diesem Problem betroffen? Bitte testen Sie auch mit den neuesten Stable- und Snapshot-Versionen (https://code.angularjs.org/snapshot/).
eckige 1.6-Version

works as expected

Hilfreichster Kommentar

Dies ist beabsichtigt (hauptsächlich um dem Verhalten von Angular 2+ zu entsprechen). Falls Sie es verpasst haben, können Sie überprüfen, ob es der erste Aufruf (vor $onInit) von $onChanges , indem Sie den Rückgabewert der Methode isFirstChange() einer der SimpleChange Objekte:

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

#

Ich gebe zu, dass meine erste Reaktion die gleiche war. Aus der Perspektive eines mentalen Modells ist es einfacher zu denken, dass $onInit() das erste ist, was im Controller passiert; dann $onChanges() , $onChanges() , $onChanges() und schließlich $onDestroy() .

Aber wenn Sie darüber nachdenken, müssen die Bindungen ausgewertet und der Controller-Instanz zugewiesen werden, bevor $onInit . Dabei wird eine Änderung der (bisher undefinierten) Werte erkannt, die wiederum über $onChanges gemeldet werden muss.

Schließen, da dies wie erwartet (oder zumindest wie beabsichtigt :wink:) funktioniert.

Alle 9 Kommentare

Dies ist beabsichtigt (hauptsächlich um dem Verhalten von Angular 2+ zu entsprechen). Falls Sie es verpasst haben, können Sie überprüfen, ob es der erste Aufruf (vor $onInit) von $onChanges , indem Sie den Rückgabewert der Methode isFirstChange() einer der SimpleChange Objekte:

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

#

Ich gebe zu, dass meine erste Reaktion die gleiche war. Aus der Perspektive eines mentalen Modells ist es einfacher zu denken, dass $onInit() das erste ist, was im Controller passiert; dann $onChanges() , $onChanges() , $onChanges() und schließlich $onDestroy() .

Aber wenn Sie darüber nachdenken, müssen die Bindungen ausgewertet und der Controller-Instanz zugewiesen werden, bevor $onInit . Dabei wird eine Änderung der (bisher undefinierten) Werte erkannt, die wiederum über $onChanges gemeldet werden muss.

Schließen, da dies wie erwartet (oder zumindest wie beabsichtigt :wink:) funktioniert.

Vielen Dank für deine Antwort, jetzt ist es klarer :)

Ich verstehe, dass dies beabsichtigt ist, wie wäre es, wenn wir die Definition der Funktion $onChanges() in $onInit() registrieren.

@bharatpatil , es sollte in AngularJS (1.x.)

if (changes.foo.isFirstChange()) {
// $onInit() wurde noch nicht aufgerufen...
}

@gkalpak Ich denke, dieses Argument ist falsch. binding.isFirstChange() Methode garantiert nur, dass die zugehörige Bindung zum ersten Mal aufgerufen wurde. Denken Sie an eine Bindung, die initialisiert wird, nachdem ein Serviceaufruf zu lange dauert. In dieser Situation sollte die Methode controller.$onInit Methode controller.$onChanges aufgerufen werden. Liege ich falsch?

Eine Bindung hat am Anfang immer einen Wert (kann undefined ), der sich immer von ihrem vorinitialisierten Wert unterscheidet. Daher wird $onChanges() immer mit changes.foo aufgerufen, bevor $onInit() aufgerufen wird.

Es macht keinen logischen Sinn, dass eine Bindung einen Wert haben kann, bevor sie initialisiert wurde. Das ist die Wörterbuchdefinition des Wortes initialisieren (Anfangswerte setzen). Sie können etwas nicht ändern, wenn es keinen Anfangswert hat. Ich denke, die Namensgebung ist hier ganz falsch und unnatürlich.

Ich kann mich an keine Situation erinnern, in der ich nicht gezwungen war, so etwas wie diesen Code zu schreiben:

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

"Änderungen" vor "Initialisierung" aufzurufen macht keinen Sinn.

Standardmäßig mit Angular ... warum sollte jemand erwarten, dass init vor Änderungen stattfindet?

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen