AngularJs ✕ Firebaseで爆速イメージストア環境の作成



以前、[AngularJs ✕ Firebaseで爆速リアルタイムアプリケーションの作成](http://qiita.com/you_matz/items/0794129893f9eefc24fd)という記事を書きましたが、
今回は画像をさくっとどこかにあげて利用したい時、firebaseを使えば、5分で環境が出来ます。

S3、Parseの利用を検討しましたが、

-  無料
- APIドキュメントがわかりやすい（Parseはファイルストレージが20GBだが、ドキュメントがわかりにくい）
- リアルタイムにデータ同期しやすい

上記の点でAngularJs×Firebaseを採用。なんといってもリアルタイムデータ同期が魅力的。

※Milkcocoaは検討してませんw




##Firebaseとは
いわゆるモバイルBassでWebアプリケーション、モバイル・アプリケーションの開発者向けにリアルタイムにスケーラブルなバックエンドサービスを提供しています。
一定の転送量、接続数、容量は無料で、クレジットなしで使用できます。

ストレージ1GBまで無料なので、まぁ問題ないレベル。
バックアップは無料プランでは取れません。
https://www.firebase.com/


##AngularFire
そして、AngularJsからFirebaseを利用できる、
AngularFireというAPIも公開されていますので、
バックエンドのコードを書く必要も、サーバも必要なく、
必要な作業に集中できます。

AngularFireのAPIを利用することで、
Angularjsのモデルが自動的に同期され、Firebase上でリアルタイムにデータバインディングされます。
これでhtml側でのview, Angularjsでのmodel, firebaseでストアされたjsonのデータの3wayデータバインディングが可能となります。


##angular-file-upload
FlashによるFileAPI代替を提供するモジュール
HTML5のFileAPIを利用,HTML5のFileAPIサポートしていないブラウザ（IE8、IE9など）にはFlashを利用して同等の機能を提供。
今回はbase64データのURL生成してアップロードしています。


##サンプル:画像アップロードアプリ
```index.html
<script src="https://gist.github.com/manchan/0d8597b1ac131d1b1f16.js"></script>
<noscript><pre><code>

File: index.html
-------------------------



<!doctype html>
<html>
<head>
<!-- AngularJS -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.min.js"></script>
<!-- Firebase -->
<script src="https://cdn.firebase.com/js/client/2.3.0/firebase.js"></script>
<!-- AngularFire -->
<script src="https://cdn.firebase.com/libs/angularfire/1.1.3/angularfire.min.js"></script>
<!-- Angular-file-upload -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/danialfarid-angular-file-upload/10.1.0/ng-file-upload.js"></script>
<style type="text/css">
	.thumb {width: 24px;height: 24px;float: none;position: relative;top: 7px;}
	form .progress {line-height: 15px;}
	.progress {display: inline-block;width: 100px;border: 3px groove #CCC;}
	.progress div {font-size: smaller;background: orange;width: 0;}
	ol, ul{list-style:none;}
	#content #photo{position: relative;overflow: hidden;}
	#content #photo ul{position: relative;left: 50%;float: left;}
	#content #photo li{position: relative;left: -50%;float: left;}
	#content #photo .r20{margin-left:20px;}
	#content #photo li img {width: 420px;height: 420px;}
</style>
</head>
<body>
<div>
	<h1>AngularJs practice</h1>
	<body ng-app="fileUpload" ng-controller="MyCtrl">
	<form name="myForm">
		<fieldset>
			<legend>Upload on form submit</legend>
			Title:
			<input type="text" name="userName" ng-model="username" size="31" required>
			<i ng-show="myForm.userName.$error.required">*required</i>
			<br>Photo:
			<input type="file" ngf-select ng-model="picFile" name="file"
				   accept="image/*" ngf-max-size="2MB" required>
			<i ng-show="myForm.file.$error.required">*required</i><br>
			<i ng-show="myForm.file.$error.maxSize">File too large 
          {{picFile.size / 1000000|number:1}}MB: max {{picFile.$errorParam}}</i>
          			<img ng-show="myForm.file.$valid" ngf-thumbnail="picFile" class="thumb"> <button ng-click="picFile = null" ng-show="picFile">Remove</button>
			<br>
			<button ng-disabled="!myForm.$valid"
					ng-click="uploadPic(picFile)">Submit</button>
			<span ng-show="picFile.result">Upload Successful</span>
			<span class="err" ng-show="errorMsg">{{errorMsg}}</span>
		</fieldset>
		<br>
	</form>
	<div id="content">
		<h2>photo</h2>
		<div id="photo">
			<button type="button" class="btn btn-danger" ng-click="image_all_remove()">All Remove</button>
			<ul>
				<li ng-repeat="img in images | orderBy:'-submitDate'">
					<p>{{img.$key}}:{{img.submitDate}}</p>
					<img src="{{img.images}}" alt="" width="{{img.width}}" height="{{img.height}}"/>
				</li>
			</ul>
		</div>
	</div>
	</body>
	<script type="text/javascript">
	// 依存モジュールとしてfirebase、ngFileUploadを登録	
	var app = angular.module('fileUpload', ['ngFileUpload', 'firebase']);
	app.controller('MyCtrl', ['$scope','$firebase','$firebaseArray', 'Upload', '$timeout', function ($scope,$firebase, $firebaseArray, Upload, $timeout) {

		// "https://<your-firebase>.firebaseio.com/"
		var fb = new Firebase("https://<your-firebase>.firebaseio.com/");
		var ref = fb.child("images").orderByChild("submitDate");		
		var sync = $firebaseArray(ref);
		var syncArray = $firebaseArray(fb.child("images"));
		// ストアされたjson objectをmodelにバインド
		$scope.images = sync
		$scope.uploadPic = function(file) {
			var title = $scope.username;
			var submitDate = new Date().toISOString();
			var images =  Upload.base64DataUrl(file).then(function(base64Urls){

			      $timeout(function () {
			        file.result = base64Urls.data;
			      });

				// 同期配列にArray.push
				syncArray.$add({
					title:     title,
					images : base64Urls,
					submitDate: submitDate
				})
				.then(function(error) {
					if (error) {
							console.log("Error:",error);
						} else {
							console.log("Post set successfully!");
						}
					});
			});
		};
		// 画像全削除
		$scope.image_all_remove = function(){
			angular.forEach($scope.images, function(img, i){
				var row = $scope.images.$getRecord($scope.images[i].$id);
				$scope.images.$remove(row);
			});
		};
	}]);	
	</script>
</div>
</body>
</html>

</code></pre></noscript>
```
わずか110行で簡単イメージストアアプリが作成できます。
```var ref = new Firebase("https://<your-firebase>.firebaseio.com/");
```
上記の箇所をfirebaseにサインアップして、URLを書き換えるだけですぐ使えます。
サインアップはこちらから
https://www.firebase.com/login/




##※注意
無料プランでストレージは1GBまでです。


##Firebaseにストアされたデータにindexをはる方法
設定で、json形式でkey,rulesの中に.indexOnを記述するだけ
詳細はこちら
https://www.firebase.com/docs/security/guide/indexing-data.html

##Firebaseにストアされたデータのセキュリティに関して
jsonでのセキュリティルールの設定が可能。
認証されたユーザがどのようにデータを変更できるかを決める。
データの転送はSSL経由。

さらなる詳細はこちら
https://www.firebase.com/docs/security/


##AngularFireの使用アプリ
好きなアーティストの音楽をランキング順の聴くことができるサービスです。
Recentの箇所をfirebaseでストアしています。
Lamusica
http://manchan.github.io/lamusica/
githubはこちら
https://github.com/manchan/lamusica

##AngularFireのドキュメントはこちら
https://www.firebase.com/docs/web/libraries/angular/index.html

##ng-file-uploadのドキュメントはこちら
https://github.com/danialfarid/ng-file-upload

##おわりに
5分は長すぎたかもしれません。