官术网_书友最值得收藏!

Introduction to Angular UI Router

The core of Ionic Framework is an open source routing module called Angular UI Router. It implements states that are a part of a state machine represented by the complete app. In a normal Angular app, we use ngRoute, which defines different routes, each of which can be associated with only a single ng-view and one corresponding templateUrl. In the UI Router, routes are represented by states (discussed in the following chapter).

States and URLs

In an app using the UI Router, the views are not tied up to the URL and hence you can change the parts of the app even without changing the URL. In any mobile app, the views are not so simple that they can be changed wholly but there is a complex hierarchy of views and sub-views that change based on different states. Due to this reason it is better to maintain states instead of routes and hence Ionic chose to use the Angular UI Router instead of ngRoute. States are also defined in the config section of an angular module.

We will learn how to create a state by adding a simple view for our sample app. A new state is created with the name homeView, which will be the default view shown after the app is bootstrapped. It will be associated with a controller and a template string or template URL similar to the route:

angular.module('BookStore', ['ionic'])
.config(['$stateProvider','$urlRouterProvider',
  function mainAppConfig($stateProvider,$urlRouterProvider){
    $urlRouterProvider.otherwise('/home')
    $stateProvider.state('homeView', {
      url: '/home',
      template: '<p>App Home View!</p>',
  .   controller: 'HomeController'
    });
  }]
)

The state that we have created will be accessible using the URL http://<domain-name>/home and will be opened by default because of the code $urlRouterProvider.otherwise('/home').

We can associate a template like the previous one or give a URL to the html template using the templateUrl property on the state. Whenever this state is loaded, the template HTML code will be injected into the <ion-nav-view> directive of the parent state. In this case, for the root state, we should be adding the <ion-nav-view> directive to the index.html file with some initial content:

<ion-nav-view>
  Loading View...
</ion-nav-view>

The perfect way to decide whether a state should exist or not is by ensuring that a state adheres to the following principles:

  • A state represents a section of your app that is navigable from one or multiple other states and displays important information about your app
  • A state encapsulates important markup and logic in terms of a template and a controller
  • Sometimes, multiple states would have some part of the view common and the best approach to implement such a requirement is to create separate states and use state hierarchy to model the commonalities

Nested states and views

We have already seen how to create a simple state, but we would hardly have an app with simple states. In order to represent a complex view, we would divide our state into some sub states representing sub sections of the views.

We can create nested states in the following multiple ways.

Using the dot notation

In order to create a nested state, we can use . to write the name of the child state after the parent state. If the parent state is named as homeView, we can register a nested state menu by naming it .state ('homeView.menu', {}). The Angular UI Router module by default sets the state before the dot operator as the parent of the state object.

Using the parent property

Nested states can also be created by using a parent property on the state object passed as a second argument to the state method of $stateProvider. The name of the parent state can be set as a string value to the parent property:

$stateProvider.state('menu',{
  parent: 'homeView',
  templateUrl:'homeView.menu.html',
  controller: 'MenuController'
}

Using object-based states

We can use objects instead of strings to set the parent property of the state object:

var homeView = { name:'homeView', ... };
var menu = { name: 'homeView.menu',
             parent: homeView,
             templateUrl:'homeView.menu.html'
           }

States can be registered in any order and a child state can be registered before the parent state. It will queue the child state registration until the parent is registered.

No two state names can be the same. With the dot notation or without dot notation, the names of the states need to be different even if the two states have different parents.

Views for nested views

If the application is in a particular state, and the state is active, then all its ancestor states are active by default. The child states will load their templates into their parents' <ion-nav-view> directives.

Ways to transition to a state

In order to transition to a specific state or make any state active, there are multiple ways available.

You can use an anchor tag and set the href attribute to # followed by the URL for the state. For example, if the URL is set to /home/main, then the href attribute value should be #/home/main:

<a href="#/home/main"> Main Link </a>

Another way to link states in HTML is to use the ui-sref directive, which allows the developer to pass in the state name instead of state URL:

<a ui-sref="homeView.main"> Main Link </a>

If we want to transition to a particular state from JavaScript, then we can use a method on the $state object that can be injected into any controller. Please note that in ui.sref you give the value starting from the parent template. For example, if you are giving a link in index.html then you should give ui-sref='homeView.main' but if the link is in homeView.html then give ui-sref='main':

<a ui-sref="homeView.main"> Main Link </a>

We will be working with a new Ionic Project using a blank starter project template and use the code snippets given along with the chapters to build the BookStore e-commerce sample app.

Abstract state

In the UI router, there is a provision to define an abstract state, which can have child states but it cannot be activated itself. This state cannot be transitioned to and it is activated automatically when one of its descendants is activated. The use cases for using an abstract state is when we want to use a state for layouts only, when a URL needs to be appended to all states, and to provide common data or resolved dependencies to all child states.

Abstract states would still require a <ion-nav-view/> directive in the template:

.state('homeView',{
  abstract: true,
  url: '/home',
  templateUrl: 'homeView.html'
});

Multiple and named views

In a complex mobile app, we would want multiple sections of our app to change according to different states. In Ionic also, we can have more than one <ion-nav-view/> in a single template by giving them a named attribute. We can have only one maximum unnamed ion-nav-view in a template.

When setting multiple views in a state, we have to use the views property, which will contain the name of the views as keys and objects for each view (templateUrl, controller, and so on) as values.

Abstract states would still require a <ion-nav-view/> directive in the template:

$stateProvider
.state('homeView.books', {
  abstract:true,
  url:'/books',
  templateUrl: 'homeView.books.html'
})
.state('homeView.books.list',{
  views: {
    filters: {
      templateUrl:'homeView.books.filters.html'
    },
    list: {
      templateUrl:'homeView.books.list.html'
    }
  }
});

In a state where the views property is set, it automatically ignores the template, templateUrl or templateProvider, so if you want to set a template, then you need to define an abstract state as a parent defining the layout. Also, remember that in Ionic, by default <ion-nav-view/> has such CSS styling that it takes the whole screen size and the last named view will always be on top. You have to write custom CSS styling to achieve your design.

View names – relative versus abstract

In the previous example, by default the named view is expected on the parent state. If we want to reference a specific named view of any ascendant state, then we can use @ to write the exact view like <view-name>@<state-name>.

State parameters

URL routing is very important along with the state mechanics defined for the app. Using the power of URL routing we can send data or parameters in the URL itself, which helps in identifying the state along with some unique identifiers for the state. There are various types of parameter that can be passed to a route or state.

Basic parameters

The URL can have dynamic parts, which can contain any value, and the controller should be able to access the value passed. You can use a : character or { } to define a dynamic URL part, which is called a basic parameter:

$stateProvider
.state('homeView.books.detail', {
  url: "/books/:bookId",
  templateUrl: 'books.detail.html',
  controller: function ($stateParams) {
    // If we got here from a url of /contacts/42
    expect($stateParams).toBe({bookId: "42"});
    // expect() is a method of Jasmine Framework Unit Testing Code
  }
})

Alternatively, the basic parameter can also be defined using curly braces:

url: "/books/{bookId}"

Regex parameters

We can restrict the values passed in the url parameters by using a regular expression inside curly brackets in the url value of the state. For example:

url: "/books/{bookId:[0-9]{1,8}}"

The previous line specifies that the bookId parameter can be digits only and its length can vary from 1 to 8.

Query parameters

Query parameters are similar to the HTML query string parameters commonly used. You can send parameters in the URL itself after the ? symbol as key value pairs.

Single parameter

Sample URL structure to represent single query parameter is as follows:

url: "/books?bookId" // will match to url of /books?bookId=value

Multiple parameters

Sample URL structure to represent multiple query parameters is as follows:

url: "/books?bookId&category" // will match to /books?bookId=v1&category=c1
The $stateParams service

This is an in-built service in the UI Router module, which provides access to each state parameter in the controller. It is important to note that parameters only specific to that state and not its ascendants will be available in the controller. An example of URLs and corresponding $stateParams object is as follows; in this example it is mentioned how the bookId parameter can be accessed using $stateParams:

// If url is of type 'books/:bookId/details?section'
// Actual Url hit is  /books/23/details?section=4
console.log($stateParams);
// Console Output:
{ bookId: 23, section: 4}

State events and resolve

Important angular events are fired during the management of states in an app. Whenever the state changes from one state to another, there are a handful of events that are broadcasted from the $rootScope and are available for all the controller scopes to listen. If we want to handle them globally, we can use the $on method on the $rootScope variable to handle them. The code would look like this:

$rootScope.$on('<event-name>',function handler(eventArgs ...){});

The lists of events available are as follows:

Resolve

Each and every state can have a property resolve, which is helpful to provide content or data to the controller. resolve is an optional map of dependencies that should be injected to the controller.

A useful feature of resolve is that it can also contain promises, which can help us to get data using AJAX requests. Also, the controller is not initialized for a state before all the resolve dependencies. The resolve object contains key and value pairs. The key can be any string whereas the value can be a function or a string. If the value of resolve is a string, it represents a service in the same module, and if it is a function, it should return a value or any promise.

The code for an example resolve block in a state definition looks like this:

$stateProvider.state('homeView',{
  url:'/home',
  resolve: {
    information: function(infoService) {
      return infoService.getInfo();
    },
    about: 'aboutService'
  }
});
主站蜘蛛池模板: 怀化市| 志丹县| 贡觉县| 荆州市| 麻栗坡县| 辽中县| 禹城市| 昂仁县| 基隆市| 基隆市| 菏泽市| 花垣县| 阿尔山市| 溧水县| 辽宁省| 英吉沙县| 乌鲁木齐县| 蛟河市| 军事| 凌云县| 孟州市| 敖汉旗| 丹棱县| 马鞍山市| 哈巴河县| 邢台县| 博乐市| 桑植县| 阜新| 磐石市| 泌阳县| 开鲁县| 建德市| 洪雅县| 望谟县| 乌拉特后旗| 汨罗市| 石嘴山市| 赤峰市| 通许县| 汕尾市|