疑念は探究の動機であり、探究の唯一の目的は信念の確定である。

数学・論理学・哲学・語学のことを書きたいと思います。どんなことでも何かコメントいただけるとうれしいです。特に、勉学のことで間違いなどあったらご指摘いただけると幸いです。 よろしくお願いします。くりぃむのラジオを聴くこととパワポケ2と日向坂46が人生の唯一の楽しみです。

複数のv-selectを連動させる方法

概要
例えばあるカテゴリを選択すると、自動的にそのサブカテゴリが選択できるようにしたい。
Vuetifyのv-selectを2つ使ってその方法を示す。


App.vue

<template>
<v-app>
<v-select
  v-on:click="initializeSubcategories"
  v-model="categories"
  label="SELECT CATEGORY"
  item-text="name"
  :items="categoryList"
  return-object
  ></v-select>
<v-select
  v-model="subcategories"
  label="SELECT SUBCATEGORY"
  :items="categories.children"
  item-text="name"
  ></v-select>
<p>categories: {{ categories.children }}</p>
<p>subcategories: {{ subcategories }}</p>
</v-app>
</template>

<script>
export default {
  data() {
    return {
      categories: '',
      subcategories: '',
      categoryList: [
        {
          name: 'CATEGORY 1',
          code: 'cat 1',
          children: [
            {
              name: 'SUBCATEGORY 1-1',
              code: 'subcat 1-1',
            },
            {
              name: 'SUBCATEGORY 1-2',
              code: 'subcat 1-2',
            },
            {
              name: 'SUBCATEGORY 1-3',
              code: 'subcat 1-3',
            },
          ]
        },
        {
          name: 'CATEGORY 2',
          code: 'cat 2',
          children: [
            {
              name: 'SUBCATEGORY 2-1',
              code: 'subcat 2-1',
            },
            {
              name: 'SUBCATEGORY 2-2',
              code: 'subcat 2-2',
            },
            {
              name: 'SUBCATEGORY 2-3',
              code: 'subcat 2-3',
            },
            {
              name: 'SUBCATEGORY 2-4',
              code: 'subcat 2-4',
            },
          ]
        },
        {
          name: 'CATEGORY 3',
          code: 'cat 3',
          children: [
            {
              name: 'SUBCATEGORY 3-1',
              code: 'subcat 3-1',
            },
          ]
        },
      ],
    }
  },

  methods: {
    initializeSubcategories() {
      this.subcategories = '';
    },

  },
};
</script>

実行結果
f:id:yoheiwatanabe0606:20211130163452g:plain


f:id:yoheiwatanabe0606:20211130161206p:plain

  • Click the Category Select

f:id:yoheiwatanabe0606:20211130161344p:plain

  • Select a Category

f:id:yoheiwatanabe0606:20211130161724p:plain

  • Click the Subcategory Select

f:id:yoheiwatanabe0606:20211130161828p:plain

  • Select a Subcategory

f:id:yoheiwatanabe0606:20211130161918p:plain

  • Bug: if no categories are selected, then a subcategory is no data available

f:id:yoheiwatanabe0606:20211130162024p:plain

解説

カテゴリデータを次のようにします。

<script>
export default {
  data() {
    return {
      categories: '',
      subcategories: '',
      categoryList: [
        {
          name: 'CATEGORY 1',
          code: 'cat 1',
          children: [
            {
              name: 'SUBCATEGORY 1-1',
              code: 'subcat 1-1',
            },
            {
              name: 'SUBCATEGORY 1-2',
              code: 'subcat 1-2',
            },
            {
              name: 'SUBCATEGORY 1-3',
              code: 'subcat 1-3',
            },
          ]
        },
        {
          name: 'CATEGORY 2',
          code: 'cat 2',
          children: [
            {
              name: 'SUBCATEGORY 2-1',
              code: 'subcat 2-1',
            },
            {
              name: 'SUBCATEGORY 2-2',
              code: 'subcat 2-2',
            },
            {
              name: 'SUBCATEGORY 2-3',
              code: 'subcat 2-3',
            },
            {
              name: 'SUBCATEGORY 2-4',
              code: 'subcat 2-4',
            },
          ]
        },
        {
          name: 'CATEGORY 3',
          code: 'cat 3',
          children: [
            {
              name: 'SUBCATEGORY 3-1',
              code: 'subcat 3-1',
            },
          ]
        },
      ],
    }
  },

};
</script>

基本文法

v-selectの基本は次のとおりです。

<v-select
  label="SELECT CATEGORY"
  :items="categoryList"
  ></v-select>

labelは選択肢の名称を記入できます。これはオプションです。
ただし、このままだと[object, object]と表示されます。


実行結果
f:id:yoheiwatanabe0606:20211130175826p:plain

解決策

これを解決する方法は2つあります。

その1

一つ目はカテゴリデータのキーnametextに変えることです。つまり、次のようにします。

<script>
export default {
  data() {
    return {
      categoryList: [
        {
          text: 'CATEGORY 1',
          code: 'cat 1',
          children: [
            {
             .......
            },
        {
          text: 'CATEGORY 3',
          code: 'cat 3',
          children: [
           ........
          ]
        },
      ],
    }
  },

};
</script>

というのも、:itemsはデフォルトでは"categoryList"で指定したキーtextを参照するからです。

その2

しかし、前者の方法はとても不便です。もう一つはカテゴリデータは変更せずに、item-textを追加する方法です。このオプションでデフォルトの参照キーをnameに変更します。

  <v-select
  label="SELECT CATEGORY"
  item-text="name"
  :items="categoryList"
  ></v-select>


実行結果
f:id:yoheiwatanabe0606:20211130180142p:plain


セレクトの戻り値を取得する方法

次にv-selectで選択した戻り値を取得する方法を示します。
まず、戻り値を入れる変数を次のように設定します。

  <v-select
  v-model="categories"
  label="SELECT CATEGORY"
  item-text="name"
  :items="categoryList"
  ></v-select>
<p>categories: {{ categories }}</p>

....
  data() {
    return {
      categories: '',
      categoryList: [
      ......
      ]
....

v-selectのオプションにv-modelを追加して、data()categories: '',を追加します。


しかし、これだけでは戻り値を取得できません。
先ほどと同じように、:itemsはデフォルトでは"categoryList"で指定したキーvalue(もし存在すれば)を戻り値として参照します。ですので、キーをcodeからvalueに変更すれば、戻り値を取得できます。しかし、それよりもv-selectのオプションにitem-valueを追加して、戻り値の参照キーを変更したほうが簡単です。参照キーは配列でも問題ありませんので、item-value="children"としても構いません。

  <v-select
  v-model="categories"
  label="SELECT CATEGORY"
  item-text="name"
  item-value="children"
  :items="categoryList"
  ></v-select>
<p>categories: {{ categories }}</p>

実行結果
f:id:yoheiwatanabe0606:20211130184933p:plain

サブカテゴリについて

サブカテゴリについてもカテゴリと同じように実行できます。

  • data()に変数subcategoriesを追加する。
  • v-selectのオプションにitem-text="name"を追加する。
  • v-selectのオプションにitem-value="code"を追加する。
  • v-select:items="categories"を追加する。

このように修正すれば、カテゴリの選択肢からサブカテゴリの選択肢が絞られるような実装となります。

バグの修正について

カテゴリが選択されたら、それに従ってサブカテゴリも選択されるようなプログラムはこれでできます。
しかし、このままではいくつかのバグが生じてしまいます。

  1. CATEGORY 1およびSUBCATEGORY 1-1を選んだ後に、「やっぱ、カテゴリを変更する」と思って、カテゴリをCATEGORY 2変更するとカテゴリとサブカテゴリが不一致になってしまう(カテゴリはCATEGORY 2であり、サブカテゴリはSUBCATEGORY 1-1となる)。
  2. カテゴリを選ばずに、いきなりサブカテゴリを選択すると「No data available」と表示されてしまう。

一つ目のバグはsubcategoriesを初期化する(空文字にする)関数を作成して、カテゴリがクリックされるとそれが実行されるように修正すれば直ります。

<template>
<v-app>
<v-select
  v-on:click="initializeSubcategories"
  v-model="categories"
  label="SELECT CATEGORY"
  item-text="name"
  :items="categoryList"
  return-object
  ></v-select>
.....
.....
              name: 'SUBCATEGORY 3-1',
              code: 'subcat 3-1',
            },
.....
  },

  methods: {
    initializeSubcategories() {
      this.subcategories = '';
    },

  },
};
</script>


もう一つのバグはcategoriesが空文字ならば二つ目のセレクトがクリックできないように修正すれば直ると思います(未実装)。



僕から以上