14

Ich habe einen AngularJS Dienst, der mit dem Server kommuniziert und gibt Übersetzungen von verschiedenen Abschnitten der Anwendung:AngularJS UI-Router: Wie können typische Daten global für alle Routen aufgelöst werden?

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; 
    }]); 

Der Name des Abschnitts als section Parameter der get Funktion übergeben wird.

Ich verwende AngularJS ui-Router-Modul und Muster folgende Design beschrieben here

So habe ich die folgenden Zustände config:

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' 
    }) 

Dies funktioniert gut, aber wie Sie kann ich feststellen, ausdrücklich Geben Sie translations im Parameter resolve an. Ich denke, das ist nicht gut genug, da dies die Logik dupliziert.

Gibt es eine Möglichkeit, Übersetzungen global aufzulösen und die Code-Duplikate zu vermeiden. Ich meine eine Art Middleware.

Ich dachte über das Abhören der $stateChangeStart nach, dann Übersetzungen für den neuen Zustand und binden sie an Controller, aber ich habe den Weg nicht gefunden, es zu tun.

Jeder Rat wird sehr geschätzt werden.

Wichtiger Hinweis: In meinem Fall muss der aufgelöste translations object die Übersetzungsdaten enthalten, nicht service/factory/was auch immer.

Mit freundlichen Grüßen.

+0

Ich habe keine Zeit, eine Antwort zu schreiben, aber ich sollte erwähnen, dass Zustandsdefinitionen einfache Javascript-Objekte sind. Sie können sie in eine Liste einfügen (fügen Sie die 'name:' ​​-Deklaration als verschachteltes Attribut für jeden Status ein) und durchlaufen Sie jede einzelne. Fügen Sie in jedem Zustand, in dem Sie iterieren, die Auflösung hinzu. –

Antwort

6

Obwohl dies eine sehr alte Frage ist, möchte ich die Lösung posten, die ich jetzt verwende. Ich hoffe, es wird jemandem in der Zukunft helfen. Nach der Verwendung verschiedener Ansätze kam ich zu einem beautiful angularjs pattern by John Papa

Er schlägt vor, einen speziellen Service routerHelperProvider zu verwenden und Zustände als ein reguläres JS-Objekt zu konfigurieren. Ich werde hier nicht den gesamten Provider kopieren. Siehe den obigen Link für Details. Aber ich werde zeigen, wie ich mein Problem mit Hilfe dieses Dienstes gelöst habe.

Hier ist der Teil des Codes dieser Anbieter, die das JS Objekt nimmt und wandelt sie in die Konfigurationszustände:

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

ich es wie folgt transformiert:

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); 

    }); 

}); 

Und meine Strecke Konfiguration Objekt sieht jetzt wie folgt aus:

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

Also was ich getan habe:

Ich implementiert das Objekt resolveAlways, das die benutzerdefinierte translationsCategory Eigenschaft übernimmt, injiziert denDienst und löst die erforderlichen Daten. Jetzt muss es nicht jedes Mal gemacht werden.

25

Lassen Sie mich Ihnen meinen Ansatz zeigen. Es is a working plunker

Lassen Sie uns einen translation.json wie dieses:

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

Nun lassen Sie uns vorstellen, die Super Mutter Zustandroot

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

Dieser Superwurzelzustand mit nicht url(nicht Bewirkt eine beliebige Kinder-URL). Jetzt werden wir leise, dass injizieren in jedem Staat:

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

Wie wir sehen können, verwenden wir parent Einstellung - und nicht Wirkung/verlängern den ursprünglichen Zustand Namen.

Der Wurzelzustand wird das Laden der Übersetzungen bei einem Schuss über neue Methode 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; 
}]) 

Wir nicht $q überhaupt brauchen. Unser Super-Root-Zustand löst das nur einmal ... über $http und loadAll() Methode.Alle diese sind nun geladen, und wir können auch diesen Dienst stellen in $rootScope:

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

Und wir können darauf zugreifen, wie dies anyhwere:

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

Wow ... das ist Lösung profitieren fast aus Jedes Feature kommt mit UI-Router ... würde ich sagen. Alle wurden einmal geladen. Alle geerbt wegen $ rootScope und Ansicht Vererbung ... alle in jedem Kind Zustand verfügbar ...

Überprüfen Sie, dass alle here.

+0

Vielen Dank für Ihre Antwort. Leider wird das in meinem Fall nicht funktionieren, da ich an der sehr großen Anwendung arbeite und es tausende von Übersetzungen gibt. Sie auf einmal zu laden ist unmöglich. Außerdem brauche ich ein Objekt, das Übersetzungen enthält, auf die ich per Schlüssel zugreifen kann. Nicht der Service, den ich von Templates aus anrufe: wie {{translations.home}}. – Sray

+2

Meine Lösung ist ein Konzept. Sie müssen nicht alles laden. Ich zeige dir nur, wie es anders geht. Rufen Sie einfach $ http im get .. aber überprüfen Sie meine Lösung ... –

Verwandte Themen