2015-01-30 10 views
14

Ho un servizio di AngularJS, che comunica con il server e restituisce traduzioni di diverse sezioni dell'applicazione:Ui-router AngularJS: come risolvere i dati tipici a livello globale per tutti i percorsi?

angular 
    .module('utils') 
    .service('Translations', ['$q','$http',function($q, $http) { 
     translationsService = { 
      get: function(section) { 
       if (!promise) { 
        var q = $q.defer(); 
        promise = $http 
          .get(
           '/api/translations', 
           { 
            section: section 
           }) 
          .success(function(data,status,headers,config) { 
           q.resolve(result.data); 
          }) 
          .error(function(data,status,headers,config){ 
           q.reject(status); 
          }); 
        return q.promise; 
       } 
      } 
     }; 

     return translationsService; 
    }]); 

Il nome della sezione è passato come parametro section della funzione get.

Sto utilizzando il modulo AngularJS ui-router e seguendo il modello di progettazione descritto here

Così ho i seguenti stati di configurazione:

angular.module('app') 
    .config(['$stateProvider', function($stateProvider) { 
    $stateProvider 
    .state('users', { 
     url: '/users', 
     resolve: { 
      translations: ['Translations', 
       function(Translations) { 
        return Translations.get('users'); 
       } 
      ]    
     }, 
     templateUrl: '/app/users/list.html', 
     controller: 'usersController', 
     controllerAs: 'vm' 
    }) 
    .state('shifts', { 
     url: '/shifts', 
     resolve: { 
      translations: ['Translations', 
       function(Translations) { 
        return Translations.get('shifts'); 
       } 
      ]    
     }, 
     templateUrl: '/app/shifts/list.html', 
     controller: 'shiftsController', 
     controllerAs: 'vm' 
    }) 

Questo funziona bene, ma come si può notare che devo esplicitamente specificare translations nel parametro di risoluzione. Penso che non sia abbastanza buono in quanto questo duplica la logica.

Esiste un modo per risolvere le traduzioni a livello globale ed evitare i duplicati del codice. Intendo una specie di middleware.

Stavo pensando di ascoltare il $stateChangeStart, quindi ottenere traduzioni specifiche per il nuovo stato e collegarle ai controller, ma non ho trovato il modo di farlo.

Qualsiasi consiglio sarà molto apprezzato.

Nota importante: Nel mio caso il codice translations object deve contenere i dati di traduzione, non servizio/fabbrica/altro.

Cordiali saluti.

+0

Non ho tempo per scrivere una risposta, ma dovrei menzionare che le definizioni di stato sono semplici oggetti javascript. Puoi metterli in una lista (inserisci la dichiarazione 'name:' ​​come attributo annidato di ogni stato) e scorrere su ciascuno di essi. In ogni stato su cui si esegue l'iterazione, aggiungere la risoluzione. –

risposta

6

Anche se questa è una domanda molto vecchia, vorrei pubblicare una soluzione che sto usando ora. Spero che possa aiutare qualcuno in futuro. Dopo aver utilizzato alcuni approcci differenti mi si avvicinò con un beautiful angularjs pattern by John Papa

Egli suggerisce di utilizzare un servizio speciale routerHelperProvider e configurare gli stati come un oggetto normale JS. Non ho intenzione di copiare e incollare l'intero provider qui. Vedi il link sopra per i dettagli. Ma mostrerò come ho risolto il mio problema con i mezzi di quel servizio.

qui è la parte di codice di tale provider che prende l'oggetto JS e la trasforma alla configurazione stati:

function configureStates(states, otherwisePath) { 
    states.forEach(function(state) { 
     $stateProvider.state(state.state, state.config); 
}); 

ho trasformato come segue:

function configureStates(states, otherwisePath) { 

    states.forEach(function(state) { 

     var resolveAlways = { 

      translations: ['Translations', function(Translations) { 

       if (state.translationCategory) { 

        return Translations.get(state.translationCategory); 

       } else { 

        return {}; 

       } 

      }], 

     }; 



     state.config.resolve = 

      angular.extend(state.config.resolve || {}, resolveAlways || {}); 



     $stateProvider.state(state.state, state.config); 

    }); 

}); 

E la mia configurazione percorso oggetto ora appare come segue:

 { 
      state: ‘users’, 
      translationsCategory: ‘users’, 
      config: { 
       controller: ‘usersController’ 
       controllerAs: ‘vm’, 
       url: ‘/users’. 
       templateUrl: ‘users.html' 
      } 

Quindi quello che ho fatto:

Ho implementato l'oggetto resolveAlways che accetta la proprietà personalizzata translationsCategory, inietta il servizio Translations e risolve i dati necessari. Ora non c'è bisogno di farlo ogni volta.

25

Lascia che ti mostri il mio approccio. Ci is a working plunker

Diamo uno translation.json come questo:

{ 
    "home" : "trans for home", 
    "parent" : "trans for parent", 
    "parent.child" : "trans for child" 
} 

Ora, cerchiamo di introdurre lo stato super-genitoreroot

$stateProvider 
    .state('root', { 
    abstract: true, 
    template: '<div ui-view=""></div>', 
    resolve: ['Translations' 
     , function(Translations){return Translations.loadAll();}] 
    }); 

Questo stato di root super-non sta avendo alcun url(non effettuare l'eventuale url figlio). Ora, noi silenziosamente iniettare che in ogni stato:

$stateProvider 
    .state('home', { 
     parent: 'root', 
     url: "/home", 
     templateUrl: 'tpl.html', 
    }) 
    .state('parent', { 
     parent: 'root', 
     url: "/parent", 
     templateUrl: 'tpl.html', 
    }) 

Come possiamo vedere, usiamo l'impostazione parent - e non fare effetto/estendere l'originale stato di nome.

stato La radice sta caricando le traduzioni in un solo colpo via nuovo metodo loadAll():

.service('Translations', ['$http' 
    ,function($http) { 
    translationsService = { 
     data : {}, 
     loadAll : function(){ 
     return $http 
      .get("translations.json") 
      .then(function(response){ 
      this.data = response.data;  
      return this.data; 
      }) 
     }, 
     get: function(section) { 
     return data[section]; 
     } 
    }; 

    return translationsService; 
}]) 

Non abbiamo bisogno di $q affatto. Il nostro super stato radice si risolve solo una volta ... tramite il metodo $http e loadAll().Tutti questi sono ora caricate, e possiamo anche inserire tale servizio in $rootScope:

.run(['$rootScope', '$state', '$stateParams', 'Translations', 
    function ($rootScope, $state, $stateParams, Translations) { 
    $rootScope.$state = $state; 
    $rootScope.$stateParams = $stateParams; 
    $rootScope.Translations = Translations; 
}]) 

e possiamo accedervi anyhwere in questo modo:

<h5>Translation</h5> 
<pre>{{Translations.get($state.current.name) | json}}</pre> 

Wow ... che è la soluzione trarre profitto da quasi ogni caratteristica che viene con UI-Router ... direi. Tutto caricato una volta. Tutto ereditato a causa di $ rootScope e visualizzazione dell'eredità ... tutto disponibile in qualsiasi stato figlio ...

Verificare che tutto here.

+0

Grazie per la risposta. Sfortunatamente, questo non funzionerà nel mio caso perché sto lavorando su un'applicazione di grandi dimensioni e ci sono migliaia di traduzioni. Caricarli in una volta è impossibile. Inoltre, ho bisogno di avere un oggetto che contenga le traduzioni alle quali posso accedere per chiave. Non il servizio che chiamo dai template: come {{translations.home}}. – Sray

+2

La mia soluzione è un concetto. Non devi caricare tutto questo. Ti faccio solo vedere come farlo in modo diverso. Basta chiamare $ http nel get .. ma controlla la mia soluzione ... –

Problemi correlati