Vue 0.11からselectタグとのバインディングがすっきり書けるようになります。この機能を使い、selectタグでよくあるカスケードのサンプルを書いてみました。確認したバージョンはVue 0.11-rc2です。
なお、題材として作成したサンプルはこちらのAnguler版を元にしています。Vueでも同じような感じで書けるようになっていますね。
シンプルなパターン
- optionタグの表示値とvalue属性が同じ値となっています。
- options属性に文字列の配列を渡すと自動的にoptionタグを生成してくれます。
- 子供のselectタグの初期選択値の設定は、
$watch
を使ってselectedCategory
の変更時に行われるようにしています。 - デモはこちら。
HTML
<div id="main">
<select v-model="selectedCategory" options="categories">
</select>
<select v-model="selectedItem" options="items[selectedCategory]">
</select>
{{selectedCategory}} : {{selectedItem}}
</div>
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"}
のような形式の配列を渡すことで自動的に生成してくれます。 - デモはこちら。
HTML
最初のサンプルと同じため省略。
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つの構造化データになっています。
- デモはこちら。
HTML
<div id="main">
<select v-model="selectedCategory" options="categories">
</select>
<select v-model="selectedItem" options="items">
</select>
{{selectedCategory}} : {{selectedItem}}
</div>
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;
}
}
});