13

I'd like to implement a setup where i can define a "root state" in the main module, and then add child states in other modules. This, because i need the root state to resolve before i can go to the child state.

Apparently, this should be possible according to this FAQ: How to: Configure ui-router from multiple modules

For me it doesn't work: Error Uncaught Error: No such state 'app' from ngBoilerplate.foo

Here is what i have:

app.js

angular.module( 'ngBoilerplate', [
  'templates-app',
  'templates-common',
  'ui.state',
  'ui.route',
  'ui.bootstrap',
  'ngBoilerplate.library'
])
.config( function myAppConfig ( $stateProvider, $urlRouterProvider ) {
    $stateProvider
        .state('app', {
            views:{
                "main":{
                    controller:"AppCtrl"
                }
            },
            resolve:{
                Auth:function(Auth){
                    return new Auth();
                }
            }
        });
    $urlRouterProvider.when('/foo','/foo/tile');
    $urlRouterProvider.otherwise( '/foo' );
})
.factory('Auth', ['$timeout','$q', function ($timeout,$q) {
    return function () {
        var deferred = $q.defer();
        console.log('before resolve');
        $timeout(function () {
            console.log('at resolve');
            deferred.resolve();
        }, 2000);

        return deferred.promise;

    };
}])
.run(function run( $rootScope, $state, $stateParams ) {
    console.log('greetings from run');

    $state.transitionTo('app');
})
.controller( 'AppCtrl', function AppCtrl ( $scope, Auth ) {
    console.log('greetings from AppCtrl');
});

foo.js

angular.module( 'ngBoilerplate.foo', ['ui.state'])

.config(function config( $stateProvider ) {
  $stateProvider
      .state( 'app.foo', {
        url: '/foo/:type',
        views: {
            "main": {
                controller:'FooCtrl',
                templateUrl: function(stateParams) { /* stuff is going on in here*/ }
            }
        }
      });
})
.controller( 'FooCtrl', function FooCtrl( $scope ) {
  console.log('deferred foo');
});

How do i make this work or what other approaches could i take to have something global resolved before every state (without defining a resolve on each state)?

8
  • I am trying to do the exact same thing, and I think I know the issue. I believe it's just a limitation with $stateProvider. The scenario you (and I) have is the module that defines the root state (in this scenario state app in module 'ngBoilerplate) requires another module (in this case ngBoilerplate.foo) that defines a state that is a child of the said root state (i.e. app.foo). All of the first module's (ngBoilerplate) dependencies need to be resolved first (which includes running all their .configs to be run) before it runs its own .config`. Commented Aug 16, 2013 at 0:40
  • So if $stateProvider could only allow for the defining of child states, even if the parent state hasn't yet been defined, and instead throw a fit after the config stage if there is a child state with no parent state defined. Commented Aug 16, 2013 at 0:44
  • Have you tried @Sydney answer below? Commented Aug 16, 2013 at 1:01
  • plunkr to clearly demonstrate the issue I just described. In the console it will output "test config" then throw a Uncaught Error: No such state 'app' from test because the $stateProvider.state('app', {...}); in the app module's config hasn't been run yet. Sydney's answer doesn't help with the issue at hand. Commented Aug 16, 2013 at 1:18
  • In your Plunkr I would reverse the dependency. 'test' module depends on app module since app.test state depends on app state. So var module = angular.module('app', ['ui.state']); and var test = angular.module('test', ['app']);, your Plunkr now complains about the missing controller which is correct. Commented Aug 16, 2013 at 6:07

3 Answers 3

7

I finally chose this approach which does the job for me:

// add all your dependencies here and configure a root state e.g. "app"
angular.module( 'ngBoilerplate', ['ui.router','templates-app',
'templates-common','etc','etc']);

// configure your child states in here, such as app.foo, app.bar etc.
angular.module( 'ngBoilerplate.foo', ['ngBoilerplate']);
angular.module( 'ngBoilerplate.bar', ['ngBoilerplate']);

// tie everything together so you have a static module name
// that can be used with ng-app. this module doesn't do anything more than that.
angular.module( 'app', ['ngBoilerplate.foo','ngBoilerplate.bar']);

and then in your app index.html

<html ng-app="app">
Sign up to request clarification or add additional context in comments.

1 Comment

This is what I was looking for simple and elegant.
1

In the documentation the feature1 module depends on the application module. Try

angular.module( 'ngBoilerplate.foo', ['ngBoilerplate'])

Comments

0

I would of just commented but i do not have the rep. I know this is old but i had the same problem and came across this. One thing i am confused about is in app.js you do not import "ngBoilerplate.foo" but ngBoilerplate.library instead. I had the same problem and my solution was to inject sub modules into the top module instead of their parent.

My structure was module('ngBoilerplate'), module('ngBoilerplate.foo') and module('ngBoilerplate.foo.bar')'. I was injecting ngBoilerplate.foo.bar into ngBoilerplate.foo and the $stateProvider was failing. I needed to inject ngBoilerplate.foo.bar into top level ngBoilerplate.

I thought i would put this here in case anyone else sees this. The error i had was Uncaught TypeError: Cannot read property 'navigable' of undefined from ngBoilerplate.foo

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.