VueJs и Vuex, как прикрепить v-модель к динамическим полям - PullRequest
0 голосов
/ 03 декабря 2018

У меня есть серия флажков, сгенерированных базой данных.Вызов базы данных обычно не завершается до загрузки страницы.

Это часть моего Vue.

folderList представляет собой список папок из базы данных, каждая из которых имеет ключ и документ.label для описания флажка и doc.hash для использования в качестве уникального ключа.

<template>
    <ul>
        <li v-if="foldersList!=null" v-for="folder in folderData">
            <Checkbox :id="folder.key" :name="folder.hash" label-position="right" v-model="searchTypeList[folder.hash]">{{ folder.doc.label }}</Checkbox>
        </li>
    </ul>
</template>
export default {
    name: 'Menu',
    components: {
        Checkbox,
        RouteButton
    },
    props: {
        foldersList: {type: Array, required: true}
    },
    computed: {
        ...mapGetters({
            searchListType: 'getSearchListType'
        }),
        searchTypeList: {
            get() {
                return this.searchTypeList;
            },
            set(newValue) {
                console.log(newValue);
                //Vuex store commit
                this.$store.commit(Am.SET_SEARCH_TYPES, newValue);
            }
        }
    },
    methods: {
            checkAllTypes: _.debounce(function (folderList){
            const initialList = {};
            folderList.forEach((folder) => {
                initialList[folder.hash] = true;
            });
            this.$store.commit(Am.SET_SEARCH_TYPES, initialList);
        }, 100)
    },
    mounted() {
        //hacky way of prefilling data after it loads
        this.$store.watch(
            (state) => {
                return this.foldersList;
            },
            this.checkAllTypes,
            {
                deep: false
            }
        );
    }

Флажок - это пользовательский компонент с флажком скользящего стиля, его v-модель похожа на эту

<template>
    <div class="checkbox">
        <label :for="id" v-if="labelPosition==='left'">
            <slot></slot>
        </label>
        <label class="switch">
            <input type="checkbox" :name="name" :id="id" :disabled="isDisabled" v-bind:checked="checked" v-on:change="$emit('change',  $event.target.checked)"/>
            <span class="slider round"></span>
        </label>
        <label :for="name" v-if="labelPosition==='right'">
            <slot></slot>
        </label>
    </div>
</template>

<script>
    export default {
        name: 'Checkbox',
        model: {
            prop: 'checked',
            event: 'change'
        },
        props: {
            id: {default: null, type: String},
            name: {required: true, type: String},
            isDisabled: {default: false, type: Boolean},
            checked: Boolean,
            labelPosition: {default: 'left', type: String},
            value: {required: false}
        }
    };
</script>

Я установил, что флажок работает с использованием простой не динамической v-моделии без цикла.

Я хочу собрать массив проверенных значений.

В моем примере выше, я пытался с этим вычисленным, чтобы попытаться связать vuex, как я сделал с другими полями, но get считается мутацией, потому что он добавляет свойства к объекту, когда он проходит по циклу.Я не знаю, как решить это

Vuex:

const state = {        
    searchListType: {}
};

const getters = {
    getSearchListType: function (state) {
        return state.searchListType;
    }
};

const mutations = {
    [Am.SET_SEARCH_TYPES]: (state, types) => {
        state.searchListType = types;
    }
};

Как правильно связать их?Мне нужны значения в vuex, чтобы несколько родственных компонентов могли использовать значения и сохранять их между изменениями страницы.

Кроме того, каков правильный способ предварительного заполнения данных?Я предполагаю, что у меня есть серьезная структурная проблема здесь.FolderList является асинхронным и может загружаться в любой момент, однако обычно он не изменяется после загрузки приложения.Он заполняется родителем, поэтому ребенку просто нужно подождать, пока он получит данные, и каждый раз, когда он меняется, по умолчанию отмечайте все.

Спасибо

1 Ответ

0 голосов
/ 04 декабря 2018

Я собирался предложить использовать событие и метод изменения вместо вычисленного get & set, но при тестировании я обнаружил, что v-модель работает нормально без какого-либо дополнительного кода.Ниже приведено приблизительное описание вашего сценария.

Возможно, что-то из взаимодействия с пользовательским компонентом вызывает вашу проблему?

Ref Настройка компонентов , использовали ли вы

model: {
  prop: 'checked',
  event: 'change'
},
props: {
  checked: Boolean
},

в компоненте Checkbox?


Vue.component('Checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})

new Vue({
  el: '#app',
  data: {
    folderData: [],
    searchTypeList: {}
  },
  created() {
    // Dynamic checkbox simulation
    setTimeout(() => {
      this.folderData = [
        { key: 1 },
        { key: 2 },
        { key: 3 },
      ]
    }, 2000)
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
<ul>
  <li v-if="folderData != null" v-for="folder in folderData">
    <Checkbox :id="folder.key" :name="folder.key" 
      v-model="searchTypeList[folder.key]"></Checkbox>
  </li>
</ul>

{{searchTypeList}}

</div>

Обработка обновлений Vuex

Я думаю, что самый простой способ обработки обновлений в магазине - это разделить v-model на :checked и @change свойства.Таким образом, ваш элемент управления не пытается выполнить прямую обратную запись в хранилище, но все же получает его значение непосредственно из хранилища и реагирует на изменения хранилища (как изменения от вызова API, так и от вызовов $store.commit() этого компонента).

Это соответствующее руководство Vuex Form Handling .

<ul>
  <li v-if="folderData != null" v-for="folder in folderData">
    <Checkbox :id="folder.key" :name="folder.key" 
      :checked="theList[folder.key]"
      @change="changeChecked(folder.key)"
      ></Checkbox>
  </li>
</ul>

...

computed: {
  ...mapGetters({
    theList: 'getSearchListType'  // Standard getter with get() only
  }),
},
methods: {
  changeChecked(key) {
    this.$store.commit('updateChecked', key)  // Handle details in the mutation
  }
}
...