Translation: In-depth Angularui Router
Original address: http://www.ng-newsletter.com/posts/angular-ui-router.html
Ui-router:https://angular-ui.github.io/ui-router/site/#/api/ui.router
Ui-router is a particularly useful part of the Angularui library, a routing framework that organizes our interfaces by providing a state machine mechanism rather than a simple URL.
This library provides numerous additional controls for views, and we can create nested views, use multiple views on a single page, multiple views to control a single view, and more. For finer control and more complex applications, Ui-router is a great tool.
Ui-router manages routing from the State, which treats the application as a combination of multiple states, routed through state switching.
- A state can correspond to a page address and reach the specific state of the application through a specific address.
- Manage UI and behavior for a particular state with State controller, template, and views
- Use nested views to resolve recurring content in the page.
Installation
Install Ui-router, either directly to download the release version or through Bower.
$ Bower Install Angular-ui-router--save
Then, you need to enter this library in the page, and of course load the angular library first.
<script type= "Text/javascript" src= "Angular-ui-router.js" ></script>
Inject ui.router into the angular.
Angular.module (' myApp ', [' Ui.router '])
Unlike angular built-in ngroute, ui-router can nest views, which are based on state, not URL.
Also unlike ngroute using the Ng-view directive, in Ui-router we use the Ui-view directive.
When considering the relationship between routing and state in Ui-router, we mainly focus on what state of the application corresponds to what route the application is in.
<div ng-controller= "Democontroller" > <div ui-view></div></div>
Like Ngroute, for a given state, the contents of the template are populated with <div ui-view></div> elements, and each template can also contain its own ui-view, which is why we can support nested paths.
When defining the path, we use the. config method, as usual, but use the $stateProvider to replace the $routeProvider.
. config (function ($stateProvider, $urlRouterProvider) { $stateProvider . State (' start ', { URL: '/start '), templateurl: ' partials/start.html ' )});
In this way, we define the state named start, which defines state configuration information, or stateconfig, similar to a routing configuration object, through which we configure state information.
Template, Templateurl, Templateprovider
You can use one of the following three ways to define the template used by the view:
- Template, string-mode content, or a function that returns HTML
- Templateurl, the path to a template, or a function that returns a template path
- Templateprovider, functions that return HTML content
For example
$stateProvider. State (' home ', { Template: '
ControllerSimilar to Ngroute, we can either associate a predefined controller with the name of the controller or directly create a controller function to handle it.
If there is no corresponding template definition, the Controller object will not be created.
ResolveUsing the Resolve feature, we can prepare a set of dependent objects to be injected into the controller. In Ngroute, resolve can be resolved before the actual rendering of the route promise
The Resolve option provides an object where the key is the dependent name that prepares the controller to be injected, and the value is the factory that created the object.
If it is a string, try to use this string to match the currently registered service name, if it is a function, execute the function, the value returned is dependent. If the function returns a promise, it is resolved before the controller is instantiated, and the returned value is injected into the controller.
$stateProvider. State (' home ', { resolve: { //This'll return immediately as the //result is a promise
person:function () { return { name: "Ari", email: "[email protected]" } }, //This function Returns a promise, therefore //It'll be resolved before the controller //is instantiated currentdetails : function ($http) { return $http ({ method: ' JSONP ', URL: '/current_details ' }); }, // We can use the resulting promise in another //Resolution facebookid:function ($http, currentdetails) { $h TTP ({ method: ' GET ', URL: ' http://facebook.com/api/current_user ', params: { Email: Currentdetails.data.emails[0]}} ) } , controller:function ($scope, person, Currentdetails, Facebookid) { $scope. person = person; }})
UrlThe URL is used to set a specific state for the app. That is, we can reach a certain state through a URL, so the URL here is not a simple URL, but a sign of a reachable state.
This feature is similar to the URL in Ngroute, but can be seen as a major upgrade, as we'll see later.
A simple route looks like the following.
$stateProvider . State (' Inbox ', { URL: '/inbox ', Template: '
When we navigate to/index, the app will transition to the Inbox state, using the content template provided here to populate the Ui-view content.
The URL can contain a variety of content, incredibly powerful, and can be set as simple parameters in Ngroute.
$stateProvider . State (' Inbox ', { URL: '/inbox/:inboxid ', Template: '
Here, we created the: Inboxid parameter to capture the second part of the URL, for example, if the app accesses/inbox/1, $stateParameter. Inboxid becomes 1, in fact, the value of the $stateParams will be {inboxid: 1}
You can also use a different syntax.
URL: '/inbox/{inboxid} '
The path must match exactly, unlike Ngroute, if the user accesses/inbox/, the path configuration will work, but if the/inbox is accessed, the state will not be activated.
You can also use regular expressions to represent parameters so that you can set matching rules by using regular expressions, for example.
Match only Inbox IDs this contain//6 hexidecimal digitsurl: '/inbox/{inboxid:[0-9a-fa-f]{6} ',//or//match every URL At the end of '/inbox '//To ' Inboxid ' (a catch-all) URL: '/inbox/{inboxid:.*} '
Note that capturing groups cannot be used in routing
You can even use query parameters in the path.
Would match a route such as///inbox?sort=ascendingurl: '/inbox?sort '
Absolute routingIf you use the absolute URL method, you need to add special characters in the URL string development ^
$stateProvider . State (' contacts ', { URL: '/contacts ', ... }) . State (' Contacts.list ', { URL: ' ^/list ', ... });
‘contacts‘
Status will match"/contacts"
‘contacts.list‘
The status will match "/list"
. The URL of the child state is not appended to the URL of the parent state because it is used ^
.
Nested routines by
We can use URL parameters to add to the route to implement nested routines. This can provide multiple ui-views on our page, for example, we can provide nested independent routes on top of/inbox. The sub-state is used here.
$stateProvider . State (' Inbox ', { URL: '/inbox/:inboxid ', Template: ' <div>
The first route, as before, now has a second route, a Zi Lu that matches inbox, and the syntax (.) indicates that this is a sub-route.
/INBOX/1 matches the first state, and/inbox/1/priority matches the second state. With this syntax, we can support nested URLs in the parent route. The Ui-view directive in the parent view will handle the priority.
ParamsThe params option is an array of parameter names or regular values. It cannot merge URL options, and the app populates the $stateParams service with these parameters when the state is activated.
ViewsWe can provide a named view in state. This is a powerful feature, and in a single view, we can define multiple views and even use a single template.
If we use the views parameter, then Templateurl, template, and Templateprovider are ignored. If we want to include the parent template, we need to create an abstract template.
If we have the following template.
<div> <div ui-view= "Filters" ></div> <div ui-view= "Mailbox" ></div> < div ui-view= "Priority" ></div></div>
The main note is that the top-level state naturally corresponds to the view in the master page, which is generally noname, so a noname view is required to match the placeholder. Other views need to match the view in the parent state placeholder, these placeholder can be named or naname, natural, Noname can only have one, otherwise cannot differentiate, we in provider configuration, It is necessary to describe clearly the correspondence between these view and placeholder.
Use @ To define an absolutely named view name, preceded by the name of placeholder, followed by the name of the state. An empty representation of an unnamed ui-view,@ is followed by an empty representation relative to the root template, usually index.html
We can create a named view and populate the corresponding template. Each child view can have a unique template, controller, and data.
$stateProvider . State (' Inbox ', {views : { ' filters ': { Template: '
In this example, we have two named views nested in the abstract view.
AbstractWe can never activate an abstract template directly, but it is activated by deriving a template.
Abstract templates provide templates that encapsulate named views that can be passed $scope objects to derived child templates. It can be used to solve dependency problems, or specific data processing, or simply the same URL to nest multiple routes, for example, all routes are under/admin.
$stateProvider . State (' admin ', { abstract:true, url: '/admin ', Template: ' <div ui-view></ Div> ' }) . State (' Admin.index ', { URL: '/index ', Template: '
OnEnter, OnExitThese callback functions are called when the application enters or exits the view. They can both set the callback function, and the function can access the obtained data.
These callback functions provide some of our ability to access new views, or to change the current state. This is a good place to execute the "is you sure" dialog box, or to request the user to log in before entering.
Two functions do not provide parameters, the required information needs to be provided by itself.
DataWe can attach any number to our state configuration object Configobject, the Data property is similar to the Resolve property, and will not resolve promise unless it is injected into the controller.
Attaching data is a convenient way to pass data from the parent state to the child State.
EvnetsSimilar to Ngroute services, Angular-route services trigger multiple events at different points in the state life cycle. We can handle these events by listening to them in the $scope.
All of the following events are triggered in the $rootScope, so we can listen to these events in any $scope object.
State Change eventscan be monitored as follows
$scope. $on (' $stateChangeStart ', function (evt, tostate, Toparams, FromState, Fromparams), { //We can prevent this STA Te from completing evt.preventdefault ();});
$stateChangeStartTriggered when a state starts to go over another state.
$stateChangeSuccesstriggered when the state transition is complete.
$stateChangeErrorAn error occurred in the state transition. Common errors such as the inability to get a template, or promise not succeed resolve and so on
View Load EventsUi-router also provides events for the view loading phase.
$viewContentLoadingThe view begins to load, however, before the DOM is rendered.
You can listen as follows.
$scope. $on (' $viewContentLoading ', function (event, viewconfig) { //Access to all the View config properties. and one special property ' TargetView ' //Viewconfig.targetview});
$viewContentLoadThe view is loaded and the rendering is complete.
$stateParamsIn the previous section, we used the $stateParams to get the params from the URL parameter, which is different from the URL.
For example, if we inbox the status URL as follows.
URL: '/inbox/:inboxid/messages/{sorted}?from&to '
The user uses the following URL to access
/inbox/123/messages/ascending?from=10&to=20
Our $stateParams object will fetch the following data.
{inboxid: ' 123 ', sorted: ' Ascending ', From:10, to:20}
$urlRouterProviderSimilar to Ngroute, you can create rules that are processed when a particular URL is accessed.
Different states can be activated through different URLs, so $urlRouterProvider is not required when managing activation and loading state. It is required outside of state management, such as redirection, or verification.
When ()The When function requires two parameters, we want to match the path, and the other is the target we want to redirect. It can also be a function.
For example, if you want any empty routes to be routed to our/inbox route.
. config (function ($urlRouterProvider) { $urlRouterProvider. When (' ', '/inbox ');});
If a function handler is provided, the function is called when the route matches, and it can return the result of one of the following three types.
- False, this response tells $urlRouter the rules do not match, and should look for other matching states that are useful when we want to verify that the user has access to the correct address.
- String, $urlRouter it as the redirect target.
- True or undefined, the function has already processed the URL
otherwise ()
Similar to the Oterwise () method in Ngroute, Oterwiese () redirects without additional route matching. This is a good way to create a default URL.
The otherwise () function requires only one argument, a string, or a function.
If a string is provided, it is treated as a default address, which is redirected to this address when any wrong or mismatched route is not matched.
If it is a function, it will be executed when there is no other route match.
. config (function ($urlRouterProvider) { $urlRouterProvider. Otherwise ('/'); or $urlRouterProvider. Otherwise ( function ($injector, $location) { $location. Path ('/'); });});
Rule ()
You can use the rule () function if we want to process any route or do some processing before other routes.
We must return a validated path string
App. Config (function ($urlRouterProvider) { $urlRouterProvider. Rule ( function ($injector, $location) { Return '/index '; })
Activation status
There are three ways to activate a specific state
- Use the $state. Go () method
- Connections that use UI-SREF bindings
- Navigate directly to the URL associated with the state
Create a Registration wizard
Why not use it?
We create a Registration wizard to rehearse the use of ui-router.
Using Ui-router, we create a simple registration service that uses a controller to process the registration.
First, we create the view of the app.
<div ng-controller= "Wizardsignupcontroller" >
In this view, we define the registration view. Next, in the Registration Wizard, you need three steps
- Start, in this step, we get the user name, provide welcome information
- Email, here, we get the user's email message
- Finish, here, the user completes the registration, we simply display the completion page
Registration process relies on the Wizardapp.controllers module,
Angular.module (' Wizardapp ', [ ' Ui.router ', ' wizardapp.controllers ' ]);
Our Wizardsignupcontroller controller uses $scope. The user object collects information throughout the process.
Angular.module (' wizardapp.controllers ', []). Controller (' Wizardsignupcontroller ', [' $scope ', ' $state ', function ($scope, $state) { $scope. user = {}; $scope. Signup = function () {}}]);
The wizard now handles the main work of logical processing, configuring Config ()
Angular.module (' Wizardapp ', [ ' Ui.router ', ' wizardapp.controllers ' ]). config ([' $stateProvider ', ' $ Urlrouterprovider ', function ($stateProvider, $urlRouterProvider) { $stateProvider . State (' start ', { URL: '/step_1 ', templateurl: ' partials/wizard/step_1.html ' }) . State (' email ', { URL: '/step_2 ', templateurl: ' partials/wizard/step_2.html ' }) . State (' Finish ', { URL: '/finish ', templateurl: ' partials/wizard/step_3.html ' );}]);
In this way, our basic process is already there. Now, if the user navigates to/step_1, they will see the start page, although the address is now/step_1, and we want to be/wizard/step_1
For this effect, we create an abstract state to host each step.
. config ([' $stateProvider ', ' $urlRouterProvider ', function ($stateProvider, $urlRouterProvider) { $stateProvider . State (' Wizard ', { abstract:true, url: '/wizard ', Template: ' <div><div ui-view></ Div></div> ' }) . State (' Wizard.start ', { URL: '/step_1 ', templateurl: ' partials/wizard/ Step_1.html ' }) . State (' Wizard.email ', { URL: '/step_2 ', templateurl: ' Partials/wizard/step_2. HTML ' }) . State (' Wizard.finish ', { URL: '/finish ', templateurl: ' partials/wizard/step_3.html ') });}]);
In this way, they are safely nested under the/wizard.
Navigating between states, we use the instruction Ui-sref provided by Ui-router to generate links, which are used to generate navigation links.
For example, Step_1.html is as follows.
<!--step_1.html-->
We also want to execute a specific action after the registration process is completed to invoke the signup function defined on the parent controller, and we can add a controller in the final step to invoke the $scope. Signup () function. Because the entire wizard is encapsulated in Wizardsignupcontrooler, we can access nested scope objects as usual.
. State (' Wizard.finish ', { URL: '/finish ', templateurl: ' partials/wizard/step_3.html ', Controller: function ($scope) { $scope. Signup (); }});
SummarizeHere we delve into almost all the features of Ui-router, and we find this library very useful and hopefully can help you.
ResourcesLearn Ui-router Series Articles Index
Angular Ui-router