|
| 1 | +angular.module('uiRouterSample.contacts', [ |
| 2 | + 'ui.router' |
| 3 | +]) |
| 4 | + |
| 5 | +.config( |
| 6 | + [ '$stateProvider', '$urlRouterProvider', |
| 7 | + function ($stateProvider, $urlRouterProvider) { |
| 8 | + $stateProvider |
| 9 | + ////////////// |
| 10 | + // Contacts // |
| 11 | + ////////////// |
| 12 | + .state('contacts', { |
| 13 | + |
| 14 | + // With abstract set to true, that means this state can not be explicitly activated. |
| 15 | + // It can only be implicitly activated by activating one of its children. |
| 16 | + abstract: true, |
| 17 | + |
| 18 | + // This abstract state will prepend '/contacts' onto the urls of all its children. |
| 19 | + url: '/contacts', |
| 20 | + |
| 21 | + // Example of loading a template from a file. This is also a top level state, |
| 22 | + // so this template file will be loaded and then inserted into the ui-view |
| 23 | + // within index.html. |
| 24 | + templateUrl: 'app/contacts/contacts.html', |
| 25 | + |
| 26 | + // Use `resolve` to resolve any asynchronous controller dependencies |
| 27 | + // *before* the controller is instantiated. In this case, since contacts |
| 28 | + // returns a promise, the controller will wait until contacts.all() is |
| 29 | + // resolved before instantiation. Non-promise return values are considered |
| 30 | + // to be resolved immediately. |
| 31 | + resolve: { |
| 32 | + contacts: ['contacts', |
| 33 | + function( contacts){ |
| 34 | + return contacts.all(); |
| 35 | + }] |
| 36 | + }, |
| 37 | + |
| 38 | + // You can pair a controller to your template. There *must* be a template to pair with. |
| 39 | + controller: ['$scope', '$state', 'contacts', 'utils', |
| 40 | + function ( $scope, $state, contacts, utils) { |
| 41 | + |
| 42 | + // Add a 'contacts' field in this abstract parent's scope, so that all |
| 43 | + // child state views can access it in their scopes. Please note: scope |
| 44 | + // inheritance is not due to nesting of states, but rather choosing to |
| 45 | + // nest the templates of those states. It's normal scope inheritance. |
| 46 | + $scope.contacts = contacts; |
| 47 | + |
| 48 | + $scope.goToRandom = function () { |
| 49 | + var randId = utils.newRandomKey($scope.contacts, "id", $state.params.contactId); |
| 50 | + |
| 51 | + // $state.go() can be used as a high level convenience method |
| 52 | + // for activating a state programmatically. |
| 53 | + $state.go('contacts.detail', { contactId: randId }); |
| 54 | + }; |
| 55 | + }] |
| 56 | + }) |
| 57 | + |
| 58 | + ///////////////////// |
| 59 | + // Contacts > List // |
| 60 | + ///////////////////// |
| 61 | + |
| 62 | + // Using a '.' within a state name declares a child within a parent. |
| 63 | + // So you have a new state 'list' within the parent 'contacts' state. |
| 64 | + .state('contacts.list', { |
| 65 | + |
| 66 | + // Using an empty url means that this child state will become active |
| 67 | + // when its parent's url is navigated to. Urls of child states are |
| 68 | + // automatically appended to the urls of their parent. So this state's |
| 69 | + // url is '/contacts' (because '/contacts' + ''). |
| 70 | + url: '', |
| 71 | + |
| 72 | + // IMPORTANT: Now we have a state that is not a top level state. Its |
| 73 | + // template will be inserted into the ui-view within this state's |
| 74 | + // parent's template; so the ui-view within contacts.html. This is the |
| 75 | + // most important thing to remember about templates. |
| 76 | + templateUrl: 'app/contacts/contacts.list.html' |
| 77 | + }) |
| 78 | + |
| 79 | + /////////////////////// |
| 80 | + // Contacts > Detail // |
| 81 | + /////////////////////// |
| 82 | + |
| 83 | + // You can have unlimited children within a state. Here is a second child |
| 84 | + // state within the 'contacts' parent state. |
| 85 | + .state('contacts.detail', { |
| 86 | + |
| 87 | + // Urls can have parameters. They can be specified like :param or {param}. |
| 88 | + // If {} is used, then you can also specify a regex pattern that the param |
| 89 | + // must match. The regex is written after a colon (:). Note: Don't use capture |
| 90 | + // groups in your regex patterns, because the whole regex is wrapped again |
| 91 | + // behind the scenes. Our pattern below will only match numbers with a length |
| 92 | + // between 1 and 4. |
| 93 | + |
| 94 | + // Since this state is also a child of 'contacts' its url is appended as well. |
| 95 | + // So its url will end up being '/contacts/{contactId:[0-9]{1,4}}'. When the |
| 96 | + // url becomes something like '/contacts/42' then this state becomes active |
| 97 | + // and the $stateParams object becomes { contactId: 42 }. |
| 98 | + url: '/{contactId:[0-9]{1,4}}', |
| 99 | + |
| 100 | + // If there is more than a single ui-view in the parent template, or you would |
| 101 | + // like to target a ui-view from even higher up the state tree, you can use the |
| 102 | + // views object to configure multiple views. Each view can get its own template, |
| 103 | + // controller, and resolve data. |
| 104 | + |
| 105 | + // View names can be relative or absolute. Relative view names do not use an '@' |
| 106 | + // symbol. They always refer to views within this state's parent template. |
| 107 | + // Absolute view names use a '@' symbol to distinguish the view and the state. |
| 108 | + // So 'foo@bar' means the ui-view named 'foo' within the 'bar' state's template. |
| 109 | + views: { |
| 110 | + |
| 111 | + // So this one is targeting the unnamed view within the parent state's template. |
| 112 | + '': { |
| 113 | + templateUrl: 'app/contacts/contacts.detail.html', |
| 114 | + controller: ['$scope', '$stateParams', 'utils', |
| 115 | + function ( $scope, $stateParams, utils) { |
| 116 | + $scope.contact = utils.findById($scope.contacts, $stateParams.contactId); |
| 117 | + }] |
| 118 | + }, |
| 119 | + |
| 120 | + // This one is targeting the ui-view="hint" within the unnamed root, aka index.html. |
| 121 | + // This shows off how you could populate *any* view within *any* ancestor state. |
| 122 | + 'hint@': { |
| 123 | + template: 'This is contacts.detail populating the "hint" ui-view' |
| 124 | + }, |
| 125 | + |
| 126 | + // This one is targeting the ui-view="menuTip" within the parent state's template. |
| 127 | + 'menuTip': { |
| 128 | + // templateProvider is the final method for supplying a template. |
| 129 | + // There is: template, templateUrl, and templateProvider. |
| 130 | + templateProvider: ['$stateParams', |
| 131 | + function ( $stateParams) { |
| 132 | + // This is just to demonstrate that $stateParams injection works for templateProvider. |
| 133 | + // $stateParams are the parameters for the new state we're transitioning to, even |
| 134 | + // though the global '$stateParams' has not been updated yet. |
| 135 | + return '<hr><small class="muted">Contact ID: ' + $stateParams.contactId + '</small>'; |
| 136 | + }] |
| 137 | + } |
| 138 | + } |
| 139 | + }) |
| 140 | + |
| 141 | + ////////////////////////////// |
| 142 | + // Contacts > Detail > Item // |
| 143 | + ////////////////////////////// |
| 144 | + |
| 145 | + .state('contacts.detail.item', { |
| 146 | + |
| 147 | + // So following what we've learned, this state's full url will end up being |
| 148 | + // '/contacts/{contactId}/item/:itemId'. We are using both types of parameters |
| 149 | + // in the same url, but they behave identically. |
| 150 | + url: '/item/:itemId', |
| 151 | + views: { |
| 152 | + |
| 153 | + // This is targeting the unnamed ui-view within the parent state 'contact.detail' |
| 154 | + // We wouldn't have to do it this way if we didn't also want to set the 'hint' view below. |
| 155 | + // We could instead just set templateUrl and controller outside of the view obj. |
| 156 | + '': { |
| 157 | + templateUrl: 'app/contacts/contacts.detail.item.html', |
| 158 | + controller: ['$scope', '$stateParams', '$state', 'utils', |
| 159 | + function ( $scope, $stateParams, $state, utils) { |
| 160 | + $scope.item = utils.findById($scope.contact.items, $stateParams.itemId); |
| 161 | + |
| 162 | + $scope.edit = function () { |
| 163 | + // Here we show off go's ability to navigate to a relative state. Using '^' to go upwards |
| 164 | + // and '.' to go down, you can navigate to any relative state (ancestor or descendant). |
| 165 | + // Here we are going down to the child state 'edit' (full name of 'contacts.detail.item.edit') |
| 166 | + $state.go('.edit', $stateParams); |
| 167 | + }; |
| 168 | + }] |
| 169 | + }, |
| 170 | + |
| 171 | + // Here we see we are overriding the template that was set by 'contacts.detail' |
| 172 | + 'hint@': { |
| 173 | + template: ' This is contacts.detail.item overriding the "hint" ui-view' |
| 174 | + } |
| 175 | + } |
| 176 | + }) |
| 177 | + |
| 178 | + ///////////////////////////////////// |
| 179 | + // Contacts > Detail > Item > Edit // |
| 180 | + ///////////////////////////////////// |
| 181 | + |
| 182 | + // Notice that this state has no 'url'. States do not require a url. You can use them |
| 183 | + // simply to organize your application into "places" where each "place" can configure |
| 184 | + // only what it needs. The only way to get to this state is via $state.go (or transitionTo) |
| 185 | + .state('contacts.detail.item.edit', { |
| 186 | + views: { |
| 187 | + |
| 188 | + // This is targeting the unnamed view within the 'contacts.detail' state |
| 189 | + // essentially swapping out the template that 'contacts.detail.item' had |
| 190 | + // inserted with this state's template. |
| 191 | + '@contacts.detail': { |
| 192 | + templateUrl: 'app/contacts/contacts.detail.item.edit.html', |
| 193 | + controller: ['$scope', '$stateParams', '$state', 'utils', |
| 194 | + function ( $scope, $stateParams, $state, utils) { |
| 195 | + $scope.item = utils.findById($scope.contact.items, $stateParams.itemId); |
| 196 | + $scope.done = function () { |
| 197 | + // Go back up. '^' means up one. '^.^' would be up twice, to the grandparent. |
| 198 | + $state.go('^', $stateParams); |
| 199 | + }; |
| 200 | + }] |
| 201 | + } |
| 202 | + } |
| 203 | + }); |
| 204 | + } |
| 205 | + ] |
| 206 | +); |
0 commit comments