AngularJS路由系列(2)--刷新、查看路由,路由事件和URL格式,獲取路由參數,路由的Resolve

 

本系列探尋AngularJS的路由機制,在WebStorm下開發。主要包括:css

 

刷新路由
查看當前路由以及全部路由
路由觸發事件
獲取路由參數html

路由的resolve屬性
路由URL格式html5

 

AngularJS路由系列包括:

一、AngularJS路由系列(1)--基本路由配置
二、AngularJS路由系列(2)--刷新、查看路由,路由事件和URL格式,獲取路由參數,路由的Resolve
三、AngularJS路由系列(3)-- UI-Router初體驗
四、AngularJS路由系列(4)-- UI-Router的$state服務、路由事件、獲取路由參數
五、AngularJS路由系列(5)-- UI-Router的路由約束、Resolve屬性、路由附加數據、路由進入退出事件
六、AngularJS路由系列(6)-- UI-Router的嵌套Statenode

 

項目文件結構

 

node_modules/jquery

public/
.....app/
..........bower_components/
...............toastr/
....................toastr.min.css
....................toastr.min.js
...............jquery/
....................dist/
.........................jquery.min.js
...............angular/
....................angular.min.js
...............angular-ui-router/
....................release/
.........................angular-ui-router.min.js
...............angular-route/
.........................angular-route.min.js
..........controllers/
...............HomeController.js
...............AllSchoolsController.js
...............AllClassroomsController.js
...............AllActivityiesController.js
...............ClassroomController.js
...............ClassroomSummaryController.js
...............ClassroomMessageController.js
..........css/
...............bootstrap.cerulean.min.css
..........filters/
...............activityMonthFilter.js
..........services/
...............dataServices.js
...............notifier.js
..........templates/
...............home.html
...............allSchools.html
...............allClassrooms.html
...............allActivities.html
...............classroom.html
...............classroomDetail.html
...............classroom_parent.html
..........app.js
.....index.html
.....favicon.ico
server/
.....data/
.....routes/
.....views/
.....helpers.js
package.json
server.js
json

 

刷新路由

 

有時候咱們須要刷新路由而不是整個頁面。該如何作呢?ngRoute這個module爲咱們準備了$route服務的reload()方法能夠實現。bootstrap

 

■ HomeController.js, 添加刷新路由功能,$route.reload數組

 

(function(){
    angular.module('app')
        .controller('HomeController',['dataService','notifier', '$route', '$log', HomeController]);
        
    function HomeController(dataService, notifier, $route, $log){
        var vm = this;
        vm.message = 'Welcome to School Buddy!';
        
        //從新刷新路由
        vm.refresh = function(){
            $route.reload();
        }
        
        dataService.getAllSchools()
            .then(function(schools){
                vm.allSchools = schools;
                vm.schollCount = schools.length;
            })
            .catch(showError);
            
            
        dataService.getAllClassrooms()
            .then(function(classroom){
                vm.allClassrooms = classrooms;
                vm.classroomCount = classrooms.length;
            })
            .catch(showError);
            
        dataService.getAllActivities()
            then(function(activities)){
                vm.allActivities = activities;
                vm.activityCount = activities.length;
            }
            ...
    }
}());

 

■ home.html, 添加刷新路由的按鈕promise


{{home.message}}
{{home.schoolCount}}
{{home.activityCount}}瀏覽器

<button ng-click="home.refresh()">刷新</button>

 

當點擊"刷新"按鈕,刷新的只是路由,不是整個頁面。

 

查看當前路由以及全部路由

 

$route服務提供了current和routes屬性。

 

■ HomeController.js, 查看當前路由以及全部路由,使用$route的current和routes屬性

 

(function(){
    angular.module('app')
        .controller('HomeController',['dataService','notifier', '$route', '$log', HomeController]);
        
    function HomeController(dataService, notifier, $route, $log){
        var vm = this;
        vm.message = 'Welcome to School Buddy!';
        
        //從新刷新路由
        vm.refresh = function(){
            $log.debug($route.current);
            $log.debut($route.routes);
            $route.reload();
        }
        
        dataService.getAllSchools()
            .then(function(schools){
                vm.allSchools = schools;
                vm.schollCount = schools.length;
            })
            .catch(showError);
            
            
        dataService.getAllClassrooms()
            .then(function(classroom){
                vm.allClassrooms = classrooms;
                vm.classroomCount = classrooms.length;
            })
            .catch(showError);
            
        dataService.getAllActivities()
            then(function(activities)){
                vm.allActivities = activities;
                vm.activityCount = activities.length;
            }
            ...
    }
}());

 

$route.current相關的以下:

 

$route.routes相關以下:

 

路由觸發事件

 

$route服務提供如下幾個事件:

● $routeChangeStart
● $routeChangesSuccess
● $routeChangeError
● $routeUpdate
使用$on來調用事件

 

這些事件是在路由發生變化、路由成功、路由異常、路由更新時被觸發。誰來作這些事件的載體呢?咱們能夠使用$on方法把這些事件註冊到$rootScope上去,這樣,在全局範圍內觸發這些事件。

 

■ app.js,爲$rootScope添加路由事件

 

(function(){
    var app = angular.module('app', ['ngRoute']);
    
    app.config(['$logProvider','$routeProvider', function($logProvider,$routeProvider){
        $logProvider.debugEnabled(true);
        
        $routeProvider
            .when('/',{
                controller: 'HomeController' ,
                controllerAs: 'home',
                templateUrl: '/app/templates/home.html'
            })
            .when('/schools',{
                controller: 'AllSchoolsController',
                controllerAs: 'schools',
                templateUrl: '/app/templates/allSchools.html',
                caseInsensitiveMatch: true
            })
            .when('/classrooms/:id',{
                controller: 'AllClassroomsController',
                controllerAs: 'classrooms',
                templateUrl: '/app/templates/allClassrooms.html',
                resolve:{
                    promise: function(){
                        throw 'error transitioning to classrooms';
                    }
                }
            })
            .when('/activities',{
                controller: 'AllActivitiesController',
                controllerAs: 'activities',
                templateUrl: '/app/templates/allActivities.html'
            })
            .otherwise('/');
    }]);
    
    app.run(['$rootScope', '$log', function($rootScope, $log){
        //經過$on爲$rootScope添加路由事件
        $rootScope.$on('$routeChangeSuccess',function(event, current, previous){
            $log.debug('successfully changed routes');
            
            $log.debug(event);
            $log.debug(current);
            $log.debug(previous);
        });
        
        $rootScope.$on('$routeChangeError', function(event, current, previous, rejection){
            $log.debug('error changing routes');
            
            $log.debug(event);
            $log.debug(current);
            $log.debug(previous);
            $log.debug(rejection);
        });
    }]);
}());

 

以上,使用resolve在controller初始化以前定義一個promise方法故意拋出一個異常。


在localhost:3000/#/下刷新瀏覽器,即觸發了$rootScope的$routeChangeSuccess事件。

 

可見,event用來存放當前觸發事件;current用來存放當前路由,previous用來存放上一個路由。

 

清空控制檯記錄,點擊導航欄上的Activities

 

previous顯示了上一個路由。

 

清空控制檯記錄,點擊導航欄上的Classroom,即咱們故意在該路由中設置了一個異常。

 

獲取路由參數

 

有時候咱們須要獲取路由中的參數,ngRoute爲咱們提供了$routeParams服務。

 

.when('/classrooms/:id',{

})

 

在控制器中大體這樣:

 

function ClassroomController($routeParams){
    var classroomID = $routeParams.id;
    //使用classroomID獲取相關Classroom
}

 

■ app.js,針對Classroom添加一個帶參數的路由

 

(function(){
    var app = angular.module('app', ['ngRoute']);
    
    app.config(['$logProvider','$routeProvider', function($logProvider,$routeProvider){
        $logProvider.debugEnabled(true);
        
        $routeProvider
            .when('/',{
                controller: 'HomeController' ,
                controllerAs: 'home',
                templateUrl: '/app/templates/home.html'
            })
            .when('/schools',{
                controller: 'AllSchoolsController',
                controllerAs: 'schools',
                templateUrl: '/app/templates/allSchools.html',
                caseInsensitiveMatch: true
            })
            .when('/classrooms/:id',{
                controller: 'AllClassroomsController',
                controllerAs: 'classrooms',
                templateUrl: '/app/templates/allClassrooms.html'
            })
            .when('/activities',{
                controller: 'AllActivitiesController',
                controllerAs: 'activities',
                templateUrl: '/app/templates/allActivities.html'
            })
            .when('/classrooms/:id',{
                templateUrl: '/app/templates/classroom.html',
                controller: 'ClassroomController',
                controllerAs: 'classroom'
            })
            .otherwise('/');
    }]);
    
    app.run(['$rootScope', '$log', function($rootScope, $log){
        //經過$on爲$rootScope添加路由事件
        $rootScope.$on('$routeChangeSuccess',function(event, current, previous){
            $log.debug('successfully changed routes');
            
            $log.debug(event);
            $log.debug(current);
            $log.debug(previous);
        });
        
        $rootScope.$on('$routeChangeError', function(event, current, previous, rejection){
            $log.debug('error changing routes');
            
            $log.debug(event);
            $log.debug(current);
            $log.debug(previous);
            $log.debug(rejection);
        });
    }]);
}());

 

■ ClassroomController.js

 

(function(){
    angular.module('app',[])
        .controller('ClassroomController', ['dataService','notifier', '$routeParams', ClassroomController]);
        
    function ClassroomController(dataService, notifier, $routeParams){
        var vm = this;
        
        dataService.getClassroom($routeParams.id)
            .then(function(classroom){
                vm.currentClassroom = classroom;
            })
            .catch(showError);
            
        function showError(message){
            notifier.error(message);
        }
    }
}());

 

在瀏覽器中輸入localhost:3000/#/classrooms/1

 

■ app.js,針對Classroom添加帶更多參數的路由

 

(function(){
    var app = angular.module('app', ['ngRoute']);
    
    app.config(['$logProvider','$routeProvider', function($logProvider,$routeProvider){
        $logProvider.debugEnabled(true);
        
        $routeProvider
            .when('/',{
                controller: 'HomeController' ,
                controllerAs: 'home',
                templateUrl: '/app/templates/home.html'
            })
            .when('/schools',{
                controller: 'AllSchoolsController',
                controllerAs: 'schools',
                templateUrl: '/app/templates/allSchools.html',
                caseInsensitiveMatch: true
            })
            .when('/classrooms/:id',{
                controller: 'AllClassroomsController',
                controllerAs: 'classrooms',
                templateUrl: '/app/templates/allClassrooms.html'
            })
            .when('/activities',{
                controller: 'AllActivitiesController',
                controllerAs: 'activities',
                templateUrl: '/app/templates/allActivities.html'
            })
            .when('/classrooms/:id',{
                templateUrl: '/app/templates/classroom.html',
                controller: 'ClassroomController',
                controllerAs: 'classroom'
            })
            .when('/classroom/:id/detail/:month?',{
                templateUrl: '/app/templates/classroomDetail.html',
                controller: 'ClassroomController',
                controllerAs: 'classroom'
            })
            .otherwise('/');
    }]);
    
    app.run(['$rootScope', '$log', function($rootScope, $log){
        //經過$on爲$rootScope添加路由事件
        $rootScope.$on('$routeChangeSuccess',function(event, current, previous){
            $log.debug('successfully changed routes');
            
            $log.debug(event);
            $log.debug(current);
            $log.debug(previous);
        });
        
        $rootScope.$on('$routeChangeError', function(event, current, previous, rejection){
            $log.debug('error changing routes');
            
            $log.debug(event);
            $log.debug(current);
            $log.debug(previous);
            $log.debug(rejection);
        });
    }]);
}());

 

■ ClassroomController.js

 

(function(){
    angular.module('app',[])
        .controller('ClassroomController', ['dataService','notifier', '$routeParams', ClassroomController]);
        
    function ClassroomController(dataService, notifier, $routeParams){
        var vm = this;
        
        vm.month = $routeParams.month;
        
        dataService.getClassroom($routeParams.id)
            .then(function(classroom){
                vm.currentClassroom = classroom;
                
                //判斷路由中是否有month這個參數
                if($routeParams.month){
                    //集合或數組是否爲空
                    if(classroom.activities.length > 0){
                        vm.timePeriod = dataService.getMonthName($routeParams.month);
                    } else {
                        vm.timePeriod = 'No activities this month';
                    }
                } else {
                    vm.timePeriod = 'All activities';
                }
                
            })
            .catch(showError);
            
        function showError(message){
            notifier.error(message);
        }
    }
}());

 

■ AllActivitiesController.js

 

(function(){
    angular.module('app')
        .controller('AllActivitiesController', ['dataService', 'notifier', '$location', AllActivitiesController]);
        
    function AllActivitiesController(dataService, notifier, $location){
        var vm = this;
        
        vm.seletedMonth = 1;
        
        
        //搜索過濾
        vm.search = function(){
            var classroom_detail_url = '/classrooms/' + vm.selectedClassroom.id + '/detail/' +vm.seletedMonth;
            $location.url(classroom_detail_url);
        };
        
        dataService.getAllClassrooms()
            .then(function(classrooms){
                vm.allClassrooms = classroom;
                vm.seletedClassroom = classrooms[0];
            })
            .catch(showError);
            
        dataService.getAllActivities()
            .then(function(activities)){
                vm.allActivities = activities;
            }
            .catch(showError);
            
        function showError(message){
            notifier.error(message);
        }
    }
}());

 

可見,使用$location.url(route)方法能夠輕鬆轉到任何路由。

 

路由的Resolve屬性

 

在配置路由的時候有一個Resolve屬性,接受一個Object對象,對象的每個屬性接收一個函數,resolve中的事件發生在controller初始化以前,最終也將被注入到controller中。

 

.when('/activities', {
    controller: 'AllActivitiesController',
    controllerAd: 'activities',
    templateUrl: '/app/tempaltes/allActivities.html',
    resolve: {
        activities: function(dataService){
            return dataService.getAllActivities();
        }
    }
})

 

以上,dataService.getAllActivities方法返回一個promise,必需要被resolved以後纔會轉到相應的視圖頁。接着,activities能夠被注入到AllActivitiesController中。

 

■ app.js, 在/activities路由下加上resolve屬性

 

(function(){
    var app = angular.module('app', ['ngRoute']);
    
    app.config(['$logProvider','$routeProvider', function($logProvider,$routeProvider){
        $logProvider.debugEnabled(true);
        
        $routeProvider
            .when('/',{
                controller: 'HomeController' ,
                controllerAs: 'home',
                templateUrl: '/app/templates/home.html'
            })
            .when('/schools',{
                controller: 'AllSchoolsController',
                controllerAs: 'schools',
                templateUrl: '/app/templates/allSchools.html',
                caseInsensitiveMatch: true
            })
            .when('/classrooms/:id',{
                controller: 'AllClassroomsController',
                controllerAs: 'classrooms',
                templateUrl: '/app/templates/allClassrooms.html'
            })
            .when('/activities',{
                controller: 'AllActivitiesController',
                controllerAs: 'activities',
                templateUrl: '/app/templates/allActivities.html',
                resolve: {
                    activities: function(dataService){
                        return dataService.getAllActivites();
                    }
                }
            })
            .when('/classrooms/:id',{
                templateUrl: '/app/templates/classroom.html',
                controller: 'ClassroomController',
                controllerAs: 'classroom'
            })
            .when('/classroom/:id/detail/:month?',{
                templateUrl: '/app/templates/classroomDetail.html',
                controller: 'ClassroomController',
                controllerAs: 'classroom'
            })
            .otherwise('/');
    }]);
    
    app.run(['$rootScope', '$log', function($rootScope, $log){
        //經過$on爲$rootScope添加路由事件
        $rootScope.$on('$routeChangeSuccess',function(event, current, previous){
            $log.debug('successfully changed routes');
            
            $log.debug(event);
            $log.debug(current);
            $log.debug(previous);
        });
        
        $rootScope.$on('$routeChangeError', function(event, current, previous, rejection){
            $log.debug('error changing routes');
            
            $log.debug(event);
            $log.debug(current);
            $log.debug(previous);
            $log.debug(rejection);
        });
    }]);
}());

 


■ AllActivitiesController.js,把路由resolve屬性中的activities注入到控制器中來

 

(function(){
    angular.module('app')
        .controller('AllActivitiesController', ['dataService', 'notifier', '$location', 'activities', AllActivitiesController]);
        
    function AllActivitiesController(dataService, notifier, $location, activities){
        var vm = this;
        
        vm.seletedMonth = 1;
        
        //這裏的activites中路由的resolve中來
        //原先的getAllActivities方法就不須要存在了
        vm.allActivities = actvities;
        
        
        //搜索過濾
        vm.search = function(){
            var classroom_detail_url = '/classrooms/' + vm.selectedClassroom.id + '/detail/' +vm.seletedMonth;
            $location.url(classroom_detail_url);
        };
        
        dataService.getAllClassrooms()
            .then(function(classrooms){
                vm.allClassrooms = classroom;
                vm.seletedClassroom = classrooms[0];
            })
            .catch(showError);
            
            
        function showError(message){
            notifier.error(message);
        }
    }
}());

 

使用resolve的好處是:當視圖頁向$scope要數據的時候,因爲在controller實例化以前已經準備好了數據,因此頁面延遲時間大大縮短。

 

路由URL格式

 

● Hashbang格式: localhost:3000/#/classrooms/1/detail/12,默認的就是這種格式
● HTML5格式:localhost:3000/classrooms/1/detail/12,須要使用$locationProvider配置,若是使用這種格式,但瀏覽器不支持HTML5的歷史API,Angular就會使用Hashbang格式。

 

■ app.js, 引用$locationProvider配置自定義url格式

 

(function(){
    var app = angular.module('app', ['ngRoute']);
    
    app.config(['$logProvider','$routeProvider', '$locationProvider', function($logProvider,$routeProvider, $locationProvider){
        $logProvider.debugEnabled(true);
        
        //使用自定義url格式
        $locationProvider.hasPrefix('!');
        
        $routeProvider
            .when('/',{
                controller: 'HomeController' ,
                controllerAs: 'home',
                templateUrl: '/app/templates/home.html'
            })
            .when('/schools',{
                controller: 'AllSchoolsController',
                controllerAs: 'schools',
                templateUrl: '/app/templates/allSchools.html',
                caseInsensitiveMatch: true
            })
            .when('/classrooms/:id',{
                controller: 'AllClassroomsController',
                controllerAs: 'classrooms',
                templateUrl: '/app/templates/allClassrooms.html'
            })
            .when('/activities',{
                controller: 'AllActivitiesController',
                controllerAs: 'activities',
                templateUrl: '/app/templates/allActivities.html',
                resolve: {
                    activities: function(dataService){
                        return dataService.getAllActivites();
                    }
                }
            })
            .when('/classrooms/:id',{
                templateUrl: '/app/templates/classroom.html',
                controller: 'ClassroomController',
                controllerAs: 'classroom'
            })
            .when('/classroom/:id/detail/:month?',{
                templateUrl: '/app/templates/classroomDetail.html',
                controller: 'ClassroomController',
                controllerAs: 'classroom'
            })
            .otherwise('/');
    }]);
    
    app.run(['$rootScope', '$log', function($rootScope, $log){
        //經過$on爲$rootScope添加路由事件
        $rootScope.$on('$routeChangeSuccess',function(event, current, previous){
            $log.debug('successfully changed routes');
            
            $log.debug(event);
            $log.debug(current);
            $log.debug(previous);
        });
        
        $rootScope.$on('$routeChangeError', function(event, current, previous, rejection){
            $log.debug('error changing routes');
            
            $log.debug(event);
            $log.debug(current);
            $log.debug(previous);
            $log.debug(rejection);
        });
    }]);
}());

 

■ index.html,爲了配合以上的自定義url格式須要作些改變

 

<a href="#!/">School Buddy</a>

<a href="#!/schools">Schools</a>
<a href="#!/classrooms">Classrooms</a>
<a href="#!/activities">Activities</a>

 

 

■ app.js, 引用$locationProvider配置HTML5的url格式

 

(function(){
    var app = angular.module('app', ['ngRoute']);
    
    app.config(['$logProvider','$routeProvider', '$locationProvider', function($logProvider,$routeProvider, $locationProvider){
        $logProvider.debugEnabled(true);
        
        //使用HTML5格式
        $locationProvider.html5Mode({
            enabled: true,
            requireBase: true, //須要配置基地址
            rewriteLinks: true //遇到舊版本的瀏覽器會使用默認的Hashbang模式
        });
        
        $routeProvider
            .when('/',{
                controller: 'HomeController' ,
                controllerAs: 'home',
                templateUrl: '/app/templates/home.html'
            })
            .when('/schools',{
                controller: 'AllSchoolsController',
                controllerAs: 'schools',
                templateUrl: '/app/templates/allSchools.html',
                caseInsensitiveMatch: true
            })
            .when('/classrooms/:id',{
                controller: 'AllClassroomsController',
                controllerAs: 'classrooms',
                templateUrl: '/app/templates/allClassrooms.html'
            })
            .when('/activities',{
                controller: 'AllActivitiesController',
                controllerAs: 'activities',
                templateUrl: '/app/templates/allActivities.html',
                resolve: {
                    activities: function(dataService){
                        return dataService.getAllActivites();
                    }
                }
            })
            .when('/classrooms/:id',{
                templateUrl: '/app/templates/classroom.html',
                controller: 'ClassroomController',
                controllerAs: 'classroom'
            })
            .when('/classroom/:id/detail/:month?',{
                templateUrl: '/app/templates/classroomDetail.html',
                controller: 'ClassroomController',
                controllerAs: 'classroom'
            })
            .otherwise('/');
    }]);
    
    app.run(['$rootScope', '$log', function($rootScope, $log){
        //經過$on爲$rootScope添加路由事件
        $rootScope.$on('$routeChangeSuccess',function(event, current, previous){
            $log.debug('successfully changed routes');
            
            $log.debug(event);
            $log.debug(current);
            $log.debug(previous);
        });
        
        $rootScope.$on('$routeChangeError', function(event, current, previous, rejection){
            $log.debug('error changing routes');
            
            $log.debug(event);
            $log.debug(current);
            $log.debug(previous);
            $log.debug(rejection);
        });
    }]);
}());

 

■ index.html,爲了配合URL的HTML5格式須要作些改變

 

<head>
    <base href="/">
</head>

<a href="/">School Buddy</a>

<a href="/schools">Schools</a>
<a href="/classrooms">Classrooms</a>
<a href="/activities">Activities</a>

 

可是url使用HTML5格式有一個很差的地方,當輸入一個不存在的url就會報一個404的錯。

 

 

未完待續~~

相關文章
相關標籤/搜索