Я пытаюсь обновить несколько полей в столбце в базе данных. У меня 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 предупреждает о том, что состояния не должны изменяться напрямую от компонентов.