首先给大家介绍angular-ui-router的基本用法。
如何引用依赖angular-ui-routerangular.module("app",["ui.router"]).config(function($stateProvider){$stateProvider.state(stateName, stateCofig);}) $stateProvider.state(stateName, stateConfig)stateName是string类型
stateConfig是object类型
//statConfig可以为空对象
$stateProvider.state("home",{});
//state可以有子父级
$stateProvider.state("home",{});
$stateProvider.state("home.child",{})
//state可以是链式的
$stateProvider.state("home",{}).state("about",{}).state("photos",{});
stateConfig包含的字段: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])
形参to是string类型,必须,使用"^"或"."表示相对路径;
形参toParams可空,类型是对象;
形参options可空,类型是对象,字段包括:location为bool类型默认true,inherit为bool类型默认true, relative为对象默认$state.$current,notify为bool类型默认为true, reload为bool类型默认为false
$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.comment
ui-srefui-sref="stateName"
ui-sref="stateName({param:value, param:value})"
ui-view==没有名称的ui-view
<div ui-view></div>$stateProvider.state("home",{template: "<h1>hi</h1>"}) 或者这样配置:
$stateProvider.state("home"{views: {"": {template: "<h1>hi</h1>"}}}) ==有名称的ui-view
<div ui-view="main"></div>$stateProvider.state("home",{views: {"main" : {template: "<h1>hi</h1>"}}}) ==多个ui-view
<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和viewapp.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"})}) 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>
state之间的跳转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>
以上通过ui-sref属性完成state之间的跳转。
多个view以及state嵌套有时候,一个页面上可能有多个ui-view,比如:
<div ui-view="header"></div><div ui-view="body"></div>
假设,以上页面属于一个名称为parent的state中。
我们知道在ui-router中,一个state大致是这样设置的:
<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和会根据页头上的点击呈现不同的内容
<div ui-view="header"></div><div ui-view="body"></div>
header.html 把原先indext.html中nav部分放到这里来
<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 路由现在这样设置
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这个路由
.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>
.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>,来到:
.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>,来到:
.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中的相关部分如下:
<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
<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
<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多级嵌套的设置为
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设置为抽象。
.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");
即
.state("content.home",{url: "home",views:{"body@content":{templateUrl: "partials/home.html"}}}) 最终把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"}}})})添加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";}]);//别名:ctrPhotophotoGallery.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;}}]);//别名:ctrPhotoListphotoGallery.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;}}]);//别名:ctrPhotoDetailphotoGallery.controller("PhotoDetailController",["$scope", "$state", function($scope,$state){}]); 以上,通过$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> state间如何传路由参数在content.photos.detail这个state设置接收一个路由参数。
.state("content.photos.detail",{url: "/detail/:id",templateUrl: "partials/photos-detail.html",controller: "PhotoDetailController",controllerAs: "ctrPhotoDetail"}) 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> 以上,通过<a ui-sref="content.photos.detail({id:photo.id})">把路由参数送出。
controller.js PhotoDetailController控制器通过$stateParams获取路由参数
...//别名:ctrPhotoDetailphotosGallery.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中获取数据。
<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间如何传字符串参数在路由中这样设置:
.state("content.photos.detail.comment",{url:"/comment?skip&limit",templateUrl: "partials/photos-detail-comment.html",controller: "PhotoCommentController",controllerAs: "ctrPhotoComment"}) controllers.js 中修改如下
photoGallery.controller("HomeController",["$scope", "$state", function($scope, $state){this.message = "Welcome to the Photo Gallery";}]);//别名:ctrPhotophotoGallery.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;}}]);//别名:ctrPhotoListphotoGallery.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;}}]);//别名:ctrPhotoDetailphotoGallery.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 需要把查询字符串参数传递出去
<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
<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属性,把一个对象赋值给它。
.state("content",{url: "/",abstract: true,data:{user: "user",password: "1234"},views:{"":{templateUrl: "partials/content.html"},"header@content":{templateUrl: "partials/header.html"},}}) 给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;}}}}})添加一个有关登录页的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;}}}}}}) 添加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> 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> 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));}})在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));}}]);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> 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");}});}]); 修改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;}}}}})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));}})以上,添加了
data:{required: true} 同理,content.photos.detail.comment这个state
.state("content.photos.detail.comment",{url:"/comment?skip&limit",templateUrl: "partials/photos-detail-comment.html",controller: "PhotoCommentController",controllerAs: "ctrPhotoComment",data:{required: true}}) 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");});}]); 添加一个state:
.state("content.notfound",{url:"notfound",views: {"body@content": {templateUrl: "partials/page-not-found.html"} } }) 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>
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()});});}]); 添加一个state
.state("content.log",{url:"log",data:{required: true},views: {"body@content": {templateUrl: "partials/log.html"} } }) 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 ? 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事件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:
.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
<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>