2016-02-24 13 views
17

Dato che abbiamo un'applicazione Angular 1.x piuttosto grande, non è possibile aggiornarla completamente a Angular 2 ma adoro la nuova architettura. La versione 1.5 porta straordinari component alla stessa vecchia app. Come tutte le cose interessanti, manca di documentazione ;-)OnChanges a 1,5 componenti angolari non funziona

Quindi, ecco una domanda. Ho queste due righe nella definizione del controller:

this.$onInit = setType; 
this.$onChanges = setType; 

il primo sta funzionando, mentre il secondo no. Sto usando il binding '<'. Quindi, al primo caricamento, lo stato del componente viene impostato in base ai valori passati, mentre le modifiche non vengono riflesse. Ho la speranza che dovrebbe funzionare da [1] e [2].

[1] https://docs.angularjs.org/guide/component

[2] https://angular.io/docs/js/latest/api/core/OnChanges-interface.html

UPD Ok, ho imparato che non dovrebbe funzionare: https://github.com/angular/angular.js/issues/14030

Qualcuno sa buone soluzioni alternative?

UPD2 Funziona come di 1.5.3

+0

Risposta rapida: ho dovuto eseguire un 'angular.copy()' con un oggetto (non primitivo) quando modifico i valori per attivare '$ onChange()' nel componente figlio. – Maxence

+0

Prova questo $ doCheck http://www.kristofdegrave.be/2016/07/component-lifecycle-docheck-angular-15x_22.html –

risposta

7

Per quanto posso dire, sia il metodo $onChanges e $onInit dovrebbe funzionare con la versione 1.5.3 AngularJS.

Ho creato un plnkr that demonstrates both usages.

Dispone di due componenti, un componente esterno e uno interno, in cui un valore è vincolato dal componente esterno a quello interno utilizzando l'operatore vincolante univoco <. Un campo di input aggiorna il valore del componente esterno. Su ogni input da tastiera nel campo di input, viene attivato il metodo $onChanges (aprire la console per vedere).

angular.module("app", []) 
.component("outer", { 
    restrict: "E", 
    template: `<input ng-model=$ctrl.value> <br /> 
      <inner value="$ctrl.value"> 
      </inner>` 
}) 
.component("inner", { 
    restrict: "E", 
    template: `{{$ctrl.value}}`, 
    bindings: { 
     value: "<" 
    }, 
    controller: function(){ 
     function setType() { 
      console.log("called"); 
     } 
     this.$onInit = setType; 
     this.$onChanges = setType; 
    } 
}); 
+0

1.5.3 non è ancora stato rilasciato, vero? Mi riferivo alla 1.5.0, che era l'unica nel ramo 1.5.x per volta in cui scrivevo la domanda iniziale. – leitasat

+0

Buono a sapersi comunque, grazie! – leitasat

+2

1.5.3 è stato rilasciato circa una settimana fa. I ganci sono stati introdotti in quella versione :). – KwintenP

17

A partire dal AngularJs 1.5.3, supponendo ctrl.someModel è tenuto a senso unico in un componente figlio, quanto segue non si innescherà $ onChanges.

function get() { 
    api.getData().then((data) => { 
    ctrl.someModel.data = data 
    } 
} 

Sembra che l'aggiornamento delle proprietà di un oggetto non venga riconosciuto come aggiornamento.

Questo è il modo in cui attualmente lo aggiro. Non credo che sia la soluzione migliore, ma innesca $ onChanges. Creo una copia profonda del mio modello iniziale, aggiungo i dati come una delle sue proprietà e quindi imposto il mio modello iniziale sul valore del nuovo oggetto. Essenzialmente, aggiorno l'intero oggetto, che viene prelevato dal gancio ciclo di vita:

function get() { 
    api.getData().then((data='42') => { 
    const updatedModel = angular.copy(ctrl.someModel) 
    updatedModel.data = data 
    ctrl.someModel = updatedModel 
    } 
} 

E nel componente figlio (assumendo il modello come stato rilegata come 'dati'):

this.$onInit = function(bindings) { 
    if (bindings.data && bindings.data.currentValue) { 
    console.log(bindings.data.currentValue) // '42' 
    } 
} 
+0

Questa è in realtà una buona soluzione dato che si stanno essenzialmente utilizzando dati immutabili, quindi funzionerebbe perfettamente con il flusso e tutte queste cose. – leitasat

+2

È un buon modo per risolvere questo problema. Ma può essere fatto meglio. Ho scritto un post sul blog con un esempio su come usare ImmutableJS per sistemarlo in un modo "più pulito". http://blog.kwintenp.com/the-onchanges-lifecycle-hook/ – KwintenP

+1

Ho avuto un problema simile, ma dal momento che avevo a che fare con una matrice invece che con la copia, ho usato semplicemente 'Array.slice()' che restituisce una copia dell'array e '$ onChanges' effettivamente sparati nel componente. Grazie! – Nobita

9

Dealing con $onChanges è difficile. In realtà, ecco perché nella versione 1.5.8 hanno introdotto il $doCheck, simile a Angular 2 ngDoCheck.

In questo modo, è possibile ascoltare manualmente cambiamenti all'interno dell'oggetto che si sta ascoltando, che non si verifica con il gancio $onChanges (chiamato solo quando viene cambiato il riferimento dell'oggetto). È la stessa cosa, ma viene chiamato per per ogni ciclo di digestione che consente di verificare manualmente le modifiche (ma meglio di quelle dell'orologio).

Per ulteriori dettagli, vedere this blog post

0

In sostanza, $ onChanges angolare grilletto gancio del ciclo di vita quando angolare trovare la variazione di riferimento (non la proprietà in oggetto modificato), così al fine di richiamare i $ onChanges nel bambino , nel genitore, assegna il nuovo oggetto. per esempio,

angular.module("app", []) 
.component("outer", { 
    restrict: "E", 
    controller : function(){ 
     this.value = {}; 
     this.userButtonClick = function(someValue){ 
      this.value = angular.copy(someValue); 
     } 
    }, 
    template: `<input ng-click="$ctrl.userButtonClick({somevalue : "value"})" /> 
    <br /> 
      <inner value="$ctrl.value"> 
      </inner>` 
    })   
.component("inner", { 
     restrict: "E", 
     template: `{{$ctrl.value}}`, 
     bindings: { 
      value: "<" 
     }, 
     controller: function(){ 
      function setType() { 
       console.log("called"); 
      } 
      this.$onInit = setType; 
      this.$onChanges = function(changeObj){ 
       console.log("changed value",changeObj.value.currentValue); 
      } 
     } 
    }); 

Non utilizzare $ doCheck a meno che non si vuole veramente innescare un callback in ogni ciclo digerire, perché viene richiamato in ogni ciclo $ digerire non importa qualche cambiamento vincolante o meno.

Problemi correlati