I have a form component used for client registration and edit. When the form component is created I first check if the URL has an ID or not to determine what type of form to display. If the form has no ID ( meaning register new client ) all fields should be empty. And if the URL has an ID then I load the client info via an Axios request then store the data in Vuex and display the data in the fields for modifications.
<Form enctype="multipart/form-data" @submit="$emit('submit')">
<validation-provider
name="Compnay name"
>
<v-text-field
v-model="details.company_name"
label="Compnay name"
/>
<span class="text-sm text-red-500">{{ errors[0] }}</span>
</validation-provider>
<validation-provider
name="Compnay name"
>
<v-text-field
v-model="details.email"
label="Compnay email"
/>
<span class="text-sm text-red-500">{{ errors[0] }}</span>
</validation-provider>
<validation-provider
name="Compnay phone"
>
<v-text-field
v-model="details.phone"
label="Compnay name"
/>
<span class="text-sm text-red-500">{{ errors[0] }}</span>
</validation-provider>
...
Then I set data properties here
data: function () {
return {
details: {
type: Object,
default: () => ({})
},
In create
I did await this.$store.dispatch("clients/getClientById", { id: id})
to get the client info
The challenge I'm facing is after I get the client from computed
I couldn't find a way to add them in v-model to send them with FormData
or edit them. Can somebody guide me, please.
I attempted to do this. but I got an error saying Error: [vuex] do not mutate vuex store state outside mutation handlers.
Once I type something in the field
async getClientById(id){
await this.$store.dispatch("clients/getClientById", {
id: id})
.then(res => {
if (res.status === 200 ){
let clientData = res.data.data
this.details = clientData
this.status = clientData.status
}
})
Your "last attempt" doesn't work because of objects are Passed by Reference in JS so this.details
in the end points to the object inside Vuex state and changing data inside Vuex directly outside of a mutation (by v-model
in this case) is prohibited in strict mode (which is a good thing)
You can fix it by making the copy of the object (will work only if members are simple values, not objects as spread operator is doing only shallow copy) ie:
if (res.status === 200 ){
let clientData = { ...res.data.data }
this.details = clientData
this.status = clientData.status
}
In most Create/Edit forms you want some features:
Best way to do it imho is to make the form so that all data are first copied from Vuex into local data
of the form component and all inputs are bound to the local data. This has multiple benefits:
When user types something, only local data changes and original data in Vuex are intact. Implementing "Cancel" button is then as easy as simply closing the form (and discarding all local data).
Implementing "Save" is also easy - just check all validations are passing and then use mutation to commit
changed data into Vuex store
If the data under edit (stored in Vuex) are used in multiple places in your app, other "places" (components) doesn't "see" intermediate data which can be invalid during editing (for example you have two numbers in the store - A and B. Editing form for them and other component which displays result of A/B
. If editing form is bound to the Vuex data directly and user changes B to 0, form displays validation error but your display component still sees the 0 in the store and throws an error)
Form component code is simpler because binding to local reactive data is much easier then binding form controls directly to Vuex