Нажатие на флажок изменяет выбранное значение на значение по умолчанию в VueJs - PullRequest
0 голосов
/ 26 января 2020

enter image description here Я пытаюсь обновить несколько полей в столбце в базе данных. У меня Laravel в качестве API и Vue на передней панели. Это одностраничное приложение.

Моя форма состоит из трех полей, а именно: name - это имя элемента, cook_id - это идентификатор связанного повара и publish - это логическое значение для определения, является ли элемент опубликовано.

Это то, что у меня есть в компоненте Items:

<template>
    <div>
        <table class="table-auto w-full">
            <thead class="border bg-teal-100">
                <tr>
                    <th class="py-2" colspan="4">Recent food items</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="(item, index) in items" :key="item.id">
                    <td class="border p-2 text-center">{{ index+1 }}</td>
                    <td class="border px-4 py-2">{{ item.name }}</td>
                    <td class="border px-4 py-2">{{ item.cook.name }}</td>
                    <td class="border p-1 text-center w-2/5">
                        <button class="btn-edit" @click.prevent="showModal(item)">Edit</button>
                        <button class="btn-remove">Remove</button>
                    </td>
                </tr>
            </tbody>
        </table>

        <Modal @closeModal="closeModal" v-if="this.show">
            <EditItem @updated="closeModal"></EditItem>
        </Modal>
    </div>
</template>

<script>
import EditItem from './EditItem';
import Modal from '../components/Modal';
import { mapGetters } from 'vuex';

export default {

    components: { EditItem, Modal },

    data() {
        return {
            show: false,
        }
    },

    created() {
        this.$store.dispatch('fetchItems')
    },

    computed: {
        ...mapGetters({
            items: 'items'
        }),
    },

    methods: {
        showModal(item) {
            this.show = true
            this.$store.commit('itemSelected', item)
        },

        closeModal() {
            this.show = false
        },
    }
}
</script>

<style>

</style>

Я просто сохраняю item в магазине Vuex, по которому щелкнули, который в конечном итоге будет отображается в компоненте Modal. Вы можете игнорировать другие биты кода здесь.

Это то, что у меня есть в EditItem компоненте, который по сути является формой, содержащей существующие данные, извлеченные из хранилища через геттер:

<template>
    <div>

        <form class="w-full max-w-lg">

            <div class="flex flex-wrap -mx-3 mb-2">
                <div class="w-full px-3">
                    <label for="name"> Food Item </label>
                    <input id="name" type="text" placeholder="Item name" :value="item.name" @input="getName" />
                </div>
            </div>

            <div class="flex flex-wrap -mx-3 mb-2">
                <div class="w-full px-3">
                    <label for="cook">
                        Cook
                    </label>
                    <div class="relative">
                        <select class="" id="cook_id" :value="item.cook.id" @input="getCook">
                            <option disabled value="">Select a cook</option>
                            <option v-for="(cook, index) in cooks" :key="cook.id" :value="cook.id">{{ cook.name }}</option>
                        </select>
                        <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
                            <svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"/></svg>
                        </div>
                    </div>

                    <label class="md:w-2/3 block text-gray-500 font-bold mt-4">
                        <input class="mr-2 leading-tight" type="checkbox" :checked="item.publish" @change="getPublish($event)">
                        <span class="text-sm">
                            Publish for review
                        </span>
                    </label>
                </div>
            </div>

            <button type="submit" class="btn-primary" @click.prevent="submitData(item)">Update</button>
        </form>

    </div>
</template>

<script>
import { mapGetters } from 'vuex';

export default {

    data() {
        return {

        }
    },

    computed: {
        ...mapGetters({
            item: 'selectedItem',
            cooks: 'cooks'
        }),
    },

    methods: {
        getName(e) {
            this.$store.commit('updateName', e.target.value)
        },

        getCook(e) {
            this.$store.commit('updateCook', e.target.value)
        },

        getPublish(e) {
            this.$store.commit('updatePublish', e.target.checked)
        },

        submitData(item) {
            this.$store.dispatch('updateItem', item).then(res => {
                this.$emit('updated')
            })
        }
    }
}
</script>

<style>

</style>

Обратите внимание, что значения option на входе select получены из другой таблицы с именем cooks.

Наконец, вот что у меня есть в хранилище Vuex:

items. js

import axios from "axios";

const state = {
    items: [],
    selectedItem: {id: '', name: '', cook: {name: ''}, publish: ''}
};

const actions = {
    fetchItems: context => {
        axios.get("/api/items").then(response => {
            context.commit("itemsFetched", response.data);
        }).catch(error => {
            // eslint-disable-next-line
            console.error(error);
        });
    },

    createItem: (context, data) => {
        return new Promise((resolve, reject) => {
            axios.post('/api/items/create', {
                name: data.name,
                cook_id: data.cook_id,
                publish: data.publish
            }).then(res => {
                console.log(res.data)
                context.commit('itemCreated', res.data)
                resolve(res)
            }).catch(err => {
                console.log(err)
                reject(err)
            })
        })
    },

    updateItem: (context, item) => {
        console.log(item)
        return new Promise((resolve, reject) => {
            axios.patch('/api/items/' + item.id, {
                name: item.name,
                publish: item.publish,
                cook_id: item.cook_id
            }).then(res => {
                context.commit('itemUpdated', res.data)
                resolve(res)
            }).catch(err => {
                console.log(err)
                reject(err)
            })
        })
    },
}

const mutations = {
    itemsFetched: (state, items) => {
        state.items = items;
    },

    itemCreated: (state, item) => {
        state.items.push({
            name: item.name,
            cook_id: item.cook_id,
            publish: item.publish,
            cook: {
                name: item.cook.name
            }
        })
    },

    itemSelected: (state, item) => {
        state.selectedItem = item
    },

    updateName: (state, name) => {
        state.selectedItem.name = name
    },

    updateCook: (state, cook) => {
        console.log(cook)
        state.selectedItem.cook_id = cook
    },

    updatePublish: (state, publish) => {
        state.selectedItem.publish = publish
    },

    itemUpdated: (state, item) => {
        const index = state.items.findIndex(i => i.id == item.id)

        state.items.splice(index, 1, {
            id: item.id,
            name: item.name,
            publish: item.publish,
            cook_id: item.cook.id,
            cook: { name: item.cook.name}
        })
    },

};

const getters = {
    items: state => state.items,
    selectedItem: state => state.selectedItem
};

export default {
    state,
    getters,
    actions,
    mutations
};

Все работает отлично, за исключением того, что, когда я нажимаю на флажок, выбранное значение возвращается к значению по умолчанию во внешнем интерфейсе. Отправка формы отправляет правильные данные обратно на сервер, на внешнем интерфейсе это просто странно.

Чтобы прояснить проблему, я прикрепил файл GIF. Обратите внимание, как при установке флажка изменяется выбранное значение.

Кроме того, я не уверен на 100% в своем текущем дизайне обработки форм для обновления существующей модели в базе данных. Ваши ценные предложения по улучшению дизайна будут высоко оценены. Я не выбрал v-model, поскольку vuex предупреждает о том, что состояния не должны изменяться напрямую от компонентов.

...