Angular.js: Orden de los ganchos de los controladores ($ onChanges llamados antes de $ onInit)

Creado en 16 dic. 2016  ·  9Comentarios  ·  Fuente: angular/angular.js

¿Quieres solicitar una función o informar de un error ?
No se si se quiere o si es un error

¿Cuál es el comportamiento actual?
La primera llamada $onChanges se realiza antes de la $onInit one.
Con la configuración predeterminada angular 1.6 (preassign = false), es preferible inicializar los estados del controlador en la función $onInit , dado que los enlaces aún no son accesibles en el constructor.

¿Cuál es el comportamiento esperado?
Creo que sería más lógico llamar primero a $onInit .
Angular no debería hacer nada mientras el controlador no esté completamente inicializado.

¿Cuál es la motivación / caso de uso para cambiar el comportamiento?
Si usamos objetos que se supone que se crearán en la función $onInit en la función $onChanges ; tendremos un error en la primera llamada, porque el controlador aún no se ha inicializado.
Una solución podría ser inicializar esos objetos dentro del constructor, pero inicializaremos el controlador en dos lugares diferentes ...

¿Qué versiones de Angular y qué navegador / sistema operativo se ven afectados por este problema? Pruebe también con las últimas versiones estable y instantánea (https://code.angularjs.org/snapshot/).
versión angular 1.6

works as expected

Comentario más útil

Esto está previsto (principalmente para que coincida con el comportamiento de Angular 2+). En caso de que se lo haya perdido, puede verificar si es la primera llamada (previa a $ onInit) de $onChanges , verificando el valor de retorno del método isFirstChange() de cualquiera de los SimpleChange objetos:

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

#

Admito que mi primera reacción fue la misma. Desde la perspectiva del modelo mental, es más fácil pensar que $onInit() es lo primero que sucede en el controlador; luego $onChanges() , $onChanges() , $onChanges() y finalmente $onDestroy() .

Pero si lo piensa, los enlaces deben evaluarse y asignarse a la instancia del controlador antes de llamar a $onInit . Y al hacerlo, se detecta un cambio en los valores (previamente indefinidos), que a su vez debe informarse a través de $onChanges .

Cerrando, ya que esto está funcionando como se esperaba (o al menos como se esperaba: guiño :).

Todos 9 comentarios

Esto está previsto (principalmente para que coincida con el comportamiento de Angular 2+). En caso de que se lo haya perdido, puede verificar si es la primera llamada (previa a $ onInit) de $onChanges , verificando el valor de retorno del método isFirstChange() de cualquiera de los SimpleChange objetos:

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

#

Admito que mi primera reacción fue la misma. Desde la perspectiva del modelo mental, es más fácil pensar que $onInit() es lo primero que sucede en el controlador; luego $onChanges() , $onChanges() , $onChanges() y finalmente $onDestroy() .

Pero si lo piensa, los enlaces deben evaluarse y asignarse a la instancia del controlador antes de llamar a $onInit . Y al hacerlo, se detecta un cambio en los valores (previamente indefinidos), que a su vez debe informarse a través de $onChanges .

Cerrando, ya que esto está funcionando como se esperaba (o al menos como se esperaba: guiño :).

Muchas gracias por tu respuesta, ahora está más claro :)

Entiendo que esto es intencional, ¿qué tal si registramos la definición de la función $ onChanges () dentro de $ onInit ()?

@bharatpatil , debería funcionar en AngularJS (1.x.) pero no en Angular (2+).

if (changes.foo.isFirstChange ()) {
// $onInit() aún no se ha llamado ...
}

@gkalpak Creo que este argumento es incorrecto. binding.isFirstChange() método controller.$onInit método controller.$onChanges . ¿Me equivoco?

Un enlace siempre tiene un valor al principio (podría ser undefined ), que siempre es diferente de su valor preinicializado. Por lo tanto, $onChanges() siempre se llamará con changes.foo antes de llamar a $onInit() .

No tiene sentido lógico que un enlace pueda tener un valor antes de que se haya inicializado. Esa es la definición del diccionario de la palabra inicializar (establecer valores iniciales). No puede cambiar algo si no tiene un valor inicial. Creo que la denominación aquí es incorrecta y antinatural.

No recuerdo una situación en la que no me vi obligado a escribir algo como este código:

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

Llamar a "cambios" antes de "inicialización" no tiene ningún sentido.

Par para el curso con Angular ... ¿por qué alguien esperaría que se inicie antes de los cambios?

¿Fue útil esta página
0 / 5 - 0 calificaciones