2016-02-25 11 views
33

Sto scrivendo una direttiva Angular 1.5 e sto correndo un problema odioso con il tentativo di manipolare i dati associati prima che esista.

Ecco il mio codice:

app.component('formSelector', { 
    bindings: { 
    forms: '=' 
    }, 
    controller: function(FormSvc) { 

    var ctrl = this 
    this.favorites = [] 

    FormSvc.GetFavorites() 
    .then(function(results) { 
    ctrl.favorites = results 
    for (var i = 0; i < ctrl.favorites.length; i++) { 
     for (var j = 0; j < ctrl.forms.length; j++) { 
      if (ctrl.favorites[i].id == ctrl.newForms[j].id) ctrl.forms[j].favorite = true 
     } 
    } 
    }) 
} 
... 

Come potete vedere, sto facendo una chiamata AJAX per ottenere preferiti e poi controllando contro la mia lista legato delle forme.

Il problema è che la promessa viene soddisfatta anche prima che il binding venga compilato ... in modo che nel momento in cui eseguo il ciclo, ctrl.forms non sia ancora definito!

Senza utilizzare un $ scope. $ Watch (che fa parte del fascino di 1.5 componenti) come posso attendere il completamento del binding?

+0

hai provato $ timeout? potrebbe innescare autonomamente un computo del ciclo di vita. Oppure $ onInit – Martian2049

risposta

26

Si potrebbe utilizzare i nuovi ganci del ciclo di vita, in particolare$onChanges, per rilevare il primo cambio di un legame chiamando il metodo isFirstChange. Maggiori informazioni su questo here.

Ecco un esempio:

<div ng-app="app" ng-controller="MyCtrl as $ctrl"> 
 
    <my-component binding="$ctrl.binding"></my-component> 
 
</div> 
 

 
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.js"></script> 
 
<script> 
 
    angular 
 
    .module('app', []) 
 
    .controller('MyCtrl', function($timeout) { 
 
     $timeout(() => { 
 
     this.binding = 'first value'; 
 
     }, 750); 
 

 
     $timeout(() => { 
 
     this.binding = 'second value'; 
 
     }, 1500); 
 
    }) 
 
    .component('myComponent', { 
 
     bindings: { 
 
     binding: '<' 
 
     }, 
 
     controller: function() { 
 
     // Use es6 destructuring to extract exactly what we need 
 
     this.$onChanges = function({binding}) { 
 
      if (angular.isDefined(binding)) { 
 
      console.log({ 
 
       currentValue: binding.currentValue, 
 
       isFirstChange: binding.isFirstChange() 
 
      }); 
 
      } 
 
     } 
 
     } 
 
    }); 
 
</script>

+4

Fantastico! Grazie mille. Angular è in un posto strano in questo momento; 1.5 è davvero eccezionale e un'opzione davvero eccezionale per le app che hanno avuto inizio in 1.3 o 1.4 ... ma quando cerchi aiuto su 1.5 componenti è difficile riuscire a selezionare tutte le chatter della comunità di Angular 2! – tcmoore

+0

Approccio salvavita. Grazie Signore! –

+0

@HristoEnev Grazie! Puoi dirmi esattamente cosa ti ha aiutato? Sto pensando di perfezionare la risposta un po ', ma non sono sicuro di cosa enfatizzare: il mio metodo personalizzato o l'hook '$ onChanges()'. –

31

ho avuto un problema simile, ho fatto questo per evitare di chiamare il componente fino al valore che sto per inviare è pronto:

<form-selector ng-if="asyncValue" forms="asyncValue" ></form-selector> 
+1

Grazie, funziona perfettamente :) –

+2

È una soluzione elegante. – asiegfried

+0

@asiegfried Hm, sono d'accordo con te e allo stesso tempo sento che questo è un hack. Ci dovrebbe essere una soluzione esplicitamente documentata per questo. –

1

Ho avuto un problema simile e ho trovato questo articolo molto utile. http://blog.thoughtram.io/angularjs/2016/03/29/exploring-angular-1.5-lifecycle-hooks.html

Ho una chiamata ajax che colpisce il server al caricamento della pagina e il mio componente richiede il valore di ritorno ajax per caricare correttamente. L'ho implementato in questo modo:

this.$onChanges = function (newObj) { 
     if (newObj.returnValFromAJAX) 
     this.returnValFromAJAX = newObj.returnValFromAJAX; 
    }; 

Ora il mio componente funziona perfettamente. Per avere un riferimento Sto usando angolare 1.5.6

+0

è la chiamata ajax incorporata all'interno del componente? o stai solo passando il risultato come vincolante? –

8

Il manifesto originale ha detto:

la promessa è adempiuta anche prima che il legame è popolato ... cappello sot per il momento ho eseguito il loop, ctrl .forms non sono ancora definite

da allora AngularJS 1.5.3, dobbiamo lifecycle hooks e per soddisfare la domanda del PO, basta spostare il codice che dipende dalla attacchi di essere soddisfatto all'interno $onInit():

0.123.

$ onInit() - Chiamato in ciascun controller dopo tutti i controlli su un elemento sono stati costruiti e avevano i loro attacchi inizializzato (e prima che i pre & funzioni Collegamento Messaggio per le direttive su questo elemento ). Questo è un buon posto dove mettere il codice di inizializzazione per il tuo controller .

Quindi, nell'esempio:

app.component('formSelector', { 
    bindings: { 
    forms: '=' 
    }, 
    controller: function(FormSvc) { 
    var ctrl = this; 
    this.favorites = []; 

    this.$onInit = function() { 
     // At this point, bindings have been resolved. 
     FormSvc 
      .GetFavorites() 
      .then(function(results) { 
      ctrl.favorites = results; 
      for (var i = 0; i < ctrl.favorites.length; i++) { 
       for (var j = 0; j < ctrl.forms.length; j++) { 
       if (ctrl.favorites[i].id == ctrl.newForms[j].id) { 
        ctrl.forms[j].favorite = true; 
       } 
       } 
      } 
      }); 
    } 
} 

Quindi sì, c'è un $onChanges(changesObj), ma $onInit() affronta in modo specifico la domanda iniziale di quando siamo in grado di ottenere una garanzia che attacchi sono stati risolti.

+0

Avevo bisogno di ottenere un

dal modello del componente, ma all'interno del metodo $ onInit() il modulo non è definito. Se accedo ad esso in un timeout $ (100 ms), allora posso farlo correttamente. Non mi piace questo approccio, ma l'accesso al modulo all'interno di $ onInit() non funziona per me in quanto sembra che non tutte le associazioni siano state risolte. – Francesco

+2

Ciò richiede più voti positivi !!! –

+0

onInit non garantisce i collegamenti risolti. Vedi qui: http://javascript.qahowto.com/How-to-wait-for-binding-in-Angular-15-component-without-scopewatch-javascript-angularjs-components-21fd08b che sembra essere la stessa domanda. OnChanges è la strada da percorrere, il che significa che se hai bisogno che il tuo codice attenda binding validi, dovrai verificarlo in onChanges. –

Problemi correlati