Как использовать v-for с vuex для рендеринга форм, если мне нужен v-bind? - PullRequest
1 голос
/ 27 марта 2020

У меня есть следующий интерфейс:

enter image description here

Я постараюсь объяснить, что здесь происходит. У меня есть кнопка «Добавить сообщение». Когда я нажимаю на кнопку, у меня появляется новая форма с сообщением: заголовок, тело, изображение, язык (несколько вариантов выбора через этот плагин ). Я дважды нажал - у меня 2 сообщения. Просто.

Я не использую vue роутер. Реализация моей маршрутизации осуществляется с помощью бэкэнда. Это означает, что для каждого маршрута у меня новое состояние vuex.

Я собираюсь держать свои сообщения в vuex, но невозможно использовать v-model для этого случая. Итак, я покажу свой код.

store:

export const store = new Vuex.Store({
    state: {
        messages: [],
       // more props are here ...
    },
    mutations: {
        setMessages(state, messages) {
            state.messages = messages;
        },
   // more setters are here
    },
    getters: {
        getMessages: state => {
            return state.messages;
        },
    // more getters are here 
    },
    actions: {
        updateMessagesAction: function({commit}, value) {
            console.log(value)
        },

    }
});

Компонент сообщений:

<template>
    <div>
        <button class="btn btn-outline-info" @click.prevent="createNewMessage">
            <i class="fa fa-language"/> Add message
        </button>

        <div>
            // now it works with local state, but I need to work with vuex
            <div v-for="(message, index) in messages">
                <button class="btn btm-sm btn-danger" @click="deleteMessage(index, message)"><i class="fa fa-remove"/>
                </button>

                <b-collapse collapsed :id="`collapse-${index}`">
                    <form>
                        <div class="form-group">
                            <label class="typo__label">Languages</label>
                            <multiselect
                                    v-model="message.languages"
                                    :options="getLanguagesOptions"
                                    :multiple="true"
                                    :close-on-select="true"
                                    :clear-on-select="false"
                                    :preserve-search="true"
                                    placeholder="Languages"
                                    label="name"
                                    track-by="id"
                            >
                            </multiselect>
                        </div>

                        <div class="form-group">
                            <label for="title" class="typo__label">Title</label>

                            <input type="text" id="title" class="form-control" autocomplete="off" ???  how to bind it to vuex ???? I dont understand :(((>
                        </div>

                        <div class="form-group">
                            <label for="text" class="typo__label">Body</label>
                            <textarea class="form-control" id="text" ???  how to bind it to vuex ???? I dont understand :(((/>
                        </div>

                        <div class="form-group">
                            <div id="upload-image">
                                <div v-if="!message.imageSrc">
                                    <h2>Image</h2>
                                    <input type="file" ref="file" @change="onFileChange($event, message)">
                                </div>
                                <div v-else>
                                    <img :src="message.imageSrc"/>
                                    <button @click.prevent="removeImage($event, message)">Remove</button>
                                </div>
                            </div>
                        </div>

                        <hr class="mb-2">
                    </form>
                </b-collapse>
            </div>
        </div>
    </div>
</template>

<script>
    // imports

    export default {
        async created() {
            // set languages from servert to vuex
            let res = (await axios.post(this.urlForGettingLanguagesFromServerProp)).data;
            this.$store.commit('setLanguagesOptions', res);

        },
        name: "MessagesComponent",
        props: {
            urlForGettingLanguagesFromServerProp: String,
            uploadImageUrl: String,
            deleteImageUrl: String,
            selectedLanguagesIdsProp: {
                type: Array,
                default: () => []
            },
        },
        methods: {
            ...mapMutations(['setLanguagesSelected']),
            ...mapActions(['updateMessagesAction']),
            createNewMessage: function () {
                let message = {
                    languages: [],
                    languagesIds: [],
                    title: "",
                    text: "",
                    imageSrc: "",
                    imageDbId: 0
                };
                this.messages.push(message);
            },
            deleteMessage: function (index, message) {
                this.removeImage("", message);
                this.messages.splice(index, 1);
            },

            onFileChange: async function (e, message) {
              // this method add send image on server and save to state db image id ant path
            },
            removeImage: function (event, message) {
                // remove image from server
            }
        },
        computed: {
            ...mapGetters(['getLanguagesOptions', 'getMessages'])
        },
        watch: {
            messages: {
                deep: true,
                immediate: true,
                handler(val, oldVal) {
                    let message = JSON.parse(JSON.stringify(val));
                    this.$store.commit("setMessages", message);

                }
            }
        },
        data() {
            return {
                messages: [],
            }
        }
    }
</script>

Я вызываю этот компонент в родительском компоненте. В родительском компоненте я запускаю vuex во время операции обновления.

Как видите, этот компонент работает с локальным состоянием и синхронизирует локальное состояние с vuex. Это нормально для операции создания. Я могу отправлять сообщения в vuex, затем я могу взять его в родительском компоненте с другой информацией и отправить на сервер. Но что делать с обновлением? У меня есть данные с сервера в родительском компоненте, но локальное состояние, конечно, пусто для компонента сообщений. Как привязать все сообщения к vuex и иметь возможность изменять каждое сообщение отдельно? Я имею в виду, например, изменить заголовок первого сообщения и сразу же добавить его в vuex? Пожалуйста, помогите мне улучшить этот компонент.

...