2013-11-27 21 views
17

Sto tentando di seguire this SO answer explaining how to render a recursive JSON structure using a directive. Tuttavia, a differenza della risposta fornita, i miei dati sono non noti quando il DOM viene caricato e Angular viene eseguito per la prima volta.Aggiornamento della direttiva JS angolare in caso di modifiche del servizio

Invece, i miei dati vengono recuperati da un campo di input HTML e memorizzati in un servizio angolare (quando l'utente invia il modulo).

Come è possibile aggiornare una direttiva angolare quando i dati del servizio vengono modificati?


Aggiornamento in risposta a rispondere

@musically_ut fornito una risposta eccellente che ha aiutato, ma ha rivelato un problema correlato, impedendo un'implementazione (aggiornato qui).

La direttiva esegue il rendering HTML contenente Angular {{expressions}} quali dati di accesso memorizzati in $scope. Poiché la soluzione originale era $watch quando il servizio aveva i dati pronti. Come posso garantire che i "nuovi" dati vengano aggiunti a $scopeprima del il direttiva rendering?

Una panoramica dell'architettura e flusso è:

  1. ControllerA -> Ottenere input da utente
  2. ControllerA -> Usa servizio per trasformare i dati
  3. ControllerB ->$watch per le modifiche in servizio
  4. Directive ->$watch per cha NGES in servizio
  5. ControllerB -> Aggiungi dati $scope
  6. Directive -> Mostra trasformato i dati (da servizio) utilizzando direttive

Il problema è tra i punti 5 e 6. La direttiva esegue il rendering {{expressions}} prima che ControllerB abbia aggiunto i dati a $scope. Anche se questo ha funzionato, sembra troppo complesso e "hacky".

In effetti, per regredire, sto usando $watch in ControllerB per ascoltare quando i dati trasformati sono pronti in un servizio. Anche questo sembra un po 'eccessivo (il servizio non effettua chiamate asincrone).

+0

Sono nuovo in angolare, e arrivare a tuo post cercando informazioni circa la sorveglianza cambiamenti servizi nelle direttive. Per quanto ne capisco, pb (e in base a ciò che ho letto di recente), non dovresti "aggiungere dati allo scope" nel tuo ** ControllerB **, è meglio che lo riferisca al ** servizio **, e verrà automaticamente segnalato allo scope ** controllerB **. A proposito, sarai in grado di tenere traccia ** delle modifiche ** al servizio ** nella tua ** direttiva ** (intendo facilmente che tracciare lo scope "esterno" ** controllerB **). Ma forse mi sbaglio. –

risposta

17

È possibile iniettare il servizio durante la definizione della direttiva e quindi impostare uno $watch sui dati.Quindi nel tuo caso:

.directive('tree', function ($compile, myService) { 
    return { 
     // ... 
     link: function (scope, element, attrs) { 
      scope.$watch(function() { 
       return myService.getData(); 
      }, 
      function (newVal) { 
       if (typeof newVal !== 'undefined') { 
        // ... 
       } 
      } 
     }); 
    } 
}); 

Ciò guardare i dati per il cambiamento ed eseguire il codice ogni volta che i dati cambiano.


Tuttavia, se i dati non cambia dopo essere stata impostata una volta, un modo migliore (più efficiente) sarebbe quello di restituire una promessa dal servizio ($http metodi restituisce una promessa direttamente o è possibile creare uno utilizzando il servizio $q) e quindi aggiungere il calcolo come una continuazione ai dati.

.directive('tree', function ($compile, myService) { 
    return { 
     // ... 
     link: function (scope, element, attrs) { 
      myService.getData().then(function (data) { 
       // ... 
      }, function (err) { 
       // Handle error 
      }); 
     } 
    } 
}); 
+1

Grazie. Tuttavia, il problema è che ** la direttiva ** rende ** le espressioni ** che fanno uso dei dati JSON in $ scope. Il codice per la tua ** direttiva ** viene eseguito quando ** aggiorna ** service **, ma cosa succede se viene eseguito prima che i ** servizi ** dati possano essere inseriti in $ scope? Ciò si verifica perché i miei dati vengono recuperati da ControllerA, ma le direttive sono visualizzate in ControllerB. Osservo 'myService.getData()' in ControllerB e imposto i dati in $ scope. Tuttavia, le mie direttive vengono visualizzate prima che ControllerB aggiunga i dati aggiornati a $ scope. – Jack

0

Ho scritto una funzione breve che consente di inserire dati in Object senza sostituirlo. Puoi usarlo nel tuo servizio. In questo modo non è necessario utilizzare l'orologio. Puoi usare il normale ciclo digest di Angular. Per esempio, si veda questo semplice servizio di controllo &:

Demo: JSFidde - http://jsfiddle.net/y09kx7f7/1/ con test assert

Controller:

app.controller('dem',function($scope,me){ 
    $scope.user=me.user; // {name:'user name'} 
}) 

Il controller sarà chnage automaticamente senza orologio ogni volta il nome utente è cambiato!

Servizio

.factory('me',function($timeout){ 
    var obj={} 
    obj.user={name:'hello'} 
    $timeout(function(){ //Example of change the data 
     newUser={name:'israel'} 
     cloneInto(obj.user,newUser) 
    },1000) 
    return obj 
}) 

La funzione cloneInto che ho scritto:

// The function it is like a=b, 
// but keeping the object in his original memory position. 
function cloneInto(a,b){ 
    var i 
    for (i in a){ 
     if(typeof a[i]!='object') //For supporting deep-copy 
      delete a[i] 
    } 
    for (i in b){ 
     if (typeof b[i]=='object'){ 
      if(!a[i]) a[i]={} 
      cloneInto(a[i],b[i]) 
     } 
     else{ 
      a[i]=b[i] 
     } 
    } 
} 
Problemi correlati