AngularJS+spin.jsでOverlay(後編)

[前回](http://qiita.com/frost_star/items/1d22688b30bd15555c19)はspin.jsとangular-spinnerでAngularJSでぐるぐるアニメーションを出すところまでやった。
今回は、それを出しながら、背景を黒の半透明にして操作を不能にするようにする。

#サービス化する
前回ではコントローラの中でangular-spinnerを呼び出していたけど、毎回コントローラに処理を書くのはめんどいのでfactoryを使ってサービス化しちゃおう。

```js:overlay.js
angular.module('overlayModule',['ui.bootstrap','angularSpinner'])
	.factory('overlay',function($uibModal,usSpinnerService){
		return {
			show:function(){
			    /*ここに表示処理*/
			},
			hide:function(){
			   /*ここに停止処理*/
			}
		}
	}
);
```

このようにサービスを定義しておくことで、他のコントローラから使いやすくする。
また、今回の処理にはui.bootstrapのuibModalを使いますので依存モジュールとサービスを指定。
今、さらっと出しちゃいましたが、[UI Bootstrap](https://angular-ui.github.io/bootstrap/)を使ってますので、そちらもダウンロードして配置と読込を。

#表示処理
まず、普通にモーダルを呼んで、spinnerを起動するような処理を作る。

```js:overlay.js
modalInstance = $uibModal.open({
					templateUrl: '/overlay.html',
					backdrop: 'static',//クリックしても閉じないようにしたいのでstatic
				});
usSpinnerService.spin("overlay-spinner");
```

```html:overlay.html
<div>
	<span us-spinner="{radius:30, width:8, length: 16}" spinner-key="overlay-spinner"></span>
</div>
```
んで、コントローラから読んでみる

```js
angular.module("App",["angularSpinner"])
    .controller("appController",
            ["overlayModule",
                function(overlay){
                    overlay.show();
                }
            ]
    );
```

すると
![overlay2.png](https://qiita-image-store.s3.amazonaws.com/0/115996/5ad7eccd-a098-e2c8-23b7-be155c837695.png)

あるぇ？黒の半透明にはなって、クリックとかは効かなくなったけどアニメーションが出ていない。

#描画タイミングの問題
実はモーダルの処理として、呼び出し元のhtmlに表示させるhtmlの中身を読み込んでいるみたいなんだけど、非同期に動いているのか`usSpinnerService.spin("overlay-spinner");`が呼び出された後に読み込んでいるみたい。
つまり、spin処理が呼ばれたタイミングではovarlya.htmlの中身が読み込まれていないことになる。

これを解決するためにはモーダルの描画後に呼ばれるrenderedイベントを使ってspin処理を呼び出す。

```
modalInstance.rendered.then(function(){
					usSpinnerService.spin("overlay-spinner");
				});
```

こうすれば、モーダルの描画後にspin処理が動くはず。
![image](https://qiita-image-store.s3.amazonaws.com/0/115996/ef650397-3393-ab16-c2f4-b29943f89e6d.png)

おおっと、アニメーションは表示されたけど、画面上部が埋まっていたり、変な線が出ていたりする。

#レイアウト問題
どうやら、モーダルの内容表示箇所の位置が画面上部だったり、表示すべき内容がないために線みたいになっていたりするようです。
解決策としては、cssで位置を調整してやればOK。
モーダルとして埋め込まれたhtmlは`.modal-content`をクラスに持つdivの中に入るようなので、これに対してスタイルを定義してやればいい。

ただし、そうすると今度はモーダルの上にオーバーレイを出したいときに、(隠される方の)モーダルも影響を受けて表示が崩れることが考えられる。
そのため、modalのopenのオプションとして`windowClass: 'overlay'`を指定してやり、`.overlay .modal-content`に対して、スタイルを指定していくと綺麗にモーダル上のoverlayも上手くいきます。
![overlay.png](https://qiita-image-store.s3.amazonaws.com/0/115996/fdec1537-2856-6570-e42c-15a839147b84.png)

hideの方の処理はそんなに語ることもなく、spinを止めてモーダルを閉じるだけ。

#結論
最終的にはこんなコードになります。

```js:overlay.js
angular.module('overlayModule',['ui.bootstrap','angularSpinner'])
	.factory('overlay',function($uibModal,usSpinnerService){
		var modalInstance = null;
		return {
			show:function(){
				modalInstance = $uibModal.open({
					templateUrl: '/overlay.html',
					backdrop: 'static',
					windowClass: 'overlay'
				});

				//レンダリング終了後にspinner起動
				modalInstance.rendered.then(function(){
					usSpinnerService.spin("overlay-spinner");
				});
			},
			hide:function(){
				usSpinnerService.stop("overlay-spinner");
				modalInstance.close();
			}
		}
	}
);
```
```html:overlay.html
<style>
	.overlay .modal-content{
		margin-top:40%;
		background-color:transparent;
		border:none;
	}
</style>

<div>
	<span us-spinner="{radius:30, width:8, length: 16}" spinner-key="overlay-spinner"></span>
</div>
```

これで、コントローラ側から呼び出してオーバーレイができるようになるので、ajax処理中など時間がかかる処理の時に使えます。