[monaca]ui-router遷移時にローディング処理を入れてみた。

ui-routerで遷移する際に、ローディング（くるくる回るやつ）を入れてみました。

# ベース

onsenui, angularjs, ui-router が使える状態の最小限プロジェクト
[[monaca][onsenui][AngularJS][ui-router]onsenui/ui-router最小限プロジェクト](https://qiita.com/miz21358/items/af9e6416caa9754c43f5)

# html

```index.html
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <meta http-equiv="Content-Security-Policy" content="default-src * data: gap: https://ssl.gstatic.com; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
  <script src="components/loader.js"></script>
  <script src="script.js"></script>

  <link rel="stylesheet" href="components/loader.css">
  <link rel="stylesheet" href="css/style.css">
</head>
<body ng-app="MyApp">

	<ons-page>
		<ons-toolbar>
			<div class="center">Loading</div>
		</ons-toolbar>
		
		<div ng-controller="LoadingController">
			<ons-button ng-click="changePage('page-A')">pageA</ons-button>
			<ons-button ng-click="changePage('page-B')">pageB</ons-button>
			
			<div style="padding: 20px 10px;" ui-view></div>
			
			<my-loader></my-loader>
		</div>
		
		<script id="pageA.html" type="text/ng-template">
			<div style="background-color: #FFCCCC; padding: 10px;">pageAだよ</div>
		</script>
		<script id="pageB.html" type="text/ng-template">
			<div style="background-color: #CCCCFF; padding: 10px;">pageBだよ</div>
		</script>

	</ons-page>
	
	<ons-template id="loader.html">
		<div ng-if="$root.isLoading" class="loader-parent"><div class="loader">Loading...</div></div>
	</ons-template>
</body>	
</html>
```

# javascript

```script.js
var myApp = angular.module('MyApp', ['onsen', 'ui.router']);

// 遷移処理
myApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {

		$stateProvider
			.state('page-A', {
				url: '/pageA',
				templateUrl: 'pageA.html'
			})
			.state('page-B', {
				url: '/pageB',
				templateUrl: 'pageB.html'
			})
		
	}]);

// ボタン押下時の処理
myApp.controller('LoadingController', ['$scope', '$state', '$rootScope', '$timeout', function($scope, $state, $rootScope, $timeout) {
		$scope.changePage = function(page) {
			// ローディングフラグON
			$rootScope.isLoading = true;
			
			// 2秒待ってから遷移する
			$timeout(function() {
				$state.go(page);
			}, 2000);
		}
	}]);

// ローディングタグ
myApp.directive('myLoader', function() {
		return {
			restrict : 'E',
			replace: true,
			templateUrl: "loader.html"
		};
	});	
	
	
// 画面遷移タイミング処理
myApp.run(['$rootScope', '$transitions', '$state', function($rootScope, $transitions, $state){
	$transitions.onSuccess({to:'*'}, function(trans){
		// ページ読み込み成功
		
		// ローディングフラグOFF
		$rootScope.isLoading = false;
	});
	
}]);
```

# css

```style.css

div.loader-parent {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	margin: auto;
	height: 200px;
	width: 200px;
}
.loader {
  margin: 80px auto;
  font-size: 25px;
  width: 1em;
  height: 1em;
  border-radius: 50%;
  position: relative;
  text-indent: -9999em;
  -webkit-animation: load5 1.1s infinite ease;
  animation: load5 1.1s infinite ease;
  -webkit-transform: translateZ(0);
  -ms-transform: translateZ(0);
  transform: translateZ(0);
}
@-webkit-keyframes load5 {
  0%,
  100% {
    box-shadow: 0em -2.6em 0em 0em #7f7f7f, 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.5), -1.8em -1.8em 0 0em rgba(127,127,127, 0.7);
  }
  12.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.7), 1.8em -1.8em 0 0em #7f7f7f, 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.5);
  }
  25% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.5), 1.8em -1.8em 0 0em rgba(127,127,127, 0.7), 2.5em 0em 0 0em #7f7f7f, 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  37.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.5), 2.5em 0em 0 0em rgba(127,127,127, 0.7), 1.75em 1.75em 0 0em #7f7f7f, 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  50% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.5), 1.75em 1.75em 0 0em rgba(127,127,127, 0.7), 0em 2.5em 0 0em #7f7f7f, -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  62.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.5), 0em 2.5em 0 0em rgba(127,127,127, 0.7), -1.8em 1.8em 0 0em #7f7f7f, -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  75% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.5), -1.8em 1.8em 0 0em rgba(127,127,127, 0.7), -2.6em 0em 0 0em #7f7f7f, -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  87.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.5), -2.6em 0em 0 0em rgba(127,127,127, 0.7), -1.8em -1.8em 0 0em #7f7f7f;
  }
}
@keyframes load5 {
  0%,
  100% {
    box-shadow: 0em -2.6em 0em 0em #7f7f7f, 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.5), -1.8em -1.8em 0 0em rgba(127,127,127, 0.7);
  }
  12.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.7), 1.8em -1.8em 0 0em #7f7f7f, 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.5);
  }
  25% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.5), 1.8em -1.8em 0 0em rgba(127,127,127, 0.7), 2.5em 0em 0 0em #7f7f7f, 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  37.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.5), 2.5em 0em 0 0em rgba(127,127,127, 0.7), 1.75em 1.75em 0 0em #7f7f7f, 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  50% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.5), 1.75em 1.75em 0 0em rgba(127,127,127, 0.7), 0em 2.5em 0 0em #7f7f7f, -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  62.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.5), 0em 2.5em 0 0em rgba(127,127,127, 0.7), -1.8em 1.8em 0 0em #7f7f7f, -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  75% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.5), -1.8em 1.8em 0 0em rgba(127,127,127, 0.7), -2.6em 0em 0 0em #7f7f7f, -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  87.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.5), -2.6em 0em 0 0em rgba(127,127,127, 0.7), -1.8em -1.8em 0 0em #7f7f7f;
  }
}
```

引用元）[Single Element CSS Spinners](https://projects.lukehaas.me/css-loaders/)

# 画面イメージ

![loading12.png](https://qiita-image-store.s3.amazonaws.com/0/184714/e8c03312-72ee-e29c-dcfc-e251257dcf15.png)

# 処理の流れ

1. ボタン押下
2. ```$scope.changePage``` が実行される
    3. ```$rootScope.isLoading = true``` を設定する
    4. ```<my-loader>```内のdivタグにかかってる```ng-if="$root.isLoading"```がヒットし、divタグが表示される
    5. cssのアニメーション処理でローディングがくるくる回る
6. ```$timeout``` で2秒後に ```$state.go```(遷移処理)が実行される
7. ui-viewの読み込みが完了すると、```$transitions.onSuccess``` が実行される
    8. ```$rootScope.isLoading = false``` を設定する
    9. ローディングが非表示になる


# ソースコード

https://github.com/miz21358/ui-router-loading-sample