今更だけど、いろんな Javascript library で data-binding してみた

最近（でもないけど）、javascript 界隈の動きに全然ついていけてないので、
今更だけど、ちょっと気になっていたライブラリを触ってみた。

試してみたのは以下の５つのライブラリでのデータバインディング。

* [Knockout](#knockout)
* [AngularJS](#angularjs)
* [Vue.js](#vuejs)
* [Angular2](#angular2)
* [React](#react)

今回は、各種 Form 部品への簡単なバインディングのみのサンプルを作りました。

* \<input type="text">
* \<textarea>
* \<input type="password">
* \<input type="checkbox">
* \<select>
* \<select multiple>
* \<input type="radio">

![sample_form.png](https://qiita-image-store.s3.amazonaws.com/0/134613/7d219233-b0f8-1fa4-ec5a-310894f63f8d.png)


# Knockout
<img width="100px" alt="Vue.js" src="https://qiita-image-store.s3.amazonaws.com/0/134613/2779e651-8a6b-ba28-72fd-3ca49fab55de.png">
Microsoft の Steave Sanderson が開発＆メンテナンスしているオープンソースプロジェクト。
Microsoft 製品ではないけど、Visual Studio 2012 のプロジェクトテンプレートに組み込まれた。
Intellisense も効くみたい。
http://knockoutjs.com/


```html:HTML
<input type="text" data-bind="value: stringValue" />
<textarea data-bind="value: stringValue"></textarea>
<input type="password" data-bind="value: passwordValue" />
<input type="checkbox" data-bind="checked: booleanValue" />
<select data-bind="options: optionValues, value: selectedOptionValue"></select>
<select multiple="multiple" data-bind="options: optionValues, selectedOptions: multipleSelectedOptionValues"></select>
<label><input type="radio" value="Alpha" data-bind="checked: radioSelectedOptionValue" />Alpha</label>
```

```js:Javascript
var viewModel = {
    stringValue : ko.observable("こんにちわ"),
    passwordValue : ko.observable("hogehoge"),
    booleanValue : ko.observable(true),
    optionValues : ["Alpha", "Beta", "Gamma"],
    selectedOptionValue : ko.observable("Gamma"),
    multipleSelectedOptionValues : ko.observable(["Alpha", "Gamma"]),
    radioSelectedOptionValue : ko.observable("Beta")
};
ko.applyBindings(viewModel);
```

HTMLでは **data-bind 属性** を使用してバインディングする。
\<select> では **options バインディング** で \<option> も生成してくれる。
ViewModel では、ちょっと面倒だけど ko.observable オブジェクトを使う。
こうすることで、値の変化を検知して View が自動的に変更されるようになる。

knockout を作動させるには以下を実行する。

```js:Javascript
ko.applyBindings(viewModel);
```

ただ、上記の \<input type="text"> ではフォーカスが外れた時にしか値が変更されなかった。
**value バインディング** に **valueUpdate** パラメータを付けると change イベントの他に変更を検知するイベントを追加できた。

```html:HTML
<input data-bind='value: stringValue, valueUpdate: "afterkeydown"' />
```

サンプル：https://jsfiddle.net/hira3/bzprrng2/


# AngularJS
<img width="100px" alt="AngularJS" src="https://qiita-image-store.s3.amazonaws.com/0/134613/5d284ace-d4c8-8975-c7d5-3ca388394199.png">
Googleと個人や企業のコミュニティによって開発されている、完全にJavaScriptで書かれたオープンソースのフロントエンドWebアプリケーションフレームワーク。
https://angularjs.org/

```html:HTML
<input ng-model="formCtrl.stringValue" />
<textarea ng-model="formCtrl.stringValue"></textarea>
<input type="password" ng-model="formCtrl.passwordValue" />
<input type="checkbox" ng-model="formCtrl.booleanValue" />
<select ng-model="formCtrl.selectedOptionValue" ng-options="option for option in formCtrl.optionValues"></select>
<select multiple="multiple" ng-model="formCtrl.multipleSelectedOptionValues" ng-options="option for option in formCtrl.optionValues"></select>
<label><input type="radio" value="Alpha" ng-model="formCtrl.radioSelectedOptionValue" />Alpha</label>
```

```js:Javascript
angular.module('myApp', [])
  .controller('FormComtroller', function () {
    this.stringValue = 'こんにちわ';
    this.passwordValue = "hogehoge";
    this.booleanValue = true;
    this.optionValues = ["Alpha", "Beta", "Gamma"];
    this.selectedOptionValue = "Gamma";
    this.multipleSelectedOptionValues = ["Alpha", "Gamma"];
    this.radioSelectedOptionValue = "Beta";
});
```

HTMLでは **ng-model 属性** を使用してバインディングする。
\<select> では **ng-options 属性** で \<option> も生成してくれる。
基本的に、AngularJS は **ng-app 属性** をトリガーに自動で起動する。

サンプル：https://jsfiddle.net/hira3/f55dp8r5/

# Vue.js
<img width="100px" alt="Vue.js" src="https://qiita-image-store.s3.amazonaws.com/0/134613/f48839e7-2158-65ed-17c4-983964dd3900.png">
インタラクティブな Web インタフェースを構築するためのライブラリ。
本格的はフレームワークではなく、できる限りシンプルな API でリアクティブデータバインディングと構成可能な View コンポーネントを提供することがゴールだと言っている。
LINEのフロントエンドエンジニアのチームがWeb開発において注目・活用している。
http://vuejs.org/guide/
http://jp.vuejs.org/guide/


```html:HTML
<input v-model="stringValue" />
<textarea v-model="stringValue"></textarea>
<input type="password" v-model="passwordValue" />
<input type="checkbox" v-model="booleanValue" />
<select v-model="selectedOptionValue">
    <option v-for="option in optionValues">{{ option }}</option>
</select>
<select multiple="multiple" v-model="multipleSelectedOptionValues">
    <option v-for="option in optionValues">{{ option }}</option>
</select>
<label><input type="radio" value="Alpha" v-model="radioSelectedOptionValue" />Alpha</label>
```

```js:Javascript
var demo = new Vue({
    el: '#inputForm',
    data: {
        stringValue: 'こんにちわ',
        passwordValue: 'hogehoge',
        booleanValue : true,
    	  optionValues : ["Alpha", "Beta", "Gamma"],
        selectedOptionValue : "Gamma",
        multipleSelectedOptionValues : ["Alpha", "Gamma"],
        radioSelectedOptionValue : "Beta"
    },
});
```

HTMLでは **v-model 属性** を使用してバインディングする。
\<option> は **v-for** 属性で繰り返し生成する。
Vue インスタンスを作成することによって自動起動する。

```js:javascript
var vm = new Vue({
  // オプション
})
```

サンプル：https://jsfiddle.net/hira3/nwcaad98/

# Angular2
<img width="100px" alt="Angular2" src="https://qiita-image-store.s3.amazonaws.com/0/134613/3e0be7b9-c402-fb40-b886-b6212687d91f.png">
Googleが開発をリードするWebアプリ開発フレームワーク。
AngularJSの後継。
Version2からはJSに限定しないフレームワークとなったためAngularという名称になった。
TypeScriptでの開発が推奨されているみたい。
コンポーネント志向？
https://angular.io/

```html:HTML
<myApp></myApp>
```

```js:Javascript
var MyApp = ng
.Component({
    selector: 'myApp',
    directives: [ng.CORE_DIRECTIVES, ng.FORM_DIRECTIVES],
    template: [
        `<table>
            <tr>
                <td class="label">テキスト値 (タイプ時に更新):</td>
                <td><input [(ng-model)]="stringValue" /></td>
            </tr>
            <tr>
                <td class="label">テキスト値 (複数行):</td>
                <td><textarea [(ng-model)]="stringValue"> </textarea></td>
            </tr>
            <tr>
                <td class="label">パスワード:</td>
                <td><input type="password" [(ng-model)]="passwordValue" /></td>
            </tr>
            <tr>
                <td class="label">チェックボックス:</td>
                <td><input type="checkbox" [(ng-model)]="booleanValue" /></td>
            </tr>
            <tr>
                <td class="label">ドロップダウンリスト:</td>
                <td>
                    <select [(ng-model)]="selectedOptionValue">
                        <option *ng-for="#option of optionValues">{{option}}</option>
                    </select>
                </td>
            </tr>
            <tr>
                <td class="label">複数選択リスト:</td>
                <td>
                    <select multiple="multiple"
                          (change)="onSelectChange($event.target.selectedOptions)">
                        <option *ng-for="#option of optionValues" [selected]="isSelected(option)">{{option}}</option>
                    </select>
               	</td>
            </tr>
            <tr>
                <td class="label">ラジオボタン:</td>
                <td>
                    <label><input type="radio" name="radio" value="Alpha"
                    	[checked]="radioSelectedOptionValue=='Alpha'" (change)="radioSelectedOptionValue=$event.target.value" />Alpha</label>
                    <label><input type="radio" name="radio" value="Beta"
                    	[checked]="radioSelectedOptionValue=='Beta'" (change)="radioSelectedOptionValue=$event.target.value" />Beta</label>
                    <label><input type="radio" name="radio" value="Gamma"
                    	[checked]="radioSelectedOptionValue=='Gamma'" (change)="radioSelectedOptionValue=$event.target.value" />Gamma</label>
                </td>
            </tr>
        </table>`
    ]
})
.Class({
    constructor: function () {
        this.stringValue = 'こんにちわ';
        this.passwordValue  = 'hogehoge';
        this.booleanValue = true;
        this.optionValues = ['Alpha', 'Beta', 'Gamma'];
        this.selectedOptionValue = 'Gamma';
        this.multipleSelectedOptionValues = ['Alpha', 'Gamma'];
        this.radioSelectedOptionValue = 'Beta';
    },
    onSelectChange: function (options) {
	  	var selectedValue = [].slice.call(options).map(o => {return o.text;});
      this.multipleSelectedOptionValues = selectedValue;
    },
    isSelected(value) {
      return this.multipleSelectedOptionValues.indexOf(value) >= 0 || null;
    }
});

document.addEventListener('DOMContentLoaded', function () {
	ng.bootstrap(MyApp);
});

```

あれ？　AngularJS とは別物か？
考え方が全然違うのかな？？？
まだ全然理解できてないけど、無理やり動くものを作ってみた。
勉強しないとマズイ！！

サンプル：https://jsfiddle.net/hira3/jm4yc7pr/

# React
<img width="100px" alt="React" src="https://qiita-image-store.s3.amazonaws.com/0/134613/f5172cc4-6e66-2edd-2958-1ba6aa3be8a8.png">
ReactはFacebookが作っているUIを構築するためのライブラリ。
要はMVCフレームワークでいうところのViewの部分をComponentとして作っていくためのライブラリ。
https://facebook.github.io/react/index.html

```html:HTML
<div id="container"></div>
```

```js:Javascript
var InputText = React.createClass({
  handleValueChange: function(e) {
    this.props.onChange(e.target.value);
  },
  render: function() {
    return (
          <tr>
            <td className="label">テキスト値 (タイプ時に更新):</td>
            <td>
            	<input value={this.props.value}
            	      onChange={this.handleValueChange} />
            </td>
          </tr>
    );
  }
});

var InputTextArea = React.createClass({
  handleValueChange: function(e) {
    this.props.onChange(e.target.value);
  },
  render: function() {
    return (
          <tr>
            <td className="label">テキスト値 (複数行):</td>
            <td>
                <textarea value={this.props.value}
                      onChange={this.handleValueChange}></textarea>
            </td>
          </tr>
    );
  }
});

var InputPassword = React.createClass({
  handleValueChange: function(e) {
    this.props.onChange(e.target.value);
  },
  render: function() {
    return (
          <tr>
            <td className="label">パスワード:</td>
            <td>
                <input type="password" value={this.props.value}
                      onChange={this.handleValueChange} />
            </td>
          </tr>
    );
  }
});

var Checkbox = React.createClass({
  handleChange: function(e) {
    this.props.onChange();
  },
  render: function() {
    return (
          <tr>
            <td className="label">チェックボックス:</td>
            <td>
                <input type="checkbox" checked={this.props.value}
                      onChange={this.handleChange} />
            </td>
          </tr>
    );
  }
});

var Dropdown = React.createClass({
  handleValueChange: function(e) {
    this.props.onChange(e.target.value);
  },
  render: function() {
    return (
          <tr>
            <td className="label">ドロップダウンリスト:</td>
            <td>
              <select value={this.props.value}
              		onChange={this.handleValueChange}>
              {
                this.props.options.map(function (item) {
                  return <option>{item.text}</option>;
                })
              }
              </select>
            </td>
          </tr>
    );
  }
});

var ListBox = React.createClass({
  handleValueChange: function(e) {
    var selectedValue = [].slice.call(e.target.selectedOptions).map(o => {return o.text;});
    this.props.onChange(selectedValue);
  },
  render: function() {
    return (
          <tr>
            <td className="label">複数選択リスト:</td>
            <td>
              <select multiple={true} value={this.props.value}
              		onChange={this.handleValueChange}>
              {
                this.props.options.map(function (item) {
                  return <option>{item.text}</option>;
                })
              }
              </select>
            </td>
          </tr>
    );
  }
});

var RadioButton = React.createClass({
  handleChange: function(e) {
    this.props.onChange(e.target.value);
  },
  render: function() {
    return (
          <tr>
            <td className="label">ラジオボタン:</td>
            <td>
	            <label><input type="radio" value="Alpha"
              		checked={this.props.value === "Alpha"}
                  onChange={this.handleChange} />Alpha</label>
	            <label><input type="radio" value="Beta"
              		checked={this.props.value === "Beta"}
                  onChange={this.handleChange} />Beta</label>
	            <label><input type="radio" value="Gamma"
              		checked={this.props.value === "Gamma"}
                  onChange={this.handleChange} />Gamma</label>
            </td>
          </tr>
    );
  }
});

var MyApp = React.createClass({
  getInitialState: function(){
      return {
          stringValue: 'こんにちわ',
          passwordValue: 'hogehoge',
          booleanValue : true,
          optionValues : [{text:"Alpha"}, {text:"Beta"}, {text:"Gamma"}],
          selectedOptionValue : "Gamma",
          multipleSelectedOptionValues : ["Alpha", "Gamma"],
          radioSelectedOptionValue : "Beta"
      }
  },
  handleInputTextChange: function(text) {
  	this.setState({stringValue: text});
  },
  handleInputPasswordChange: function(text) {
  	this.setState({passwordValue: text});
  },
  handleCheckboxChange: function() {
  	this.setState({booleanValue: !this.state.booleanValue});
  },
  handleDropdownChange: function(value) {
  	this.setState({selectedOptionValue: value});
  },
  handleListBoxChange: function(values) {
    this.setState({multipleSelectedOptionValues: values});
  },
  handleRadioButtonChange: function(value) {
  	this.setState({radioSelectedOptionValue: value});
  },
  render: function() {
    return (
      <div>
        <h3>Form 部品</h3>
        <table>
        	<InputText value={this.state.stringValue}
          				onChange={this.handleInputTextChange}/>
        	<InputTextArea value={this.state.stringValue}
          				onChange={this.handleInputTextChange}/>
        	<InputPassword value={this.state.passwordValue}
          				onChange={this.handleInputPasswordChange}/>
        	<Checkbox value={this.state.booleanValue}
          				onChange={this.handleCheckboxChange}/>
        	<Dropdown value={this.state.selectedOptionValue}
          				options={this.state.optionValues}
          				onChange={this.handleDropdownChange}/>
        	<ListBox value={this.state.multipleSelectedOptionValues}
          				options={this.state.optionValues}
          				onChange={this.handleListBoxChange}/>
        	<RadioButton value={this.state.radioSelectedOptionValue}
          				onChange={this.handleRadioButtonChange}/>
        </table>
      </div>
    );
  }
});

ReactDOM.render(
  <MyApp />,
  document.getElementById('container')
);
```

React も流行っているみたいだからやってみたけど、全然わからない。orz.
とりあえず、こっちも無理やり動くものを作ってみた。
もっと勉強しないとマズイ！！！！

サンプル：https://jsfiddle.net/hira3/6qnazs9n/

これって何が良いのか全然わからなかった。
以下を見てみたら少しわかった気がする (^^;
[Reactがなぜ素晴らしいのか by Yuichiro MASUI](https://speakerdeck.com/masuidrive/reactganazesu-qing-rasiifalseka)
[ReactとFluxのこと by geta6](https://speakerdeck.com/geta6/reacttofluxfalsekoto)

# まとめ
Javascript 界隈はどんどん新しいものが出てくるね。
ちょっと勉強しないでいると、あっと言う間に付いていけなくなる。
このままだと、何も自分で判断・選択できなくなっちゃう。
もっと勉強しなきゃ！