onEnter & onExit property

onEnter เป็น property ของ state จะถูกเรียกใช้เมื่อก่อนที่จะเริ่มต้น state นั้นๆ สามารถนำไปใช้กับการตรวจสอบ permission ได้

onExit เป็น property ของ state จะถูกเรียกใช้เมื่อก่อนที่จะออกจาก state นั้นๆ โดยส่วนมากมักจะใช้ในการยืนยันข้อมูลพวก modal dialog ต่างๆ

$stateProvider.state("stateName", {
  template: 'someHtml',
  resolve: { 'someData': 'someValue' },
  controller: function($scope, someData){
    ...
  },
  onEnter: function(someData){
    if(someData){ /*** do something ***/ }
  },
  onExit: function(someData){
    if(someData){ /*** do something ***/ }
  }
})

การทำงานของ ฟังก์ชั่นใน state จะเรียงลำดับตามนี้

State Change Events

Event ที่เกี่ยวข้องกับการเปลี่ยนแปลง state มีทั้งหมด 4 Event

  • $stateChangeStart
  • $stateNotFound
  • $stateChangeSuccess
  • $stateChangeError

โดย Event ทั้งหมดนั้นจะอยู่ภายใต้ scope ของ $rootScope

$stateChangeStart

Event นี้จะถูกใช้ เมื่อเริ่มการเปลี่ยนจาก state ปัจจุบันไปยัง state ถัดไป

โดยจะมีโครงสร้างฟังก์ชั่นดังนี้

$rootScope.$on('$stateChangeStart', 
function(event, toState, toParams, fromState, fromParams){ 
	... 
});

$stateNotFound

Event นี้จะถูกใช้ เมื่อเรียกใช้งาน state ที่ไม่มีอยู่

โดยจะมีโครงสร้างฟังก์ชั่นดังนี้

$rootScope.$on('$stateNotFound', 
function(event, unfoundState, fromState, fromParams){ 
	console.log(unfoundState.to); // unfound State 
    console.log(unfoundState.toParams); // state parameter
    console.log(unfoundState.options); // options
});

$stateChangeSuccess

Event นี้จะถูกใช้ เมื่อการเปลี่ยนจาก state ปัจจุบันไปยัง state ถัดไปเสร็จสิ้น

โดยจะมีโครงสร้างฟังก์ชั่นดังนี้

$rootScope.$on('$stateChangeSuccess', 
function(event, toState, toParams, fromState, fromParams){ 
	... 
});

$stateChangeError

Event นี้จะถูกใช้ เมื่อเกิดข้อผิดพลาดขึ้นระหว่างการเปลี่ยน state โดยส่วนมากจะเป็นข้อผิดพลาดที่ไม่สามารถโหลด resolve promise ได้

โดยจะมีโครงสร้างฟังก์ชั่นดังนี้

$rootScope.$on('$stateChangeError', 
function(event, toState, toParams, fromState, fromParams, error){ 
	... 
});

การเปลี่ยน state จะมี event เรียงลำดับตามนี้

View Load Events

Event ที่เกี่ยวข้องกับการโหลดหน้าเว็บ (view) มีทั้งหมด 2 Event

  • $viewContentLoading
  • $viewContentLoaded

โดย Event ทั้งหมดนั้นจะอยู่ภายใต้ scope ของ $rootScope

$viewContentLoading

Event นี้จะถูกใช้ เมื่อเริ่มมีการโหลดหน้าเว็บ ก่อนที่จะทำการ render DOM โดยใช้ $broadcast ในการส่ง event

$scope.$on('$viewContentLoading', 
function(event, viewConfig){ 
    // Access to all the view config properties.
    // and one special property 'targetView'
    // viewConfig.targetView 
});

$viewContentLoaded

Event นี้จะถูกใช้ หลังจากการ render DOM เสร็จสิ้น โดยใช้ $emit ในการส่ง event

$scope.$on('$viewContentLoaded', function(event){ 
	... 
});

ใน config กำหนด state ขึ้นมา 3 state

angular.module('application', ['ui.router'])
    .config(function ($stateProvider, $urlRouterProvider) {
        $stateProvider
            .state('one', {
                url: '/one',
                template: '<p>this is state one</p><p ui-view></p>'
			})
			.state('one.two', {
                url: '/two',
                template: '<p>this is state one-two</p>',
            })
			.state('three', {
                url: '/three',
                template: '<p>this is state three</p>',
            })
    });

ใน html ทำการกำหนด link ไปยัง state ต่างๆ

<div class="container">
		<ul class="nav nav-pills">
			<li><a ui-sref="one">State One</a></li>
			<li><a ui-sref="one.two">State Two</a></li>
			<li><a ui-sref="three">State Three</a></li>
		</ul>
		<div>
			<p>Next of this line is ui-view</p>
			<div ui-view></div>
		</div>
	</div>

เพิ่มฟังก์ชั่น onEnter และ onExit ให้กับแต่ละ state

.state('one', {
	url: '/one',
	template: '<p>this is state one</p><p ui-view></p>',
	onEnter: function () {
		console.log("[onEnter]State One onEnter");
	},
	onExit: function () {
		console.log("[onExit]State One onExit");
	},
	controller: function () {
		console.log("[controller]State One Controller");
	}
})
.state('one.two', {
	url: '/two',
	template: '<p>this is state one-two</p>',
	onEnter: function () {
		console.log("[onEnter] State One.Two onEnter");
	},
	onExit: function () {
		console.log("[onExit] State One.Two onExit");
	}
})
.state('three', {
	url: '/three',
	template: '<p>this is state three</p>',
	onEnter: function () {
		console.log("[onEnter] State Three onEnter");
	},
	onExit: function () {
		console.log("[onExit] State Three onExit");
	},
	controller: function () {
		console.log("[controller] State Three Controller");
	}
});

เพิ่มข้อความแสดงใน log โดยกำหนด Event ใน $rootScope

angular.module('application', ['ui.router'])
    .config(function ($stateProvider, $urlRouterProvider) { 
		... 
	})
	.run(function ($state, $rootScope) {
		// State Change Event
		$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
			console.log("[$stateChangeStart] From: ", (fromState.name) ? fromState.name: "No State", "To: ", toState.name);
		});
		$rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
			console.log("[$stateChangeSuccess] From: ", (fromState.name) ? fromState.name: "No State", "To: ", toState.name);
		});
		// View Loading Event
		$rootScope.$on('$viewContentLoading', function (event, viewConfig) { 
    		console.log("[$viewContentLoading] View Loading...");
		});
		$rootScope.$on('$viewContentLoaded', function (event) { 
    		console.log("[$viewContentLoaded] Loaded Complete");
		});
	});

สามารถดูตัวอย่างผลลัพธ์ได้ที่นี่ Demo

สังเกตได้ว่า เมื่อมีการเปลี่ยนแปลง state จะมีการทำงานของ stateChange Event และ viewLoad Event

โดยจะทำ stateChange Event ก่อน viewLoad Event