概要
タイトルのとおりです。そんな需要があるのかないのかわかりませんが、勉強になったのでメモ代わりに。
前提、動機
以下のようなデータを初期値としてファイルから読み込みたかったのですが、データの保存も考慮するとファイル書き込みよりもWebStorage(僕の場合はLocalStorage)に保存して扱いたいと思ったのがきっかけです。
HTML5アプリ(Android/iOS)だったので、ファイル保存手段としてngResourceのPOSTメソッドを使えなかったという事もあります。
data.json
[
{
"author": "Archer",
"title": "Aces: nothing else comes close."
},{
"author": "Chopper",
"title": "Rock'n Roll is my life."
},{
"author": "Edge",
"title": "let me fly as your wingman just a little while longer..."
},{
"author": "Swordsman",
"title": "Faces of Aces"
}
]
用語
- angular-resource = ngResource = $resource: 同じことです。最初は区別しようと思っていたのですが断念。。
- ngStorage = $storage: 同じです。
解決策の概要
- 初期値ファイルの読み込みにはngResource(angular-resource)を使います。
ただし、書き込み(POST)はサーバ側の実装が必要になるので読み込み(GET)のみ使います。 - WebStorageはngStorageを用いました。$watchを使った双方向バインディングが強力です。
手段の詳細
1. angular-resourceとngStorageをインストールする。
bower install ngstorage angular-resource
- ng'S'torageではなく、sを小文字で入力してください。
-
--save
オプションをつけた方がbower.jsonに依存性を保存できるので便利ですね。
2. index.htmlでライブラリのjsファイルと自分のjsファイルをincludeします。
index.html
<!doctype html>
<html>
<head><meta charset="utf-8">
<!-- angular, angular-resource, ngStorageを読み込み -->
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-resource/angular-resource.js"></script>
<script src="bower_components/ngstorage/ngStorage.js"></script>
<!-- メインロジックを読み込み -->
<script src="app.js"></script>
</head>
<body ng-app="StrageTestApp">
<div ng-controller="MainCtrl as mc"> <!-- 以降mcでアクセス可能 -->
<ul>
<li ng-repeat="i in mc.items">
author: <input ng-model="i.author">
title: <input ng-model="i.title">
</li>
</ul>
</div>
</body>
</html>
3. Javascriptでangularのコードを記載します。以下、ポイントです。
- angular.moduleでngResourceとngStorageをinjectします。
- Local Storageを使う場合はconfigで$localStorageProviderに
prefixをつけた方がbetterです。
同サイトの他のwebアプリとデータが混在してしまうためです。
Session Storageの場合はあまり気にならないと思います。 - factoryでデータの読み込みとLocal Storageへのバインドを行います。
- ngResourceは遅延実行される点がポイントです。$promiseを使いましょう。
app.js
'use strict';
/**
* app definition
* ここでngResourceとngStorageをinjectionする
*/
angular.module('StrageTestApp', [
'ngResource',
'ngStorage'
])
.config(['$localStorageProvider',
function ($localStorageProvider) {
// prefixをつけないと他のwebアプリと混在してしまいます。
$localStorageProvider.setKeyPrefix('StrageTest');
}]);
/**
* controller
* サービスとindex.htmlとの橋渡しをする。
*/
angular.module('StrageTestApp')
.controller('MainCtrl', ['MainService', function(MainService){
// $scopeでもOKです。
this.items = MainService.all(); // $localStorageをitemsへ
}]);
/**
* service(factoryサービス)
* 1. ngResourceでdata.jsonから読み込む
* 2. 1.をlocalStorageに保存する
* - session storageを使いたい場合は$sessionStorageを。
* all: localStorageオブジェクトを返却するメソッド
*/
angular.module('StrageTestApp')
.factory('MainService', ['$resource', '$localStorage',
function($resource, $localStorage){
// $resource(ngResource)を使って読み込む
var res = $resource('data.json');
// $resourceは遅延実行なので$promiseを使ってデータを取得できるまで
// 待ってから$localStorageへ保存
var data = res.query();
data.$promise.then(function(){
$localStorage.$default(data); // localStorageの$defaultへ
});
// factoryサービスのreturn部
return{
all: function(){
return $localStorage; // $localStorageを返す
}
};
}]);
動作結果
- 一度バインドしてしまえば、angularの双方向バインドが効き、一文字単位で入力内容が
Web Storageに反映されます。非常に便利だと思います。
議論、future work
- 全てをローカルで実施したい場合は使いやすいのではないかと思います。
- ngStorageのprefixはまだ課題があるようでしたが (参考1)、今は特に問題なさそうに見えます
。どなたか情報あれば。
参考リンク
AngularJSでの非同期処理
本家:$resourceのドキュメント
GitHub:ngStorage
参考1: webStorage を便利に使う angularJS用モジュールを作った by amoO_O氏