Home > Web Front-end > JS Tutorial > A complete guide to UI Router in Angularjs_AngularJS

A complete guide to UI Router in Angularjs_AngularJS

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
Release: 2016-05-16 15:16:49
Original
1159 people have browsed it

First of all, I will introduce you to the basic usage of angular-ui-router.

How to reference dependency angular-ui-router

angular.module('app',["ui.router"])
.config(function($stateProvider){
$stateProvider.state(stateName, stateCofig);
}) 
Copy after login

$stateProvider.state(stateName, stateConfig)

stateName is of type string
stateConfig is object type
//statConfig can be an empty object
$stateProvider.state("home",{});
//state can have children and parents
$stateProvider.state("home",{});
$stateProvider.state("home.child",{})
//state can be chained
$stateProvider.state("home",{}).state("about",{}).state("photos",{});

StateConfig contains fields: template, templateUrl, templateProvider, controller, controllerProvider, resolve, url, params, views, abstract, onEnter, onExit, reloadOnSearch, data

$urlRouteProvider

$urlRouteProvider.when(whenPath, toPath)
$urlRouterProvider.otherwise(path)
$urlRouteProvider.rule(handler)

$state.go

$state.go(to, [,toParams],[,options])
The formal parameter to is of type string, which is required. Use "^" or "." to indicate a relative path;
The formal parameter toParams is nullable and the type is object;
The formal parameter options is nullable and the type is an object. The fields include: location is a bool type and the default is true, inherit is a bool type and the default is true, relative is an object and the default is $state.$current, notify is a bool type and the default is true, and reload is a bool type and the default is true. is false

$state.go('photos.detail')
$state.go('^') to the previous level, such as from photo.detail to photo
$state.go('^.list') to adjacent state, such as from photo.detail to photo.list
$state.go('^.detail.comment') to grandchild state, such as from photo.detail to photo.detial.comment

ui-sref

ui-sref='stateName'
ui-sref='stateName({param:value, param:value})'

ui-view

== ui-view without name

<div ui-view></div>
$stateProvider.state("home",{
template: "<h1>hi</h1>"
}) 
Copy after login

Or configure it like this:

$stateProvider.state("home"{
views: {
"": {
template: "<h1>hi</h1>"
}
}
}) 
Copy after login

==Named ui-view

<div ui-view="main"></div>
$stateProvider.state("home",{
views: {
"main" : {
template: "<h1>hi</h1>"
}
}
}) 
Copy after login

==Multiple ui-view

<div ui-view></div>
<div ui-view="data"></div>
$stateProvider.state("home",{
views: {
"":{template: "<h1>hi</h1>"},
"data": {template: "<div>data</div>"}
}
}) 
Copy after login

Project file structure

node_modules/
partials/
.....about.html
.....home.html
.....photos.html
app.js
index.html

Create state and view

app.js

var photoGallery = angular.module('photoGallery',["ui.router"]);
photoGallery.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home',{
url: '/home',
templateUrl: 'partials/home.html'
})
.state('photos',{
url: '/photos',
templateUrl: 'partials/photos.html'
})
.state('about',{
url: '/about',
templateUrl: 'partials/about.html'
})
}) 
Copy after login

index.html

<!DOCTYPE html>
<html lang="en" ng-app="photoGallery">
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.css"/>
</head>
<body>
<h1>Welcome</h1>
<div ui-view></div>
<script src="node_modules/jquery/dist/jquery.js"></script>
<script src="node_modules/angular/angular.js"></script>
<script src="node_modules/angular-ui-router/release/angular-ui-router.js"></script>
<script src="node_modules/angular-animate/angular-animate.js"></script>
<script src="node_modules/bootstrap/dist/js/bootstrap.js"></script>
<script src="node_modules/angular-bootstrap/ui-bootstrap-tpls.js"></script>
<script src="app.js"></script>
</body>
</html> 
Copy after login

Jump between states

index.html

<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a ui-sref="home" class="navbar-brand">Home</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>
<a ui-sref="photos">Photos</a>
</li>
<li>
<a ui-sref="about">About</a>
</li>
</ul>
</div>
</div>
</nav>
<div ui-view></div>
Copy after login

The above jumps between states through the ui-sref attribute.

Multiple views and state nesting

Sometimes, there may be multiple ui-views on a page, such as:

<div ui-view="header"></div>
<div ui-view="body"></div>
Copy after login
Copy after login
Copy after login

Assume that the above page belongs to a state named parent.

We know that in ui-router, a state is set roughly like this:

<div ui-view="header"></div>
<div ui-view="body"></div>
Copy after login
Copy after login
Copy after login

All key-value pairs under views in all states (similar to "body@content":{templateUrl: 'partials/photos.html'}) are put into a key-value set. The working principle of ui-view is to find matching keys in this key value set based on its own attribute values, and display the corresponding page when found.

Click on the page link corresponding to the header, which may jump to another sub-page appearing at the position of

. At this time, a child-parent relationship appears on the page, and each page belongs to a certain state, so a child-parent relationship appears between states. These redirected subpages may be called parent.son1, parent.son2... in the routing settings. This is the nesting of state.

Add content.html and header.html to the existing file structure, and the file structure becomes:

node_modules/
partials/
.....about.html
.....home.html
.....photos.html
.....content.html
.....header.html
app.js
index.html

content.html contains multiple ui-views. One ui-view is related to the page header and remains unchanged; a ui-view will display different content according to the click on the page header

<div ui-view="header"></div>
<div ui-view="body"></div>
Copy after login
Copy after login
Copy after login

header.html Put the nav part of the original indext.html here

<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a ui-sref="content.home" class="navbar-brand">Home</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>
<a ui-sref="content.photos">Photos</a>
</li>
<li>
<a ui-sref="content.about">About</a>
</li>
</ul>
</div>
</div>
</nav> 
Copy after login

index.html now looks like this

app.js routing is now set up like this

var photoGallery = angular.module('photoGallery',["ui.router"]);
photoGallery.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('home');
$stateProvider
.state('content',{
url: '/',
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{templateUrl: 'partials/header.html'},
}
})
.state('content.home',{
url: 'home',
views:{
"body@content":{templateUrl: 'partials/home.html'}
}
})
.state('content.photos',{
url: 'photos',
views:{
"body@content":{templateUrl: 'partials/photos.html'}
}
})
.state('content.about',{
url:'about',
views:{
"body@content":{templateUrl: 'partials/about.html'}
}
})
}) 
Copy after login

At this time, the page is presented like this:

→ Go to the home route

.state('content.home',{
url: 'home',
views:{
"body@content":{templateUrl: 'partials/home.html'}
}
}) 
Copy after login
Copy after login

以上,告诉我们partials/home.html将会被加载到与"body@content"匹配的ui-view中。暂时对应的ui-view还没有出现,于是等待。

→ 路由看到index.html上的

.state('content',{
url: '/',
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{templateUrl: 'partials/header.html'},
}
})
Copy after login

于是,就找到了content这个state下views下的 "":{templateUrl: 'partials/content.html'}这个键值对,把partials/content.html显示出来。

→ 分别加载partials/content.html页面上的各个部分

看到

,就加载如下:

"header@content":{templateUrl: 'partials/header.html'},

看到

,先加载 "body@content":{templateUrl: 'partials/home.html'}

→ 点击header上的链接

点击Photos,来到:

.state('content.photos',{
url: 'photos',
views:{
"body@content":{templateUrl: 'partials/photos.html'}
}
}) 
Copy after login

把partials/photos.html显示到

中去。

点击

,来到:

.state('content.about',{
url:'about',
views:{
"body@content":{templateUrl: 'partials/about.html'}
}
})
Copy after login

把partials/about.html显示到

中去。

state多级嵌套

以上,在路由设置中,state名称有content, content.photos有了这样的一层嵌套。接下来,要实现state的多级嵌套。

在photos.html页面准备加载一个子页面,叫做photos-list.html;
与photo-list.html页面相邻的还有一个页面,叫做photo-detail.html;
在photo-detail.html页面上加载一个子页面,叫做photos-detail-comment.html;

这样,页面有了嵌套关系,state也相应的会有嵌套关系。

现在,文件结构变成:

node_modules/
partials/
.....about.html
.....home.html
.....photos.html
.....content.html
.....header.html
.....photos-list.html
.....photo-detail.html
.....photos-detail-comment.html
app.js
index.html

photos.html 加一个容纳子页面的ui-view

photos

如何到达这个子页面呢?修改header中的相关部分如下:

<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a ui-sref="content.home" class="navbar-brand">Home</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>
<a ui-sref="content.photos.list">Photos</a>
</li>
<li>
<a ui-sref="content.about">About</a>
</li>
</ul>
</div>
</div> 
Copy after login

以上,通过Photos来到photos.html的子页面photos-list.html.

photos-list.html 通过2种途径到相邻页photo-detail.html

<h1>photos-list</h1>
<ul>
<li><a ui-sref="^.detail">我通过相对路径到相邻的state</a></li>
<li><a ui-sref="content.photos.detail">我通过绝对路径到相邻的state</a></li>
</ul> 
Copy after login

photo-detail.html 又提供了来到其子页面photos-detail-comment.html的ui-view

<h1>photo-details</h1>
<a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
<div ui-view></div> 
Copy after login

photos-detail-comment.html 则很简单:

photos-detail-comment

app.js state多级嵌套的设置为

var photoGallery = angular.module('photoGallery',["ui.router"]);
photoGallery.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('home');
$stateProvider
.state('content',{
url: '/',
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{templateUrl: 'partials/header.html'},
}
})
.state('content.home',{
url: 'home',
views:{
"body@content":{templateUrl: 'partials/home.html'}
}
})
.state('content.photos',{
url: 'photos',
views:{
"body@content":{templateUrl: 'partials/photos.html'}
}
})
.state('content.photos.list',{
url: '/list',
templateUrl: 'partials/photos-list.html'
})
.state('content.photos.detail',{
url: '/detail',
templateUrl: 'partials/photos-detail.html'
})
.state('content.photos.detail.comment',{
url: '/comment',
templateUrl: 'partials/photos-detail-comment.html'
})
.state('content.about',{
url:'about',
views:{
"body@content":{templateUrl: 'partials/about.html'}
}
})
})
Copy after login

抽象state

如果一个state,没有通过链接找到它,那就可以把这个state设置为abstract:true,我们把以上的content和content.photos这2个state设置为抽象。

.state('content',{
url: '/',
abstract: true,
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{templateUrl: 'partials/header.html'},
}
})
...
.state('content.photos',{
url: 'photos',
abstract: true,
views:{
"body@content":{templateUrl: 'partials/photos.html'}
}
})
Copy after login

那么,当一个state设置为抽象,如果通过ui-sref或路由导航到该state会出现什么结果呢?

--会导航到默认路由上

$urlRouterProvider.otherwise('home');


.state('content.home',{
url: 'home',
views:{
"body@content":{templateUrl: 'partials/home.html'}
}
}) 
Copy after login
Copy after login

最终把partials/home.html显示出来。

使用控制器

在实际项目中,数据大多从controller中来。

首先在路由中设置state所用到的控制器以及控制器别名。

var photoGallery = angular.module('photoGallery',["ui.router"]);
photoGallery.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('home');
$stateProvider
.state('content',{
url: '/',
abstract: true,
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{templateUrl: 'partials/header.html'},
}
})
.state('content.home',{
url: 'home',
views:{
"body@content":{
templateUrl: 'partials/home.html',
controller: 'HomeController',
controllerAs: 'ctrHome'
}
}
})
.state('content.photos',{
url: 'photos',
abstract: true,
views:{
"body@content":{
templateUrl: 'partials/photos.html',
controller: 'PhotoController',
controllerAs: 'ctrPhoto'
}
}
})
.state('content.photos.list',{
url: '/list',
templateUrl: 'partials/photos-list.html',
controller: "PhotoListController",
controllerAs: 'ctrPhotoList'
})
.state('content.photos.detail',{
url: '/detail',
templateUrl: 'partials/photos-detail.html',
controller: 'PhotoDetailController',
controllerAs: 'ctrPhotoDetail'
})
.state('content.photos.detail.comment',{
url: '/comment',
templateUrl: 'partials/photos-detail-comment.html'
})
.state('content.about',{
url:'about',
views:{
"body@content":{templateUrl: 'partials/about.html'}
}
})
})
Copy after login

添加controller.js,该文件用来定义所用到的controller.现在的文件结构为:

asserts/
.....css/
.....images/
..........image1.jpg
..........image2.jpg
..........image3.jpg
..........image4.jpg
node_modules/
partials/
.....about.html
.....home.html
.....photos.html
.....content.html
.....header.html
.....photos-list.html
.....photo-detail.html
.....photos-detail-comment.html
app.js

index.html

controllers.js

photoGallery.controller('HomeController',['$scope', '$state', function($scope, $state){
this.message = 'Welcome to the Photo Gallery';
}]);
//别名:ctrPhoto
photoGallery.controller('PhotoController',['$scope','$state', function($scope, $state){
this.photos = [
{ id: 0, title: 'Photo 1', description: 'description for photo 1', imageName: 'image1.jpg', comments:[
{name: 'user1', comment: 'Nice'},
{ name:'User2', comment:'Very good'}
]},
{ id: 1, title: 'Photo 2', description: 'description for photo 2', imageName: 'image2.jpg', comments:[
{ name: 'user2', comment: 'Nice'},
{ name:'User1', comment:'Very good'}
]},
{ id: 2, title: 'Photo 3', description: 'description for photo 3', imageName: 'image3.jpg', comments:[
{name: 'user1', comment: 'Nice'}
]},
{ id: 3, title: 'Photo 4', description: 'description for photo 4', imageName: 'image4.jpg', comments:[
{name: 'user1', comment: 'Nice'},
{ name:'User2', comment:'Very good'},
{ name:'User3', comment:'So so'}
]}
];
//给子state下controller中的photos赋值
this.pullData = function(){
$scope.$$childTail.ctrPhotoList.photos = this.photos;
}
}]);
//别名:ctrPhotoList
photoGallery.controller('PhotoListController',['$scope','$state', function($scope, $state){
this.reading = false;
this.photos = new Array();
this.init = function(){
this.reading = true;
setTimeout(function(){
$scope.$apply(function(){
$scope.ctrPhotoList.getData();
});
}, 1500);
}
this.getData = function(){
//调用父state中controller中的方法
$scope.$parent.ctrPhoto.pullData();
/*this.photos = $scope.$parent.ctrPhoto.photos;*/
this.reading = false;
}
}]);
//别名:ctrPhotoDetail
photoGallery.controller('PhotoDetailController',['$scope', '$state', function($scope,$state){
}]); 
Copy after login

以上,通过$scope.$$childTail.ctrPhotoList在父state中的controller中拿到子state中的controller;通过$scope.$parent.ctrPhoto在子state中的controller中拿到父state中的controller。

photos-list.html

<h1>photos-list</h1>
<div ng-init="ctrPhotoList.init()">
<div style="margin:auto; width: 40px;" ng-if="ctrPhotoList.reading">
<i class="fa fa-spinner fa-5x fa-pulse"></i>
</div>
<div class="well well-sm" ng-repeat="photo in ctrPhotoList.photos">
<div class="media">
<div class="media-left" style="width:15%;">
<a ui-sref="content.photos.detail">
<img class="img-responsive img-rounded" src="../asserts/images/{{photo.imageName}}" alt="">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">{{photo.title}}</h4>
{{photo.description}}
</div>
</div>
</div>
</div> 
Copy after login

state间如何传路由参数

在content.photos.detail这个state设置接收一个路由参数。

.state('content.photos.detail',{
url: '/detail/:id',
templateUrl: 'partials/photos-detail.html',
controller: 'PhotoDetailController',
controllerAs: 'ctrPhotoDetail'
}) 
Copy after login

photos-list.html 送出一个路由参数

<h1>photos-list</h1>
<div ng-init="ctrPhotoList.init()">
<div style="margin:auto; width: 40px;" ng-if="ctrPhotoList.reading">
<i class="fa fa-spinner fa-5x fa-pulse"></i>
</div>
<div class="well well-sm" ng-repeat="photo in ctrPhotoList.photos">
<div class="media">
<div class="media-left" style="width:15%;">
<a ui-sref="content.photos.detail({id:photo.id})">
<img class="img-responsive img-rounded" src="../asserts/images/{{photo.imageName}}" alt="">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">{{photo.title}}</h4>
{{photo.description}}
</div>
</div>
</div>
</div> 
Copy after login

以上,通过把路由参数送出。

controller.js PhotoDetailController控制器通过$stateParams获取路由参数

...
//别名:ctrPhotoDetail
photosGallery.controller('PhotoDetailController', ['$scope', '$state', '$stateParams',
function($scope, $state, $stateParams){
var id = null;
this.photo = null;
this.init = function(){
id = parseInt($stateParams.id);
this.photo = $scope.ctrPhoto.photos[id];
}
}
]); 
Copy after login

photos-detail.html 从以上的PhotoDetailController中获取数据。

<h1>photo-details</h1>
<a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
<a ui-sref="content.photos.list" style="margin-left: 15px;">
<i class="fa fa-arrow-circle-left fa-2x"></i>
</a>
<div ng-init="ctrPhotoDetail.init()">
<img class="img-responsive img-rounded" ng-src="../assets/images/{{ctrPhotoDetail.photo.imageName}}"
style="margin:auto; width: 60%;">
<div class="well well-sm" style="margin:auto; width: 60%; margin-top: 15px;">
<h4>{{ctrPhotoDetail.photo.title}}</h4>
<p>{{ctrPhotoDetail.photo.description}}</p>
</div>
<div style="margin:auto; width: 80%; margin-bottom: 15px;">
<button style="margin-top: 10px; width:100%;"
class="btn btn-default" ui-sref=".comment">Comments</button>
</div>
</div>
<div ui-view></div> 
Copy after login

state间如何传字符串参数

在路由中这样设置:

.state('content.photos.detail.comment',{
url:'/comment&#63;skip&limit',
templateUrl: 'partials/photos-detail-comment.html',
controller: 'PhotoCommentController',
controllerAs: 'ctrPhotoComment'
}) 
Copy after login

controllers.js 中修改如下

photoGallery.controller('HomeController',['$scope', '$state', function($scope, $state){
this.message = 'Welcome to the Photo Gallery';
}]);
//别名:ctrPhoto
photoGallery.controller('PhotoController',['$scope','$state', function($scope, $state){
this.photos = [
{ id: 0, title: 'Photo 1', description: 'description for photo 1', imageName: 'image1.JPG', comments:[
{ name:'User1', comment: 'Nice', imageName: 'man.png'},
{ name:'User2', comment:'Very good', imageName: 'man.png'},
{ name:'User3', comment:'Nice', imageName: 'woman.png'},
{ name:'User4', comment:'Very good', imageName: 'woman.png'},
{ name:'User5', comment:'Very good', imageName: 'man.png'},
{ name:'User6', comment:'Nice', imageName: 'woman.png'},
{ name:'User7', comment:'So so', imageName: 'man.png'}
]},
{ id: 1, title: 'Photo 2', description: 'description for photo 2', imageName: 'image2.JPG', comments:[
{ name:'User1', comment: 'Nice', imageName: 'man.png'},
{ name:'User2', comment:'Very good', imageName: 'man.png'},
{ name:'User3', comment:'Nice', imageName: 'woman.png'},
{ name:'User4', comment:'Very good', imageName: 'woman.png'}
]},
{ id: 2, title: 'Photo 3', description: 'description for photo 3', imageName: 'image3.JPG', comments:[
{ name:'User1', comment: 'Nice', imageName: 'man.png'},
{ name:'User2', comment:'Very good', imageName: 'man.png'},
{ name:'User3', comment:'Nice', imageName: 'woman.png'},
{ name:'User4', comment:'Very good', imageName: 'woman.png'},
{ name:'User5', comment:'Very good', imageName: 'man.png'},
{ name:'User6', comment:'Nice', imageName: 'woman.png'},
{ name:'User7', comment:'So so', imageName: 'man.png'}
]},
{ id: 3, title: 'Photo 4', description: 'description for photo 4', imageName: 'image4.JPG', comments:[
{ name:'User6', comment:'Nice', imageName: 'woman.png'},
{ name:'User7', comment:'So so', imageName: 'man.png'}
]}
];
//给子state下controller中的photos赋值
this.pullData = function(){
$scope.$$childTail.ctrPhotoList.photos = this.photos;
}
}]);
//别名:ctrPhotoList
photoGallery.controller('PhotoListController',['$scope','$state', function($scope, $state){
this.reading = false;
this.photos = new Array();
this.init = function(){
this.reading = true;
setTimeout(function(){
$scope.$apply(function(){
$scope.ctrPhotoList.getData();
});
}, 1500);
}
this.getData = function(){
//调用父state中controller中的方法
$scope.$parent.ctrPhoto.pullData();
/*this.photos = $scope.$parent.ctrPhoto.photos;*/
this.reading = false;
}
}]);
//别名:ctrPhotoDetail
photoGallery.controller('PhotoDetailController', ['$scope', '$state', '$stateParams',
function($scope, $state, $stateParams){
var id = null;
this.photo = null;
this.init = function(){
id = parseInt($stateParams.id);
this.photo = $scope.ctrPhoto.photos[id];
}
}
]);
photoGallery.controller('PhotoCommentController', ['$scope', '$state', '$stateParams',
function($scope, $state, $stateParams){
var id, skip, limit = null;
this.comments = new Array();
this.init = function(){
id = parseInt($stateParams.id);
var photo = $scope.ctrPhoto.photos[id];
if($stateParams.skip){
skip = parseInt($stateParams.skip);
}else{
skip = 0;
}
if($stateParams.limit){
limit = parseInt($stateParams.limit);
}else{
limit = photo.comments.length;
}
this.comments = photo.comments.slice(skip, limit);
}
}
]); 
Copy after login

也就是,$stateParams不仅可以接收路由参数,还可以接收查询字符串参数。

photo-detail.html 需要把查询字符串参数传递出去

<h1>photo-details</h1>
<a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
<a ui-sref="content.photos.list" style="margin-left: 15px;">
<i class="fa fa-arrow-circle-left fa-2x"></i>
</a>
<div ng-init="ctrPhotoDetail.init()">
<img class="img-responsive img-rounded" ng-src="../assets/images/{{ctrPhotoDetail.photo.imageName}}"
style="margin:auto; width: 60%;">
<div class="well well-sm" style="margin:auto; width: 60%; margin-top: 15px;">
<h4>{{ctrPhotoDetail.photo.title}}</h4>
<p>{{ctrPhotoDetail.photo.description}}</p>
</div>
<div style="margin:auto; width: 80%; margin-bottom: 15px;">
<button style="margin-top: 10px; width:100%;"
class="btn btn-default" ui-sref=".comment({skip:0, limit:2})">Comments</button>
</div>
</div>
<div ui-view></div> 
Copy after login

以上,通过ui-sref=".comment({skip:0, limit:2})把查询字符串传递出去。

photos-detail-comment.html

<h1>photos-detail-comment</h1>
<div ng-init="ctrPhotoComment.init()" style="margin-top:15px;">
<div ng-repeat="comment in ctrPhotoComment.comments" class="well well-sm" style="margin: auto; width: 60%;">
<div class="media">
<div class="media-left media-middle">
<a href="">
<img class="img-circle" style="width:60px;" src="../assets/images/{{comment.imageName}}" alt="">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">{{comment.name}}</h4>
{{comment.comment}}
</div>
</div>
</div>
</div> 
Copy after login

state间如何传递对象

通过data属性,把一个对象赋值给它。

.state('content',{
url: '/',
abstract: true,
data:{
user: "user",
password: "1234"
},
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{templateUrl: 'partials/header.html'},
}
}) 
Copy after login

给header.html加上一个对应的控制器,并提供注销方法。

$stateProvider
.state('content',{
url: '/',
abstract: true,
data:{
user: "user",
password: "1234"
},
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{
templateUrl: 'partials/header.html',
controller: function($scope, $rootScope, $state){
$scope.logoff = function(){
$rootScope.user = null;
}
}
}
}
})
Copy after login

添加一个有关登录页的state

.state('content.login',{
url:'login',
data:{
loginError: 'User or password incorrect.'
},
views:{
"body@content" :{
templateUrl: 'partials/login.html',
controller: function($scope, $rootScope, $state){
$scope.login = function(user, password, valid){
if(!valid){
return;
}
if($state.current.data.user === user && $state.current.data.password === password){
$rootScope.user = {
name: $state.current.data.user
}
// Or Inherited
/*$rootScope.user = {
name: $state.$current.parent.data.user
};*/
$state.go('content.home'); 
}else{
$scope.message = $state.current.data.loginError;
}
}
}
}
}
}) 
Copy after login

添加login.html文件,现在的文件结构为:

asserts/
.....css/
.....images/
..........image1.jpg
..........image2.jpg
..........image3.jpg
..........image4.jpg
node_modules/
partials/
.....about.html
.....home.html
.....photos.html
.....content.html
.....header.html
.....photos-list.html
.....photo-detail.html
.....photos-detail-comment.html
.....login.html

app.js

index.html

login.html

<form name="form" ng-submit="login(user, password, form.$valid)">
<div class="panel panel-primary" style="width:360px; margin: auto;">
<div class="panel-heading">
<h3 class="panel-title">Indentification</h3>
</div>
<div class="panel-body">
<input name="user" type="text" class="form-control" ng-model="user" placeholder="User ..." required>
<span ng-show="form.user.$error.required && form.user.$dirty" class="label label-danger">Enter the user</span>
<hr>
<input name="password" type="password" class="form-control" ng-model="password" placeholder="Password ..." required>
<span ng-show="form.password.$error.required && form.password.$dirty" class="label label-danger">Enter the password</span> 
</div>
<div class="panel-footer">
<button class="btn btn-default" type="submit">Login</button>
<button class="btn btn-default" type="reset">Reset</button>
<span class="label label-danger">{{message}}</span> 
</div> 
</div>
</form> 
Copy after login

header.html 修改如下

<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> 
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" ui-sref="content.home">Home</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>
<a ui-sref="content.photos.list">Photos</a> 
</li>
<li>
<a ui-sref="content.about">About</a> 
</li> 
</ul>
<ul class="nav navbar-nav navbar-right"> 
<li ng-if="user.name" class="dropdown">
<a class="dropdown-toggle" role="button" aria-expanded="false" href="#" data-toggle="dropdown">{{user.name}} <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a ui-sref="content.home" ng-click="logoff()">Sing out</a></li> 
</ul> 
</li> 
<li ng-if="!user.name">
<a ui-sref="content.login">Sing In</a>
</li> 
</ul> 
</div>
</div>
</nav> 
Copy after login

onEnter和onExit事件

.state('content.photos.detail',{
url: '/detail/:id',
templateUrl: 'partials/photos-detail.html',
controller: 'PhotoDetailController',
controllerAs: 'ctrPhotoDetail',
resolve:{
viewing: function($stateParams){
return{
photoId: $stateParams.id
}
}
},
onEnter: function(viewing){
var photo = JSON.parse(sessionStorage.getItem(viewing.photoId));
if(!photo){
photo = {
views: 1,
viewing: 1
}
}else{
photo.views = photo.views + 1;
photo.viewing = photo.viewing + 1;
}
sessionStorage.setItem(viewing.photoId, JSON.stringify(photo));
},
onExit: function(viewing){
var photo = JSON.parse(sessionStorage.getItem(viewing.photoId));
photo.viewing = photo.viewing - 1;
sessionStorage.setItem(viewing.photoId, JSON.stringify(photo));
}
})
Copy after login

在PhotoDetailController中:

photoGallery.controller('PhotoDetailController', ['$scope', '$state', '$stateParams',
function($scope, $state, $stateParams){
var id = null;
this.photo = null;
this.viewObj = null;
this.init = function(){
id = parseInt($stateParams.id);
this.photo = $scope.ctrPhoto.photos[id];
this.viewObj = JSON.parse(sessionStorage.getItem($stateParams.id));
}
}
]);
Copy after login

photos-detail.html

<h1>photo-details</h1>
<a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
<a ui-sref="content.photos.list" style="margin-left: 15px;">
<i class="fa fa-arrow-circle-left fa-2x"></i>
</a>
<div ng-init="ctrPhotoDetail.init()">
<img class="img-responsive img-rounded" ng-src="../assets/images/{{ctrPhotoDetail.photo.imageName}}"
style="margin:auto; width: 60%;">
<div class="well well-sm" style="margin:auto; width: 60%; margin-top: 15px;">
<div class="well well-sm pull-right" style="width: 100px;">
<i>Views <span class="badge">{{ctrPhotoDetail.viewObj.views}}</span></i>
</div>
<div class="well well-sm pull-right" style="width: 110px;">
<i>Viewing <span class="badge">{{ctrPhotoDetail.viewObj.viewing}}</span></i>
</div>
<h4>{{ctrPhotoDetail.photo.title}}</h4>
<p>{{ctrPhotoDetail.photo.description}}</p>
</div>
<div style="margin:auto; width: 80%; margin-bottom: 15px;">
<button style="margin-top: 10px; width:100%;"
class="btn btn-default" ui-sref=".comment({skip:0, limit:2})">Comments</button>
</div>
</div>
<div ui-view></div> 
Copy after login

StateChangeStart事件

controller.js 增加如下

photoGallery.controller('RootController', ['$scope', '$state', '$rootScope',
function($scope, $state, $rootScope){
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams){
if(toState.data.required && !$rootScope.user){
event.preventDefault();
$state.go('content.login');
}
});
}
]); 
Copy after login

修改content这个state:

.state('content',{
url:'/',
abstract: true,
data:{
user: "user",
password: "1234"
},
views:{
"":{
templateUrl: 'partials/content.html',
controller: 'RootController'
},
"header@content":{
templateUrl: 'partials/header.html',
controller: function($scope, $rootScope, $state){
$scope.logoff = function(){
$rootScope.user = null;
}
}
}
}
})
Copy after login

content.photos.detail这个state

.state('content.photos.detail',{
url:'/detail/:id',
templateUrl: 'partials/photos-detail.html',
controller: 'PhotoDetailController',
controllerAs: 'ctrPhotoDetail',
data:{
required: true
},
resolve:{
viewing: function($stateParams){
return{
photoId: $stateParams.id
}
}
},
onEnter: function(viewing){
var photo = JSON.parse(sessionStorage.getItem(viewing.photoId));
if(!photo){
photo = {
views: 1,
viewing: 1
}
}else{
photo.views = photo.views + 1;
photo.viewing = photo.viewing + 1;
}
sessionStorage.setItem(viewing.photoId, JSON.stringify(photo));
},
onExit: function(viewing){
var photo = JSON.parse(sessionStorage.getItem(viewing.photoId));
photo.viewing = photo.viewing - 1;
sessionStorage.setItem(viewing.photoId, JSON.stringify(photo));
}
})
Copy after login

以上,添加了

data:{
required: true
} 
Copy after login

同理,content.photos.detail.comment这个state

.state('content.photos.detail.comment',{
url:'/comment&#63;skip&limit',
templateUrl: 'partials/photos-detail-comment.html',
controller: 'PhotoCommentController',
controllerAs: 'ctrPhotoComment',
data:{
required: true
}
}) 
Copy after login

StateNotFound事件

photosGallery.controller('RootController', ['$scope', '$state', '$rootScope',
function($scope, $state, $rootScope){
$rootScope.$on('$stateChangeStart', 
function(event, toState, toParams, fromState, fromParams){
if(toState.data.required && !$rootScope.user){
event.preventDefault();
$state.go('content.login');
return;
} 
});
$rootScope.$on('$stateNotFound', 
function(event, unfoundState, fromState, fromParams){
event.preventDefault();
$state.go('content.notfound');
});
}
]); 
Copy after login

添加一个state:

.state('content.notfound',{
url:'notfound',
views: {
"body@content": {templateUrl: 'partials/page-not-found.html'} 
} 
}) 
Copy after login

page-not-found.html

<div class="well well-sm" style="margin: 20px;">
<i class="fa fa-frown-o fa-4x pull-left"></i><h3>404 - Sorry! Not found your page.</h3>
</div> 
Copy after login

StateChangeSuccess事件

photosGallery.controller('RootController', ['$scope', '$state', '$rootScope',
function($scope, $state, $rootScope){
$rootScope.accessLog = new Array();
$rootScope.$on('$stateChangeStart', 
function(event, toState, toParams, fromState, fromParams){
if(toState.data.required && !$rootScope.user){
event.preventDefault();
$state.go('content.login');
return;
} 
});
$rootScope.$on('$stateNotFound', 
function(event, unfoundState, fromState, fromParams){
event.preventDefault();
$state.go('content.notfound');
});
$rootScope.$on('$stateChangeSuccess', 
function(event, toState, toParams, fromState, fromParams){
$rootScope.accessLog.push({
user: $rootScope.user,
from: fromState.name,
to: toState.name,
date: new Date()
});
});
}
]); 
Copy after login

添加一个state

.state('content.log',{
url:'log',
data:{
required: true
},
views: {
"body@content": {templateUrl: 'partials/log.html'} 
} 
}) 
Copy after login

log.html

<h1><i class="fa fa-file-text-o"></i> Access Log</h1>
<div style="margin:auto; width: 380px;">
<div class="well well-sm" ng-repeat="log in accessLog track by $index">
<i class="fa fa-pencil fa-2x pull-left"></i>
{{log.user &#63; log.user.name: 'anonymous'}} in {{log.date | date: 'longDate'}} at {{log.date | date: 'shortTime'}}
<p>From: {{log.from}} => to: {{log.to}}</p>
</div>
</div> 
Copy after login

StateChangeError事件

photosGallery.controller('RootController', ['$scope', '$state', '$rootScope',
function($scope, $state, $rootScope){
$rootScope.accessLog = new Array();
$rootScope.$on('$stateChangeStart', 
function(event, toState, toParams, fromState, fromParams){
if(toState.data.required && !$rootScope.user){
event.preventDefault();
$state.go('content.login');
return;
} 
});
$rootScope.$on('$stateNotFound', 
function(event, unfoundState, fromState, fromParams){
event.preventDefault();
$state.go('content.notfound');
});
$rootScope.$on('$stateChangeSuccess', 
function(event, toState, toParams, fromState, fromParams){
$rootScope.accessLog.push({
user: $rootScope.user,
from: fromState.name,
to: toState.name,
date: new Date()
});
});
$rootScope.$on('$stateChangeError', 
function(event, toState, toParams, fromState, fromParams, error){
event.preventDefault();
$state.go('content.error', {error: error});
});
}
]); 
Copy after login

添加2个state:

.state('content.profile', {
url:'profile',
data:{
required: true
},
resolve:{
showError: function(){
throw 'Error in code.';
}
},
views:{
"body@content": {template: '<div>Error</div>'}
} 
})
.state('content.error',{
url:'error/:error',
views:{
"body@content":{
templateUrl: 'partials/error.html',
controller: function($scope, $stateParams){
$scope.error = {
message: $stateParams.error
}
}
}
}
})
Copy after login

error.html

<div class="well well-sm" style="margin: 20px;">
<i class="fa fa-exclamation-circle fa-2x"> Sorry! But this message was displayed: {{error.message}}</i>
</div>
Copy after login
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template