4

Is there a way to configure a UI Router states based on Server Side JSON file. I wan't to avoid hard coding the States inside my module.config(..).

I firstly thought of having controller which has the state map data available which can just call $stateProvider. However, I believe, controllers cannot have providers injected into them.

The other option I have thought was having a Javascript file outside of angular which puts the state configuration data in some global variable to be referenced from Module config function.

But is there a better approach?

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
Iftikhar Ali
  • 369
  • 3
  • 12

1 Answers1

3

I would say, that there are in general two ways how to use SERVER data (JSON) to build up states.

Firstly, we can use $http to load the JSON:

AngularJS - UI-router - How to configure dynamic views

The point here is, that we will in .config() state store reference to $stateProvider and use it in .run() phase, once the JSON could be loaded via $http

// ref to provider, to be configured later
var $stateProviderRef;

// config phase
app.run(['$stateProvider',
  function ($stateProvider) 
  {
    $stateProviderRef = $stateProvider
  }

// run phase
app.run(['$q', '$rootScope', '$state', '$http',
  function ($q, $rootScope, $state, $http) 
  {
    $http.get("myJson.json")
    .success(function(data)
    {
      angular.forEach(data, function (value, key) 
      { 
          var state = {
            "url": value.url,
            ...
          };
          ...
          // here we still configure provider, but in RUN
          $stateProviderRef.state(value.name, state);
      });

But there are some disadvantages. The main is, that direct url navigation (copy - paste) won't be working. The URL will not be rosolved soon enough...

Secondly, my preferred way - create JSON as variable on a server, load it as a script.

So server will somehow generate response via /api/stateData like:

var stateData  = [{ stateName : "State1",
  ...
}];

And we will inject that into page as a resource

<script src="/api/stateData" ...

This could be directly used in .config() phase, and will solve issue with URL being configured soon enough.

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • Perhaps we could add a default "init" abstract state which can load state data and configure states there. – Iftikhar Ali Feb 17 '15 at 15:08
  • No, this won't solve the issue. You simply must have states configured in config or run phase. config is the one, where you do not have access to $http and cannot load JSON. Is it a bit clearer now? – Radim Köhler Feb 17 '15 at 15:17
  • However, some states may need to have "resolve", and "data" attributes, it might be better to have an externalize "JS" function like ConfigureState which configures the states. The JS function may still be generated server side. – Iftikhar Ali Feb 17 '15 at 16:35
  • Radim, yes I understood your solution. Based upon on your original solution, what I did was is a defined a "hard coded" state in the "config function". This state is called "init". In the controller of the init function, I have access to $stateProvider. I make a JSON call, get state data and configure the state provider and than navigate to desired state from init state. The difference though is I didn't make the "init" state as "abstract". It is just an independent state. However, a state may need to have resolve etc. so it better to have an dynamically generated js file. – Iftikhar Ali Feb 17 '15 at 16:45
  • Radim, have a look at deferIntercept function of urlRouterProvider to solve the "bookmark" problem. – Chris T Feb 24 '15 at 03:13
  • @ChrisT, you (and your team) must be magician(s). I really did not see that http://angular-ui.github.io/ui-router/site/#/api/ui.router.router.$urlRouterProvider. Quick view - it simply seems to be smart, while so simple to use. I'll learn it and start to be evangalist.. ;) – Radim Köhler Feb 24 '15 at 07:05