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 it's 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,8}}'. 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="menu" 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 'contact.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 'contact.detail' state
189
+ // essentially swapping out the template that 'contact.detail.item' had
190
+ // had 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