【Fuse】Observableを極める

[前のチュートリアル](http://qiita.com/tkskto/items/c5b38d4f8a9d8acd58ec)にも出てきた`Observable`。Fuseをうまく使う上で、重要な概念ですので、より理解を深めるためにリファレンスを読んでみました。

###Observableとは？
まだ知らない方のために一応書いておきます。UXマークアップ側で、UIの値に`Observable`インスタンスを指定しておくと、指定した`Observable`の値に変更があったときに、自動でUIのほうにも更新を反映してくれる優れものです。昨日sirizさんが書いてくれた[【Fuse】UXマークアップをより強力に！UX Reactive Expressions](http://qiita.com/siriz/items/83c6e9d1c7ba0acf53b4)にも少し似ていますが、データバインディングなアプリケーションを手軽に実装することができます。

###Sample

簡単なサンプルを作りました。

```sample.ux
<App>
	<JavaScript>
		//Observableパッケージをインポート
		var Observable = require('FuseJS/Observable');

		//Observableインスタンスを生成
		var pos = new Observable(0);

		//Observableの値を更新する
		function move() {
			if(pos.value > 375) {
				pos.value = -50;
			}
			pos.value += 1;
		}

		function loop() {
			move();
			setTimeout(loop, 10);
		}
		
		loop();

		// ObservableインスタンスをUXマークアップ側に公開する
		module.exports = {
			posX : pos
		}
	</JavaScript>
	<ClientPanel>
		<StackPanel Alignment="Top">
		    <Rectangle Alignment="Left" Width="50" Height="50" Color="Red" Margin="0,10,0,0">
		    
		    	<!-- JSから公開されたposXを値として設定する。 -->
		    	<Transltion X="{posX}" />
		    </Rectangle>
		    <Rectangle Alignment="Right" Width="50" Height="50" Color="Blue" Margin="0,10,0,0">
		    
		    	<!-- JSから公開されたposXを受け取って-1をかけて設定する。 -->
		    	<Translation X="{posX} * -1" />
		    </Rectangle>
		</StackPanel>
	</ClientPanel>
</App>
```

![loop.gif](https://qiita-image-store.s3.amazonaws.com/0/100937/40ced5aa-4fd4-8dc8-b8f7-2c5a5c400c4f.gif)


`Observable`を更新すると、購読している全ての要素に伝えられます。

JS経由でスクリーンの幅を取得したかったのですが、[フォーラム](https://www.fusetools.com/community/forums/howto_discussions/screen_width_via_javascript?page=1&highlight=cc60df40-a133-42ec-b0d8-82d554aed7df#post-cc60df40-a133-42ec-b0d8-82d554aed7df)によると、JSで取得する方法は今のところないようです。requestAnimationFrameもないです。JavaScriptならなんでもありというわけではないみたいですね。

`Observable`は単一の値だけでなく、リストとして値を保持することもできます。

```ObservableList.js
var PPAP = Observable("P", "P", "A");
console.log(PPAP.length); // 3

PPAP.add("P"); // リストの最後に値を追加する
console.log(PPAP.length); // 4
console.log(PPAP.getAt(2)); // "A"
```

※console.logの値はFuse Monitor（[Cmd or Ctrl] + M）で確認できます。

チュートリアルでも使用しましたが、`map`や`where`のような、`reactive operators`と呼ばれるメソッドとの相性がとてもよいです。一例を示します。

```sample.js
var someNumbers = Observable(1,2,3,4);

//リストの各項目を2乗したリストを持つ新しい`Observable`インスタンスを生成します。
var someNumbersSquared = someNumbers.map(function(x){ return x * x; });

console.log(someNumbersSquared.getAt(3)) // null！！！
```

ただし、`reactive operator`の直後は値を取れないことに注意してください。リスナーが登録されていないと、変更が伝播されないためです。

リスナーを追加するには、先のサンプルで示したように、UXマークアップ側で`{hoge}`というように指定するやりかたが一般的です。しかしJS側でリスナーを登録することもできます。

###JSの中で`Observable`の変更を受け取る

JSで`Observable`の変更を受け取るには、`onValueChanged`メソッドを使います。先ほどのサンプルに追加すれば、直後でも値が取れるようになります。これのメソッドを使うことにより、変更があった際に何かしらの処理を加えることが可能になります。

```sample.js
var someNumbers = Observable(1,2,3,4);

//リストの各項目を2乗したリストを持つ新しい`Observable`インスタンスを生成します。
var someNumbersSquared = someNumbers.map(function(x){ return x * x; });
someNumbersSquared.onValueChanged(module, function(item){
	//なにかしらの処理
});

console.log(someNumbersSquared.getAt(3)); //16
```

単にリスナーを追加する、`addSubscriber(function(){ })`もあるのですが、これはリスナーを削除するときに、`removeSubscriber`を明示的に実行する必要があるので、`.onValueChanged`を推奨しています。

その他にも、`Observable`には、いろんな[API](https://www.fusetools.com/docs/fusejs/observable-api)が用意されています。次の機会にご紹介します。