angularjs中的路由介紹詳解 ui-route

這篇文章主要介紹了Angularjs中UI Router全攻略,涉及到angularjs ui router的基本用法,須要的朋友參考下吧
 

首先給你們介紹angular-ui-router的基本用法。css

如何引用依賴angular-ui-routerhtml

?
1
2
3
4
angular.module( 'app' ,[ "ui.router" ])
.config( function ($stateProvider){
$stateProvider.state(stateName, stateCofig);
})

$stateProvider.state(stateName, stateConfig)node

stateName是string類型
stateConfig是object類型
//statConfig能夠爲空對象
$stateProvider.state("home",{});
//state能夠有子父級
$stateProvider.state("home",{});
$stateProvider.state("home.child",{})
//state能夠是鏈式的
$stateProvider.state("home",{}).state("about",{}).state("photos",{});jquery

stateConfig包含的字段:template, templateUrl, templateProvider, controller, controllerProvider, resolve, url, params, views, abstract, onEnter, onExit, reloadOnSearch, dataangularjs

$urlRouteProviderbootstrap

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

$state.goapp

$state.go(to, [,toParams],[,options])
形參to是string類型,必須,使用"^"或"."表示相對路徑;
形參toParams可空,類型是對象;
形參options可空,類型是對象,字段包括:location爲bool類型默認true,inherit爲bool類型默認true, relative爲對象默認$state.$current,notify爲bool類型默認爲true, reload爲bool類型默認爲falseide

$state.go('photos.detail')
$state.go('^')到上一級,好比從photo.detail到photo
$state.go('^.list')到相鄰state,好比從photo.detail到photo.list
$state.go('^.detail.comment')到孫子級state,好比從photo.detail到photo.detial.commentui

ui-sref

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

ui-view

==沒有名稱的ui-view

?
1
2
3
4
<div ui-view></div>
$stateProvider.state( "home" ,{
template: "<h1>hi</h1>"
})

或者這樣配置:

?
1
2
3
4
5
6
7
$stateProvider.state( "home" {
views: {
"" : {
template: "<h1>hi</h1>"
}
}
})

==有名稱的ui-view

?
1
2
3
4
5
6
7
8
<div ui-view= "main" ></div>
$stateProvider.state( "home" ,{
views: {
"main" : {
template: "<h1>hi</h1>"
}
}
})

==多個ui-view

?
1
2
3
4
5
6
7
8
<div ui-view></div>
<div ui-view= "data" ></div>
$stateProvider.state( "home" ,{
views: {
"" :{template: "<h1>hi</h1>" },
"data" : {template: "<div>data</div>" }
}
})

項目文件結構

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

建立state和view

app.js

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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'
})
})

index.html

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!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>

state之間的跳轉

index.html

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<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>

以上經過ui-sref屬性完成state之間的跳轉。

多個view以及state嵌套

有時候,一個頁面上可能有多個ui-view,好比:

?
1
2
<div ui-view= "header" ></div>
<div ui-view= "body" ></div>

假設,以上頁面屬於一個名稱爲parent的state中。

咱們知道在ui-router中,一個state大體是這樣設置的:

?
1
2
<div ui-view= "header" ></div>
<div ui-view= "body" ></div>

全部state下views下的全部鍵值對(相似 "body@content":{templateUrl: 'partials/photos.html'})都被放到一個鍵值集合中。而ui-view的工做原理就是根據本身的屬性值,到這個鍵值集合中去找匹配 的鍵,找到就把對應的頁面顯示出來。

點擊header對應的頁面連接,可能會跳轉到另外的子頁面出如今<div ui-view="body"></div>這個位置。這時候頁面出現了子父關係,而每一個頁面都屬於某個state,這樣state間 就出現了子父關係。這些跳轉的子頁面,在路由設置中,可能被稱爲parent.son1, parent.son2...這就是state的嵌套。

在現有的文件結構上增長content.html, header.html,文件結構變爲:

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

content.html 包含了多各ui-view, 一個ui-view和頁頭相關,保持不變;令一個ui-view和會根據頁頭上的點擊呈現不一樣的內容

?
1
2
<div ui-view= "header" ></div>
<div ui-view= "body" ></div>

header.html 把原先indext.html中nav部分放到這裏來

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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>

index.html 這時變成了這樣

<div ui-view></div>

app.js 路由如今這樣設置

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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' }
}
})
})

這時候,頁面是這樣呈現出來的:

→ 來到home這個路由

?
1
2
3
4
5
6
.state( 'content.home' ,{
url: 'home' ,
views:{
"body@content" :{templateUrl: 'partials/home.html' }
}
})

以上,告訴咱們partials/home.html將會被加載到與"body@content"匹配的ui-view中。暫時對應的ui-view尚未出現,因而等待。

→ 路由看到index.html上的<div ui-view></div>

?
1
2
3
4
5
6
7
.state( 'content' ,{
url: '/' ,
views:{
"" :{templateUrl: 'partials/content.html' },
"header@content" :{templateUrl: 'partials/header.html' },
}
})

因而,就找到了content這個state下views下的 "":{templateUrl: 'partials/content.html'}這個鍵值對,把partials/content.html顯示出來。

→ 分別加載partials/content.html頁面上的各個部分

看到<div ui-view="header"></div>,就加載以下:

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

看到<div ui-view="body"></div>,先加載 "body@content":{templateUrl: 'partials/home.html'}

→ 點擊header上的連接

點擊<a ui-sref="content.photos">Photos</a>,來到:

?
1
2
3
4
5
6
.state( 'content.photos' ,{
url: 'photos' ,
views:{
"body@content" :{templateUrl: 'partials/photos.html' }
}
})

把partials/photos.html顯示到<div ui-view="body"></div>中去。

點擊<div ui-view="body"></div>,來到:

?
1
2
3
4
5
6
.state( 'content.about' ,{
url: 'about' ,
views:{
"body@content" :{templateUrl: 'partials/about.html' }
}
})

把partials/about.html顯示到<div ui-view="body"></div>中去。

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

<div ui-view></div>

如何到達這個子頁面呢?修改header中的相關部分以下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<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>

以上,經過<a ui-sref="content.photos.list">Photos</a>來到photos.html的子頁面photos-list.html.

photos-list.html 經過2種途徑到相鄰頁photo-detail.html

?
1
2
3
4
5
<h1>photos-list</h1>
<ul>
<li><a ui-sref= "^.detail" >我經過相對路徑到相鄰的state</a></li>
<li><a ui-sref= "content.photos.detail" >我經過絕對路徑到相鄰的state</a></li>
</ul>

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

?
1
2
3
<h1>photo-details</h1>
<a class= "btn btn-default" ui-sref= ".comment" >經過相對路徑去子state</a>
<div ui-view></div>

photos-detail-comment.html 則很簡單:

<h1>photos-detail-comment</h1>

app.js state多級嵌套的設置爲

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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' }
}
})
})

 抽象state

若是一個state,沒有經過連接找到它,那就能夠把這個state設置爲abstract:true,咱們把以上的content和content.photos這2個state設置爲抽象。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.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' }
}
})

那麼,當一個state設置爲抽象,若是經過ui-sref或路由導航到該state會出現什麼結果呢?

--會導航到默認路由上

$urlRouterProvider.otherwise('home');


?
1
2
3
4
5
6
.state( 'content.home' ,{
url: 'home' ,
views:{
"body@content" :{templateUrl: 'partials/home.html' }
}
})

最終把partials/home.html顯示出來。

使用控制器

在實際項目中,數據大多從controller中來。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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' }
}
})
})

添加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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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){
}]);

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

photos-list.html

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<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>

state間如何傳路由參數

在content.photos.detail這個state設置接收一個路由參數。

?
1
2
3
4
5
6
.state( 'content.photos.detail' ,{
url: '/detail/:id' ,
templateUrl: 'partials/photos-detail.html' ,
controller: 'PhotoDetailController' ,
controllerAs: 'ctrPhotoDetail'
})

photos-list.html 送出一個路由參數

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<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>

以上,經過<a ui-sref="content.photos.detail({id:photo.id})">把路由參數送出。

controller.js PhotoDetailController控制器經過$stateParams獲取路由參數

?
1
2
3
4
5
6
7
8
9
10
11
12
...
//別名: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];
}
}
]);

photos-detail.html 從以上的PhotoDetailController中獲取數據。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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>

state間如何傳字符串參數

在路由中這樣設置:

?
1
2
3
4
5
6
.state( 'content.photos.detail.comment' ,{
url: '/comment?skip&limit' ,
templateUrl: 'partials/photos-detail-comment.html' ,
controller: 'PhotoCommentController' ,
controllerAs: 'ctrPhotoComment'
})

controllers.js 中修改以下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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);
}
}
]);

也就是,$stateParams不只能夠接收路由參數,還能夠接收查詢字符串參數。

photo-detail.html 須要把查詢字符串參數傳遞出去

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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>

以上,經過ui-sref=".comment({skip:0, limit:2})把查詢字符串傳遞出去。

photos-detail-comment.html

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<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>

state間如何傳遞對象

經過data屬性,把一個對象賦值給它。

?
1
2
3
4
5
6
7
8
9
10
11
12
.state( 'content' ,{
url: '/' ,
abstract: true ,
data:{
user: "user" ,
password: "1234"
},
views:{
"" :{templateUrl: 'partials/content.html' },
"header@content" :{templateUrl: 'partials/header.html' },
}
})

給header.html加上一個對應的控制器,並提供註銷方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$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 ;
}
}
}
}
})

添加一個有關登陸頁的state

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
.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;
}
}
}
}
}
})

添加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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<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>

header.html 修改以下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<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>

onEnter和onExit事件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
.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));
}
})

在PhotoDetailController中:

?
1
2
3
4
5
6
7
8
9
10
11
12
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));
}
}
]);

photos-detail.html

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<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>

StateChangeStart事件

controller.js 增長以下

?
1
2
3
4
5
6
7
8
9
10
11
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' );
}
});
}
]);

修改content這個state:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.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 ;
}
}
}
}
})

content.photos.detail這個state

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
.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));
}
})

以上,添加了

?
1
2
3
data:{
required: true
}

同理,content.photos.detail.comment這個state

?
1
2
3
4
5
6
7
8
9
.state( 'content.photos.detail.comment' ,{
url: '/comment?skip&limit' ,
templateUrl: 'partials/photos-detail-comment.html' ,
controller: 'PhotoCommentController' ,
controllerAs: 'ctrPhotoComment' ,
data:{
required: true
}
})

StateNotFound事件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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' );
});
}
]);

添加一個state:

?
1
2
3
4
5
6
.state( 'content.notfound' ,{
url: 'notfound' ,
views: {
"body@content" : {templateUrl: 'partials/page-not-found.html' }
}
})

page-not-found.html

?
1
2
3
<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>

StateChangeSuccess事件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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()
});
});
}
]);

添加一個state

?
1
2
3
4
5
6
7
8
9
.state( 'content.log' ,{
url: 'log' ,
data:{
required: true
},
views: {
"body@content" : {templateUrl: 'partials/log.html' }
}
})

log.html

?
1
2
3
4
5
6
7
8
<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 ? log.user.name: 'anonymous' }} in {{log.date | date: 'longDate' }} at {{log.date | date: 'shortTime' }}
<p>From: {{log.from}} => to: {{log.to}}</p>
</div>
</div>

StateChangeError事件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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});
});
}
]);

添加2個state:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.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
}
}
}
}
})

error.html

?

1
2
3
<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>
相關文章
相關標籤/搜索