ngResource は $get してオブジェクトを変更して \$save を呼んだらサーバサイドに反映とかいうことができます。

  1. データを $get などで取得した直後の状態、(サーバサイドで) 保存されている状態
  2. 取得したリソースを変更した状態、(サーバサイドで) 未保存の状態
  3. $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 でリソースの更新がかかるので、全状態が自動でリセットされます。

  1. トップ
  2. tech
  3. ngResource を使って未保存の情報を明確にする

WebAudio で ScriptProcessorNode とかを使ってちょっと変なことしようと思うと、波形が実際どうなっているのか見たくなったりするわけですが、うまいこと取得できなくてイライラするわけです。なのでトリガをかけて一定期間の波形を表示するのを作りました。

デバッグ用なので、UI 上には殆ど機能はなく、以下のようにコード上で設定を引数で渡す感じです。トリガはSimple, RaisingEdge, FallingEdge, DualEdge だけとりあえず実装してあります。実装すればチャンネル間の and トリガとかもできる感じの設計です。

WebAudioDebug.prove(context, merger, {
    bufferSize : 64e3,
    windowTime : 100e-3,
    highResolution : false,
    trigger : WebAudioDebug.OscilloscopeNode.Trigger.RaisingEdge({ triggerChannel: 0, width : 10, threshold : 0.5 }),
    continuous : false
});

作ってる途中でやる気が失せたので、特に highResolution: true (Retina 対応) にしたときパフォーマンスがめっちゃ劣化するけどそのままです。あと、繋げる段数が違ったノードを merge して渡すとズレたりするので、ちょっとめんどうくさい感じです。なんとかしたいけど、その前にやる気がなくなったのでそのうちやる気がでたらやるかもしれないです。

  1. トップ
  2. tech
  3. WebAudio のデバッグ用のオシロスコープ