Vue 0.11-rc2でselectタグのカスケードサンプルを書いてみた

Vue 0.11から[selectタグとのバインディングがすっきり書ける](https://github.com/yyx990803/vue/blob/next/changes.md#directive-params)ようになります。この機能を使い、selectタグでよくあるカスケードのサンプルを書いてみました。確認したバージョンは[Vue 0.11-rc2](https://github.com/yyx990803/vue/tree/0.11.0-rc2)です。

なお、題材として作成したサンプルは[こちらのAnguler版](http://jsfiddle.net/jeremylikness/8QDNv/)を元にしています。Vueでも同じような感じで書けるようになっていますね。

## シンプルなパターン
* optionタグの表示値とvalue属性が同じ値となっています。
* options属性に文字列の配列を渡すと自動的にoptionタグを生成してくれます。
* 子供のselectタグの初期選択値の設定は、`$watch`を使って`selectedCategory`の変更時に行われるようにしています。
* [デモはこちら](http://codepen.io/wadahiro/pen/ugxCc)。

### HTML
```html
<div id="main">
  <select v-model="selectedCategory" options="categories">
  </select>
  <select v-model="selectedItem" options="items[selectedCategory]">
  </select>
  {{selectedCategory}} : {{selectedItem}}
</div>
```
### JS
```js
new Vue({
  el: "#main",
  data: {
    selectedCategory: "",
    selectedItem: "",
    categories: ["shapes", "colors", "sizes"],
    items: {
      shapes: ["square", "circle", "ellipse"],
      colors: ["red", "green", "blue"],
      sizes: ["small", "medium", "large"]
    }
  },
  created: function() {
    this.$watch("selectedCategory", function() {
      this.selectedItem = this.items[this.selectedCategory][0];
    });
    this.selectedCategory = "colors";
  }
});
```

## 表示値とvalueを変えたパターン
* 今度はoptionタグの表示値とvalue属性が別になっています。
* options属性に`{text: "Square", value: "square"}`のような形式の配列を渡すことで自動的に生成してくれます。
* [デモはこちら](http://codepen.io/wadahiro/pen/ECBfA)。

### HTML
最初のサンプルと同じため省略。
### JS
```js
new Vue({
  el: "#main",
  data: {
    selectedCategory: "colors",
    selectedItem: "red",
    categories: [
      {text: "Shapes", value: "shapes"},
      {text: "Colors",  value: "colors"},
      {text: "Sizes", value: "sizes"}
    ],
    items: {
      shapes: [
        {text: "Square", value: "square"},
        {text: "Circle", value: "circle"},
        {text: "Ellipse", value: "ellipse"}
      ],
      colors: [
        {text: "Red", value: "red"},
        {text: "Green", value: "green"},
        {text: "Blue", value: "blue"}
      ],
      sizes: [
        {text: "Small", value: "small"},
        {text: "Medium", value: "medium"},
        {text: "Large", value: "large"}        
      ]
    }
  },
  created: function() {
    this.$watch("selectedCategory", function() {
      this.selectedItem = this.items[this.selectedCategory][0].value;
    });
    this.selectedCategory = "colors";
  }
});
```

## computedを使ったパターン
* 上記のサンプルは直接バインディング可能なデータ形式で保持していましたが、異なる形式で保持している場合はcomputedを使って動的に変換して対応することもできます。
* これまではcategoriesとitemsが別の配列でしたが、1つの構造化データになっています。
* [デモはこちら](http://codepen.io/wadahiro/pen/lxhFH)。

### HTML
```html
<div id="main">
  <select v-model="selectedCategory" options="categories">
  </select>
  <select v-model="selectedItem" options="items">
  </select>
  {{selectedCategory}} : {{selectedItem}}
</div>
```
### JS
```js
// dummy response data
var response = [{
    text: "Shapes",
    value: "shapes",
    items: [
      {
        text: "Square",
        value: "square"},
      {
        text: "Circle",
        value: "circle"
      },
      {
        text: "Ellipse",
        value: "ellipse"
      }
    ]
  },
  {
    text: "Colors",
    value: "colors",
    items: [
      {
        text: "Red",
        value: "red"
      },
      {
        text: "Green",
        value: "green"
      },
      {
        text: "Blue",
        value: "blue"
      }
    ]    
  },
  {
    text: "Sizes",
    value: "sizes",
    items: [
      {
        text: "Small",
        value: "small"
      },
      {
        text: "Medium",
        value: "medium"
      },
      {
        text: "Large",
        value: "large"
      }
    ]    
  }
];

new Vue({
  el: "#main",
  data: {
    selectedCategory: "",
    selectedItem: "",
    response: null
  },
  created: function() {
    var self = this;
    
    // dummy ajax
    setTimeout(function() {
      self.response = response;
      self.selectedCategory = "colors";
    }, 100);
  },
  computed: {
    categories : function() {
      return _.map(this.response, function(val) {
        return {text: val.text, value: val.value};
      });
    },
    items: function() {
      console.log("items");
      var self = this;
      var category = _.find(this.response, function(val) {
          return val.value === self.selectedCategory;
      });
      var items = _.map(category.items, function(val) {
        return {text: val.text, value: val.value};
      });
      this.selectedItem = items[0].value;
      return items;
    }
  }
});
```