0
votes

Any explanation why the sample code (ui-router/sample/index.html) for angular-ui-router (https://github.com/angular-ui/ui-router) looks like this. Specifically:

  1. Why the nested definitions of objects like controllers?
  2. Why the specification of dependencies like this:

    angular.module('sample', ['ui.compat']) .config( [ '$stateProvider', '$routeProvider', '$urlRouterProvider', function ($stateProvider, $routeProvider, $urlRouterProvider) {

thanks

<!doctype html>
<html lang="en" ng-app="sample"><head>
  <meta charset="utf-8">
  <link rel="stylesheet" type="text/css" href="bootstrap.min.css">
  <style type="text/css">
    .fade-enter-setup, .fade-leave-setup {
      transition: opacity 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0s;
    }
    .fade-enter-setup,
    .fade-leave-setup.fade-leave-start {
      opacity: 0;
    }
    .fade-leave-setup,
    .fade-enter-setup.fade-enter-start {
      opacity: 1;
    }
  </style>
  <script src="../lib/angular-1.1.4.js"></script>
  <script src="../build/angular-ui-router.js"></script>

  <!-- could easily use a custom property of the state here instead of 'name' -->
  <title ng-bind="$state.current.name + ' - ui-router'">ui-router</title>
</head><body>
<div class="navbar navbar-fixed-top">
  <div class="navbar-inner"><div class="container">
    <a class="brand" href="#">ui-router</a>
    <ul class="nav">
      <li ng-class="{ active: $state.includes('contacts') }"><a href="#/contacts">Contacts</a></li>
      <li ng-class="{ active: $state.includes('about') }"><a href="#/about">About</a></li>
    </ul>
    <p class="navbar-text pull-right" ui-view="hint"></p>
  </div></div>
</div>
<div class="container" style="margin-top:60px" ui-view ng-animate="{enter:'fade-enter'}"></div>
<hr>
<pre>
  $state = {{$state.current.name}}
  $stateParams = {{$stateParams}}
</pre>
</body><script>

function findById(a, id) {
  for (var i=0; i<a.length; i++) {
    if (a[i].id == id) return a[i];
  }
}

angular.module('sample', ['ui.compat'])
  .config(
    [        '$stateProvider', '$routeProvider', '$urlRouterProvider',
    function ($stateProvider,   $routeProvider,   $urlRouterProvider) {
      $urlRouterProvider
        .when('/c?id', '/contacts/:id')
        .otherwise('/');

      $routeProvider
        .when('/user/:id', {
          redirectTo: '/contacts/:id',
        })
        .when('/', {
          template: '<p class="lead">Welcome to the ngStates sample</p><p>Use the menu above to navigate</p>' +
            '<p>Look at <a href="#/c?id=1">Alice</a> or <a href="#/user/42">Bob</a> to see a URL with a redirect in action.</p>',
        });

      $stateProvider
        .state('contacts', {
          url: '/contacts',
          abstract: true,
          templateUrl: 'contacts.html',
          controller:
            [        '$scope', '$state',
            function ($scope,   $state) {
              $scope.contacts = [{
                id: 1,
                name: "Alice",
                items: [{
                  id: 'a',
                  type: 'phone number',
                  value: '555-1234-1234',
                },{
                  id: 'b',
                  type: 'email',
                  value: '[email protected]',
                }],
              }, {
                id: 42,
                name: "Bob",
                items: [{
                  id: 'a',
                  type: 'blog',
                  value: 'http://bob.blogger.com',
                },{
                  id: 'b',
                  type: 'fax',
                  value: '555-999-9999',
                }],
              }, {
                id: 123,
                name: "Eve",
                items: [{
                  id: 'a',
                  type: 'full name',
                  value: 'Eve Adamsdottir',
                }],
              }];

              $scope.goToRandom = function () {
                var contacts = $scope.contacts, id;
                do {
                  id = contacts[Math.floor(contacts.length * Math.random())].id;
                } while (id == $state.params.contactId);
                $state.transitionTo('contacts.detail', { contactId: id });
              };
            }],
        })
        .state('contacts.list', {
          // parent: 'contacts',
          url: '',
          templateUrl: 'contacts.list.html',
        })
        .state('contacts.detail', {
          // parent: 'contacts',
          url: '/{contactId}',
          resolve: {
            something:
              [        '$timeout', '$stateParams',
              function ($timeout,   $stateParams) {
                return $timeout(function () { return "Asynchronously resolved data (" + $stateParams.contactId + ")" }, 10);
              }],
          },
          views: {
            '': {
              templateUrl: 'contacts.detail.html',
              controller:
                [        '$scope', '$stateParams', 'something',
                function ($scope,   $stateParams,   something) {
                  $scope.something = something;
                  $scope.contact = findById($scope.contacts, $stateParams.contactId);
                }],
            },
            'hint@': {
              template: 'This is contacts.detail populating the view "hint@"',
            },
            'menu': {
              templateProvider:
                [ '$stateParams',
                function ($stateParams){
                  // This is just to demonstrate that $stateParams injection works for templateProvider
                  // $stateParams are the parameters for the new state we're transitioning to, even
                  // though the global '$stateParams' has not been updated yet.
                  return '<hr><small class="muted">Contact ID: ' + $stateParams.contactId + '</small>';
                }],
            },
          },
        })
        .state('contacts.detail.item', {
          // parent: 'contacts.detail',
          url: '/item/:itemId',
          views: {
            '': {
              templateUrl: 'contacts.detail.item.html',
              controller:
                [        '$scope', '$stateParams', '$state',
                function ($scope,   $stateParams,   $state) {
                  $scope.item = findById($scope.contact.items, $stateParams.itemId);
                  $scope.edit = function () {
                    $state.transitionTo('contacts.detail.item.edit', $stateParams);
                  };
                }],
            },
            'hint@': {
              template: 'Overriding the view "hint@"',
            },
          },
        })
        .state('contacts.detail.item.edit', {
          views: {
            '@contacts.detail': {
              templateUrl: 'contacts.detail.item.edit.html',
              controller:
                [        '$scope', '$stateParams', '$state',
                function ($scope,   $stateParams,   $state) {
                  $scope.item = findById($scope.contact.items, $stateParams.itemId);
                  $scope.done = function () {
                    $state.transitionTo('contacts.detail.item', $stateParams);
                  };
                }],
            },
          },
        })
        .state('about', {
          url: '/about',
          templateProvider:
            [        '$timeout',
            function ($timeout) {
              return $timeout(function () { return "Hello world" }, 100);
            }],
        })
        .state('empty', {
          url: '/empty',
          templateUrl: 'empty.html',
          controller:
            [        '$scope', '$state',
            function ($scope,   $state) {
              // Using an object to access it via ng-model from child scope
              $scope.data = {
                initialViewTitle: "I am an initial view"
              }
              $scope.changeInitialViewTitle = function($event) {
                $state.transitionTo('empty.emptycontent');
              };
              $scope.showInitialView = function($event) {
                $state.transitionTo('empty');
              };
          }]
        })
        .state('empty.emptycontent', {
          url: '/content',
          views: {
            'emptycontent': {
              templateUrl: 'empty.content.html'
            }
          }
        });
    }])
    .run(
      [        '$rootScope', '$state', '$stateParams',
      function ($rootScope,   $state,   $stateParams) {
        $rootScope.$state = $state;
        $rootScope.$stateParams = $stateParams;
      }]);
</script></html>
2

2 Answers

0
votes

ui-router doesn't fully support this. You may check this library for nested routing: http://angular-route-segment.com

It provides the functionality for creating tree-like routing hierarchy which can be changed without losing the state.

$routeSegmentProvider.

when('/section1',          's1.home').
when('/section1/prefs',    's1.prefs').
when('/section1/:id',      's1.itemInfo.overview').
when('/section1/:id/edit', 's1.itemInfo.edit').
when('/section2',          's2').

segment('s1', {
    templateUrl: 'templates/section1.html',
    controller: MainCtrl}).

within().

    segment('home', {
        templateUrl: 'templates/section1/home.html'}).

    segment('itemInfo', {
        templateUrl: 'templates/section1/item.html',
        controller: Section1ItemCtrl,
        dependencies: ['id']}).

    within().

        segment('overview', {
            templateUrl: 'templates/section1/item/overview.html'}).

        segment('edit', {
             templateUrl: 'templates/section1/item/edit.html'}).

        up().

    segment('prefs', {
        templateUrl: 'templates/section1/prefs.html'}).

    up().

segment('s2', {
    templateUrl: 'templates/section2.html',
    controller: MainCtrl});
0
votes

The nesting is only one way of doing the example. you could write

                'navTitle@': {
                templateUrl : 'pages/mypage.html',
                controller: 'myController',
            },

and then just define myController anywhere else you want in your app.

function myController ($scope) {

};

as far as dependencies question...thats one way of injecting in dependancies in angular so you can reuse the code in other places.

    .factory('appLoading', function($rootScope, $state) {
    return {
        loading : function() {
            $rootScope.status = 'loading';
            if(!$rootScope.$$phase) $rootScope.$apply();
        },
        ready : function(delay) {
            function ready() {
        $rootScope.status = 'ready';
        $rootScope.title = $state.current.data.title;
        if(!$rootScope.$$phase) $rootScope.$apply();

    }

}
};
})

then if i wanted to call this loader in a module it would go inside []

like inside the onExit of a state inside ui-router...

    onExit: ['appLoading',
function ( appLoading) {
    appLoading.loading();
}],