29773


説明が難しいのでモックを作りました  
参考URL: <https://jsfiddle.net/orangelion/L5xs401d/8/>

[code]

    // https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js
    // https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.16/vue.min.js
    
    Vue.component('test-select-children', {
      template: '#test-select-children-template',
    
      data: function() {
        return {
          filterCombinations: [{
            hogeId: 2,
            fooId: 3
          }],
          test1s: [{
            id: 1,
            name: 'a'
          }, {
            id: 2,
            name: 'b'
          }],
          test2s: [{
            id: 3,
            name: 'c'
          }, {
            id: 4,
            name: 'd'
          }],
          originTest1s: [{
            id: 1,
            name: 'a'
          }, {
            id: 2,
            name: 'b'
          }],
          originTest2s: [{
            id: 3,
            name: 'c'
          }, {
            id: 4,
            name: 'd'
          }],
          cloneElement: `
           <div class='js-selectes'>
             <label>要素1</label>
              <select class='hoge' v-on:change='changeHoge($event)'>
               <option v-for='test1 in test1s' v-bind:value='test1.id'>
                  {{ test1.name }}
                </option>
              </select>
              <label>要素2</label>
              <select class='foo' v-on:change='changeFoo($event)'>
               <option v-for='test2 in test2s' v-bind:value='test2.id'>
                  {{ test 2.name }}
                </option>
              </select>
            </div>
          `
        }
      },
    
      methods: {
        changeHoge: function(e) {
          const filterIds = this.filterIds('hoge', $(e.currentTarget));
          console.log(filterIds)
          this.test2s = this.test2s.filter(function(v) {
            return !filterIds.includes(v.id)
          });
          if (filterIds.length < 1) this.test2s = this.originTest2s;
        },
        changeFoo: function(e) {
          const filterIds = this.filterIds('foo', $(e.currentTarget));
          this.test1s = this.test1s.filter(function(v) {
            return !filterIds.includes(v.id)
          });
          if (filterIds.length < 1) this.test1s = this.originTest1s;
        },
        filterIds: function(type, $target) {
          const val = parseInt($target.find('option:selected').val());
          const otherType = type === 'hoge' ? 'foo' : 'hoge';
          return this.filterCombinations.filter(function(v) {
              return v[`${type}Id`] === val;
            })
            .map(function(v) {
              return v[`${otherType}Id`]
            });
        },
        addForm: function() {
          $('.js-selectes:last').after(this.cloneElement);
          this.$compile($('.js-selectes:last')[0]);
        },
      }
    });
    
    new Vue({
      el: 'body'
    });
[/code]

[code]

    select {
      width: 100px;
    }
    
    btn {
      width: 100px;
    }
[/code]

[code]

    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.16/vue.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
    <script id='test-select-children-template' type='text/x-template'>
      <div class='js-selectes'>
        <label>要素1</label>
        <select class='hoge' v-on:change='changeHoge($event)'>
          <option v-for='test1 in test1s' v-bind:value='test1.id'>
            {{ test1.name }}
          </option>
        </select>
        <label>要素2</label>
        <select class='foo' v-on:change='changeFoo($event)'>
          <option v-for='test2 in test2s' v-bind:value='test2.id'>
            {{ test2.name }}
          </option>
        </select>
      </div>
      <button v-on:click='addForm()'>追加</button>
    </script>
    
    <test-select-children></test-select-children>
[/code]

（ひよコードで申し訳ないですが）  
質問内容はこういう機能を作ろうとした時の良い実装方法が知りたいです(Vue.js wayに乗っとった方法)

主な機能

  * 「要素1」と「要素2」はそれぞれセットである
  * 「要素1」の何かを選択した場合にfilterCombinations（に値がある場合）の「要素2」のIDを見て、「要素2」のselect boxからoptionを削る（その逆もしかり）
  * 「追加」ボタンを押すと「要素1」と「要素2」が増える

問題  
「要素1」と「要素2」を増やした時に見ているデータ（test1sとtest2s)が同じもののため、全ての「要素1」と「要素2」が反応してしまい、独立していない  
（「追加」ボタンを押した状態で「要素1」を「b」に選択すると「要素2」が「d」に全て変わってしまう）  
なので、これに対する良い実装方法を知りたいです  
（そもそも実装方法が悪い、など）

読んでいただき、ありがとうございました。


CC BY-SA 4.0
2016-10-21T08:50:46.077
29768
2019-12-13T19:09:52.927
2019-12-13T19:09:52.927
32986
19257
question
javascript vue.js
Vue.jsでselect boxが無限に追加できる時のフィルタリング機能について


Vue.jsのようなJSフレームワークをまともに使っていこうとするならば、jQueryを使うとややこしくなりやすい気がします。

(たとえば、`v-for`で回せば要素の追加も出来ますよね。)

上記リンク先のコードを`v-for`や`v-model`を使って少し書き換えてみました。

[code]

    // https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js
    // https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.16/vue.min.js
    
    Vue.component('test-select-children', {
      template: '#test-select-children-template',
    
      data: function() {
        return {
          filterCombinations: [{
            hogeId: 2,
            fooId: 3
          }],
          originTest1s: [{
            id: 1,
            name: 'a'
          }, {
            id: 2,
            name: 'b'
          }],
          originTest2s: [{
            id: 3,
            name: 'c'
          }, {
            id: 4,
            name: 'd'
          }],
          items: [{
            test1s: [{
              id: 1,
              name: 'a'
            }, {
              id: 2,
              name: 'b'
            }],
            test2s: [{
              id: 3,
              name: 'c'
            }, {
              id: 4,
              name: 'd'
            }],
            value: 1,
    
          }],
        }
      },
    
      methods: {
        changeHoge: function(item, e) {
          const filterIds = this.filterIds('hoge', item.value);
          console.log(filterIds)
          item.test2s = item.test2s.filter(function(v) {
            return !filterIds.includes(v.id)
          });
          if (filterIds.length < 1) item.test2s = this.originTest2s;
        },
        changeFoo: function(item, e) {
          const filterIds = this.filterIds('foo', item.value2);
          this.test1s = item.test1s.filter(function(v) {
            return !filterIds.includes(v.id)
          });
          if (filterIds.length < 1) item.test1s = this.originTest1s;
        },
        filterIds: function(type, val) {
          const otherType = type === 'hoge' ? 'foo' : 'hoge';
          return this.filterCombinations.filter(function(v) {
              return v[`${type}Id`] === val;
            })
            .map(function(v) {
              return v[`${otherType}Id`]
            });
        },
        addForm: function() {
          this.items.push({
            test1s: [{
              id: 1,
              name: 'a'
            }, {
              id: 2,
              name: 'b'
            }],
            test2s: [{
              id: 3,
              name: 'c'
            }, {
              id: 4,
              name: 'd'
            }],
            value: 1,
          });
        },
      }
    });
    
    new Vue({
      el: 'body'
    });
[/code]

[code]

    select {
      width: 100px;
    }
    
    btn {
      width: 100px;
    }
[/code]

[code]

    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.16/vue.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
    <script id='test-select-children-template' type='text/x-template'>
      <div v-for="item in items">
        <label>要素1</label>
        <select class='hoge' v-on:change='changeHoge(item,$event)' v-model="item.value">
          <option v-for='test1 in item.test1s' v-bind:value='test1.id'>
            {{ test1.name }}
          </option>
        </select>
        <label>要素2</label>
        <select class='foo' v-on:change='changeFoo(item,$event)' v-bind="item.value2">
          <option v-for='test2 in item.test2s' v-bind:value='test2.id'>
            {{ test2.name }}
          </option>
        </select>
      </div>
      <button v-on:click='addForm()'>追加</button>
    </script>
    
    <test-select-children></test-select-children>
[/code]

(目的のよくわからなかった部分など少し放置している部分もあります。)  
要素1と要素2のセットごとをオブジェクトとした配列にして、独立性を保証しています。


CC BY-SA 4.0
2016-10-21T09:59:59.857
29773
2019-12-13T19:09:12.023
2019-12-13T19:09:12.023
32986
2376
29768
answer