ngResource を使って未保存の情報を明確にする
ngResource は $get してオブジェクトを変更して \$save を呼んだらサーバサイドに反映とかいうことができます。
- データを $get などで取得した直後の状態、(サーバサイドで) 保存されている状態
- 取得したリソースを変更した状態、(サーバサイドで) 未保存の状態
- $save などで保存完了した状態、(サーバサイドで) 保存されている状態
とリソースの状態が変化します。
しかし、実際のアプリケーションでは、変更されたが更新されていない状態というのを表示したくなることが多々あります (変更があって未保存なら項目の色を変えるとか)。
なので、保存前の状態をどこかに保存して、保存されたらそれを更新するとかいう作業が必要になります。ただ、コントローラ側の ngResource のコールバックでいちいちこんなことしようとするとバグるので、ngResource の定義側でなんとかしたいところです。
transformResponse を使う
transformResponse は ngResource で何かしたときに呼ばれてくれるので、ここで angular.copy() で resource.saved みたいなプロパティに変更前のデータを全部つっこんでやると大変楽です。だいたい以下のようなコードです (実際はコードをまとめるけど)。
var Entry = $resource('/api/entries', { id : '@id' }, {
'query': {
method:'GET',
isArray: true,
transformResponse : function (data, headers) {
data = angular.fromJson(data);
data.saved = angular.copy(data);
return data;
}
},
'save': {
method:'POST',
transformResponse : function (data, headers) {
data = angular.fromJson(data);
data.saved = angular.copy(data);
return data;
}
}
}); // controller
$scope.entry = Entry.get({ id : 1 });
// $scope.entry.saved is original data // template
<div ng-class="{ changed: entry.body != entry.saved.body }">
<textarea ng-model="entry.body"></textarea>
</div> このように、取得したリソースを $scope に突っ込み、リソースを対象に ng-model を設定してやると、あとはいい感じになります。save などを呼ぶと変更された内容でリクエストが飛び (unsaved も送信されるのが余計ですが)、サーバ側で適切に保存されたエントリのレスポンスを返せば、transformResponse でリソースの更新がかかるので、全状態が自動でリセットされます。
関連エントリー
- AngularJS の ngResource を既存APIの仕様にあわせる AngularJS には ngResource という拡張があって、サーバに対する API 経由の CRUD 的操作を JavaScript...
- ngResource は何が便利なのか? ngResource は単にAPIのラッパーという感じではなくて、JS でサーバ側のモデルとうまく同期するように作られている。 最も簡単な例...
- AngularJS のテストでページ側のスクリプトを実行する protractor (webdriver) を使った場合、外から executeAsyncScript を使うと文字列でページ側で実行でき...
- Google Fit の REST API で体重を自動入力する (画像は過去に入力したデータを全て Google Fit へ入力しなおした様子) Fit API 全体の概念 単純にグローバルな「体重」に対...
- AngularJS で http リクエスト中画面内のボタンを disabled にする とにかく面倒だから全部の http リクエストを監視してボタンをオフにしたい。という要件 いまいちいい方法が思いうかばないけど以下のようにし...