I'm trying to adapt a sample datatable from the vuetify website itself according to my needs by implementing axios to consume my api. The GET AND DELETE method is working perfectly, however I am very confused about the POST AND PUT method, I am using 2 models as a client and the relationship with the genre, follows part of the code:
<template>
<v-data-table
:headers="headers"
:items="clients"
sort-by="firstName"
class="elevation-2"
>
<template v-slot:top>
<v-toolbar flat color="white">
<v-icon medium>mdi-account-supervisor</v-icon>
<v-toolbar-title> Clients</v-toolbar-title>
<v-divider
class="mx-4"
inset
vertical
></v-divider>
<v-spacer></v-spacer>
<v-dialog v-model="dialog" max-width="600px">
<template v-slot:activator="{ on }">
<v-btn
color="blue"
dark class="mt-6 mb-4"
v-on="on"
rounded
><v-icon medium>mdi-plus</v-icon>Add new</v-btn>
</template>
<v-card>
<v-card-title>
<span class="headline">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container>
<v-form>
<v-row>
<v-col cols="12" sm="6" md="12">
<v-text-field v-model="editedItem.firstName" label="First Name"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field v-model="editedItem.lastName" label="Last Name"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field v-model="editedItem.email" label="E-Mail"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field v-model="editedItem.phone" label="Phone"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field v-model="editedItem.mobilePhone" label="Mobile Phone"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="12">
<!-- select options-->
<v-select
label='Gender'
v-model='editedItem.gender.name'
:items='genders'
item-value='name'
item-text='name'
>
</v-select>
</v-col>
</v-row>
</v-form>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="error" rounded #click="close">Cancel</v-btn>
<v-btn color="primary" rounded #click="save">Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-toolbar>
</template>
<template v-slot:item.action="{ item }">
<v-icon
small
color="green"
class="mr-2"
#click="editItem(item)"
>
mdi-pencil
</v-icon>
<v-icon
small
color="red"
#click="deleteItem(item)"
>
mdi-delete
</v-icon>
</template>
<template v-slot:no-data>
<v-btn color="primary" #click="initialize">Reset</v-btn>
</template>
</v-data-table>
</template>
<script>
import axios from 'axios'
import Client from '../../services/clients';
import Gender from '../../services/genders';
export default {
data: () => ({
dialog: false,
headers: [
{
text: 'First Name',
align: 'start',
sortable: false,
value: 'firstName',
},
{ text: 'Last Name', value: 'lastName' },
{ text: 'Email', value: 'email' },
{ text: 'Phone', value: 'phone' },
{ text: 'Mobile Phone', value: 'mobilePhone' },
{ text: 'Gender', value: 'gender.name' },
{ text: 'Actions', value: 'action', sortable: false },
],
clients: [],
genders: [],
errors: [],
editedIndex: -1,
editedItem: {
firstName: '',
lastName: '',
email: '',
phone: '',
mobilePhone: '',
gender: '',
},
defaultItem: {
firstName: '',
lastName: '',
email: '',
phone: '',
mobilePhone: '',
gender: '',
},
}),
computed: {
formTitle () {
return this.editedIndex === -1 ? 'New Item' : 'Edit Item'
},
},
watch: {
dialog (val) {
val || this.close()
},
},
created () {
this.initialize()
},
methods: {
initialize () {
Client.list().then(response => {
this.clients = response.data
}).catch(e => {
console.log(e)
});
Gender.list().then(response => {
this.genders = response.data
}).catch(e => {
console.log(e)
});
},
editItem (item) {
axios.put('http://192.168.26.130:3000/client/' + item.id)
.then(response => {
this.editedIndex = this.clients.indexOf(item)
this.editedItem = Object.assign({}, item)
this.editedID = this.editedItem.id
this.dialog = true
this.response = response
}).catch(e => {
console.log(e)
});
},
deleteItem (item) {
if (confirm("Do you really want to delete?")) {
axios.delete('http://192.168.26.130:3000/client/' + item.id)
.then(response => {
const index = this.clients.indexOf(item)
this.deletedItem = Object.assign({}, item)
this.deletedID = this.deletedItem.id
this.clients.splice(index, 1);
this.response = response
}).catch(e => {
console.log(e)
});
}
},
close () {
this.dialog = false
setTimeout(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.editedIndex = -1
}, 300)
},
save () {
if (this.editedIndex > -1) {
axios.post('http://192.168.26.130:3000/client/')
.then(response => {
Object.assign(this.clients[this.editedIndex], this.editedItem)
this.response = response.data
}).catch(e => {
console.log(e)
});
} else {
this.clients.push(this.editedItem)
}
this.close()
},
},
}
</script>
When opening the modal to add item, only when opening the select and modifying the genre this error already appears before even saving, as shown in the image:
When clicking on save it is saved only on the front, and when updating the page the record disappears, could someone give me a light?
Update Edit.
After some changes, I think I am closer to the solution but I came to the following obstacle, When saving the client item, the gender is stored empty.
of console.log and the item saved in the front end but in the database the gender is empty
The file DataTable.vue:
<template>
<v-data-table
:headers="headers"
:items="clients"
sort-by="firstName"
class="elevation-2"
>
<template v-slot:top>
<v-toolbar flat color="white">
<v-icon medium>mdi-account-supervisor</v-icon>
<v-toolbar-title> Clients</v-toolbar-title>
<v-divider
class="mx-4"
inset
vertical
></v-divider>
<v-spacer></v-spacer>
<v-dialog v-model="dialog" max-width="600px">
<template v-slot:activator="{ on }">
<v-btn
color="blue"
dark class="mt-6 mb-4"
v-on="on"
rounded
><v-icon medium>mdi-plus</v-icon>Add new</v-btn>
</template>
<v-card>
<v-card-title>
<span class="headline">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container>
<v-form>
<v-row>
<v-col cols="12" sm="6" md="12">
<v-text-field v-model="editedItem.firstName" label="First Name"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field v-model="editedItem.lastName" label="Last Name"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field v-model="editedItem.email" label="E-Mail"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field v-model="editedItem.phone" label="Phone"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field v-model="editedItem.mobilePhone" label="Mobile Phone"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="12">
<!-- select options-->
<v-select
label='Gender'
v-model='editedItem.gender'
:items='genders'
item-value='name'
item-text='name'
>
</v-select>
</v-col>
</v-row>
</v-form>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="error" rounded #click="close">Cancel</v-btn>
<v-btn color="primary" rounded #click="save">Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-toolbar>
</template>
<template v-slot:item.action="{ item }">
<v-icon
small
color="green"
class="mr-2"
#click="editItem(item)"
>
mdi-pencil
</v-icon>
<v-icon
small
color="red"
#click="deleteItem(item)"
>
mdi-delete
</v-icon>
</template>
<template v-slot:no-data>
<v-btn color="primary" #click="initialize">Reset</v-btn>
</template>
</v-data-table>
</template>
<script>
import axios from 'axios'
import Client from '../../services/clients';
import Gender from '../../services/genders';
export default {
data: () => ({
dialog: false,
headers: [
{
text: 'First Name',
align: 'start',
sortable: false,
value: 'firstName',
},
{ text: 'Last Name', value: 'lastName' },
{ text: 'Email', value: 'email' },
{ text: 'Phone', value: 'phone' },
{ text: 'Mobile Phone', value: 'mobilePhone' },
{ text: 'Gender', value: 'gender.name' },
{ text: 'Actions', value: 'action', sortable: false },
],
clients: [],
genders: [],
errors: [],
editedIndex: -1,
editedItem: {
firstName: '',
lastName: '',
email: '',
phone: '',
mobilePhone: '',
gender: '',
},
defaultItem: {
firstName: '',
lastName: '',
email: '',
phone: '',
mobilePhone: '',
gender: '',
},
}),
computed: {
formTitle () {
return this.editedIndex === -1 ? 'New Item' : 'Edit Item'
},
},
watch: {
dialog (val) {
val || this.close()
},
},
created () {
this.initialize()
},
methods: {
initialize () {
Client.list().then(response => {
this.clients = response.data
}).catch(e => {
console.log(e)
});
Gender.list().then(response => {
this.genders = response.data
}).catch(e => {
console.log(e)
});
},
editItem (item) {
axios.put('http://192.168.26.130:3000/client/' + item.id)
.then(response => {
this.editedIndex = this.clients.indexOf(item)
this.editedItem = Object.assign({}, item)
this.editedID = this.editedItem.id
this.dialog = true
this.response = response
}).catch(error => {
console.log(error.response)
});
},
deleteItem (item) {
if (confirm("Do you really want to delete?")) {
axios.delete('http://192.168.26.130:3000/client/' + item.id)
.then(response => {
const index = this.clients.indexOf(item)
this.deletedItem = Object.assign({}, item)
this.deletedID = this.deletedItem.id
this.clients.splice(index, 1);
this.response = response
}).catch(error => {
console.log(error.response)
});
}
},
close () {
this.dialog = false
setTimeout(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.editedIndex = -1
}, 300)
},
save () {
if (this.editedIndex > -1) {
Object.assign(this.clients[this.editedIndex], this.editedItem)
} else {
this.clients.push(this.editedItem)
axios.post('http://192.168.26.130:3000/client/', this.editedItem)
.then(response => {
console.log(response)
}).catch(error => {
console.log(error.response)
});
}
this.close()
},
},
}
</script>
Please would someone help me?
There are a couple of issues. First, you aren't passing any data to your PUT and POST requests. They should look something like:
editItem (item) {
// YOU NEED TO PASS AN OBJECT TO THE PUT REQUEST ▼▼HERE▼▼
axios.put('http://192.168.26.130:3000/client/' + item.id , item)
.then(response => {
// handle response...
})
.catch(err => { console.log(error) })
},
save () {
if (this.editedIndex > -1) {
// YOU NEED TO PASS AN OBJECT TO THE POST REQUEST ▼▼HERE▼▼
axios.post('http://192.168.26.130:3000/client/', this.editedItem)
.then(response => {
// handle response...
})
.catch(err => { console.log(error) })
} else { /* ... */ }
},
Second, under the hood, <v-select> uses a v-for to iterate over all of the options that are supposed to go into the dropdown menu. If this were a plain HTML <select> element, it would look something like this:
<select name="gender">
<option value="">Select a gender...</option>
<option
v-for="gender in genders"
:key="gender"
value="gender.value"
>
{{ gender.text }}
</option>
</select>
Vuetify expects the array of genders to be in one of two formats, either an array of strings, or an array of objects with text and value properties:
const genders = ['male', 'female', 'other']
// OR
const genders = [
{ value: 1, text: 'male' }, // `value` can be anything you want
{ value: 2, text: 'female' },
{ value: 3, text: 'other' },
]
Alternatively, if your genders array has a different data structure, you can tell Vuetify what properties to use for the value and text properties (this is what it looks like you did). So if your genders array looks like this:
const genders = [
{ name: 'male' },
{ name: 'female' },
{ name: 'other' },
]
Your <v-select> should look like this (in your case you used the SAME property for both text and value, which is perfectly fine to do):
<v-select
v-model="editedItem.gender"
:items="genders"
item-text="name"
return-object
/>
What I'm guessing, based on the image you attached, is that the genders array is NOT in one of these formats, and this is causing an error when Vuetify tries to turn it into a dropdown. Also, I think you intend for the value selected to be assigned to editedItem.gender and not editedItem.gender.name. Here's a codepen showing how to use objects for v-select items.
If the items array is in one of the two formats I showed before, you do NOT need to specify the item-text and item-value props. They will be detected automatically.
Hope this helps!
Related
I'm using vuetify datatable and I fill the table with API- GET Request via Axios.
The problem is when I click Edit Button on the right the placeholder of the textboxes overlap with the selected rows' values.
The issue can be easily understandable from the picture.
Also, when I delete the default headers i.e., (Carbs (g) and Protein (g)) from the code, the actions column is disappearing.. (Picture 2)
Finally, here is the City.vue
<template>
<v-data-table
:headers="headers"
:items="cities"
sort-by="Id"
class="elevation-1"
>
<template v-slot:top>
<v-toolbar
flat
>
<v-toolbar-title>CITY CRUD</v-toolbar-title>
<v-divider
class="mx-4"
inset
vertical
></v-divider>
<v-spacer></v-spacer>
<v-dialog
v-model="dialog"
max-width="500px"
>
<template v-slot:activator="{ on, attrs }">
<v-btn
color="primary"
dark
class="mb-2"
v-bind="attrs"
v-on="on"
>
New City
</v-btn>
</template>
<v-card>
<v-card-title>
<span class="text-h5">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col
cols="12"
sm="6"
md="4"
>
<v-text-field
v-model="editedItem.Id"
label="Id"
></v-text-field>
</v-col>
<v-col
cols="12"
sm="6"
md="4"
>
<v-text-field
v-model="editedItem.Text"
label="Text"
></v-text-field>
</v-col>
<v-col
cols="12"
sm="6"
md="4"
>
<v-text-field
v-model="editedItem.Description"
label="Description"
></v-text-field>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="blue darken-1"
text
#click="close"
>
Cancel
</v-btn>
<v-btn
color="blue darken-1"
text
#click="save"
>
Save
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-dialog v-model="dialogDelete" max-width="500px">
<v-card>
<v-card-title class="text-h5">Are you sure you want to delete this item?</v-card-title>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" text #click="closeDelete">Cancel</v-btn>
<v-btn color="blue darken-1" text #click="deleteItemConfirm">OK</v-btn>
<v-spacer></v-spacer>
</v-card-actions>
</v-card>
</v-dialog>
</v-toolbar>
</template>
<template v-slot:[`item.actions`]="{ item }">
<v-icon
small
class="mr-2"
#click="editItem(item)"
>
mdi-pencil
</v-icon>
<v-icon
small
#click="deleteItem(item)"
>
mdi-delete
</v-icon>
</template>
<template v-slot:no-data>
<v-btn
color="primary"
#click="initialize"
>
Reset
</v-btn>
</template>
</v-data-table>
</template>
<script>
import axios from 'axios'
export default {
data: () => ({
dialog: false,
dialogDelete: false,
headers: [
{
text: 'Id',
align: 'start',
sortable: false,
value: 'Id',
},
{ text: 'Text', value: 'Text' },
{ text: 'Description', value: 'Description' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Actions', value: 'actions', sortable: false },
],
cities: [],
editedIndex: -1,
editedItem: {
Id: 0,
Text: '',
Description: '',
},
defaultItem: {
Id: 0,
Text: '',
Description: '',
},
}),
watch: {
dialog (val) {
val || this.close()
},
dialogDelete (val) {
val || this.closeDelete()
},
},
created () {
this.initialize()
},
methods: {
initialize () {
axios.get("https://localhost:44377/city")
.then((response)=>{
this.cities=response.data;
});
},
editItem (item) {
this.editedIndex = this.cities.indexOf(item)
this.editedItem = Object.assign({}, item)
this.dialog = true
},
deleteItem (item) {
this.editedIndex = this.cities.indexOf(item)
this.editedItem = Object.assign({}, item)
this.dialogDelete = true
},
deleteItemConfirm () {
this.cities.splice(this.editedIndex, 1)
this.closeDelete()
},
close () {
this.dialog = false
this.$nextTick(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.editedIndex = -1
})
},
closeDelete () {
this.dialogDelete = false
this.$nextTick(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.editedIndex = -1
})
},
save () {
if (this.editedIndex > -1) {
Object.assign(this.cities[this.editedIndex], this.editedItem)
} else {
this.cities.push(this.editedItem)
}
this.close()
},
},
}
</script>
im trying to add this.loading = false; in this below code.
.catch(
Toast.fire({
icon: 'warning',
title: 'Invalid Email or Password'
})
)
page code
<template>
<v-row justify="center">
<v-col cols="12" sm="6">
<form #submit.prevent="login">
<v-card ref="form">
<v-card-text>
<h3 class="text-center">Login</h3>
<v-divider class="mt-3"></v-divider>
<v-col cols="12">
<v-img
src="/assets/1.png"
class="my-3"
contain
height="50"
/>
</v-col>
<v-col cols="12" sm="12">
<v-text-field
v-model.trim="form.mobile_number"
type="number"
label="Mobile No"
solo
hide-details="auto"
></v-text-field>
<span class="form-text red--text" v-if="errors.mobile_number">
{{ errors.mobile_number[0] }}
</span>
<!-- <small class="form-text red--text" v-if="errors.mobile_number">{{errors.mobile_number[0]}}</small> -->
</v-col>
<v-col cols="12">
<v-text-field
v-model.trim="form.password"
type="password"
label="Password"
solo
hide-details="auto"
append-icon="mdi-eye"
></v-text-field>
<span class="form-text red--text" v-if="errors.password">
{{ errors.password[0] }}
</span>
<!-- <small class="form-text red--text" v-if="errors.password">{{errors.password[0]}}</small> -->
</v-col>
</v-card-text>
<v-divider class="mt-12"></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<div class="text-center">
<v-btn
rounded
type="submit"
:loading="loading"
color="primary"
dark
>Login</v-btn
>
</div>
</v-card-actions>
</v-card>
</form>
</v-col>
</v-row>
</template>
<script>
export default {
created(){
if (User.loggedIn()) {
this.$router.push({name: 'DashBoard'})
}
},
data(){
return {
loading: false,
form:{
mobile_number: null,
password: null
},
errors:[],
};
},
methods:{
login(){
this.loading = true;
axios.post('/api/auth/login',this.form)
.then(res => {
User.responseAfterLogin(res)
Toast.fire({
icon: 'success',
title: 'Signed in successfully'
})
this.$router.push({ name: 'DashBoard'});
})
.catch((error) => {this.loading = false;
{
this.errors = error.response.data.errors;
}
})
.catch(
Toast.fire({
icon: 'warning',
title: 'Invalid Email or Password'
})
)
.finally(() => {
this.loading = false
})
}
}
};
</script>
data(){
return {
loading: false,
form:{
mobile_number: null,
password: null
},
errors: {
mobile_number: null,
password: null,
},
};
},
axios.post('/api/auth/login',this.form)
.then(res => {
User.responseAfterLogin(res)
Toast.fire({
icon: 'success',
title: 'Signed in successfully'
})
this.$router.push({ name: 'DashBoard'});
})
.catch((error) => {
this.loading = false;
this.errors = error.response.data.errors;
Toast.fire({
icon: 'warning',
title: 'Invalid Email or Password'
})
})
.finally(() => {
this.loading = false
})
I am developing a recipe app. At my CreateRecipe component, I have child component to add ingredients to the recipe or edit existing ingredients. Ill start by showing the code and what i want to achieve and then the problem
Parent component:
<template>
...
<v-dialog v-model="AddIgredientsDialog" max-width="800px">
<template v-slot:activator="{ on, attrs }">
<v-btn color="secondary" dark v-bind="attrs" v-on="on">
Add addIngredients
</v-btn>
</template>
<AddItemsForm
#addIngredient="SaveNewIgredient"
:newIngredientsItem="editedIgredient"
/>
</v-dialog>
</template>
<script>
import AddItemsForm from "./AddItemsForm"; //Child Component
data: () => ({
AddIgredientsDialog:false,
article: {
headline: "",
img: "",
content: "",
subHeader: "",
description: "",
igredients: [], //List to add/edit item at AddItemsForm child component
preperation: []
},
editedIgredient: { //Item to use for editing or adding new item to article.igredients
title: "",
subIgredients: []
},
defaultItem: { //Item used for resetting editedIgredient item
title: "",
subIgredients: []
},
editedIndex: -1, helper variable for knowing whether i need to add new item or edit exiting item
}),
methods:{
editIngredients(item) {
this.editedIndex = this.article.igredients.indexOf(item);
this.editedIgredient = Object.assign({}, item);
this.AddIgredientsDialog = true;
},
SaveNewIgredient(newItem) { //Triggered on #click of save button at child component New item is the
//item passed from children
if (this.editedIndex > -1) {
this.editedIgredient = Object.assign({}, newItem);
Object.assign(
this.article.igredients[this.editedIndex],
this.editedIgredient
);
} else {
this.article.igredients.push(this.editedIgredient);
}
this.AddIgredientsDialog = false;
this.$nextTick(() => {
this.editedIgredient = Object.assign({}, this.defaultItem);
this.editedIndex = -1;
});
},
}
</script>
Child Component:
<template>
<v-card>
<v-card-title>
<span class="headline">Add Ingredients</span>
</v-card-title>
<v-card-text>
<v-text-field v-model="newIngredientsItem.title" placeholder="כותרת">
</v-text-field>
<v-row align="center">
<v-col sm="11">
<v-text-field
v-model="newIgredient"
placeholder="New Igredient"
#keyup.enter="addNewIgredient"
>
</v-text-field>
</v-col>
<v-col sm="1">
<v-btn icon #click="addNewIgredient">
<v-icon>
mdi-plus
</v-icon>
</v-btn>
</v-col>
<v-col class="mt-0 pt-0" cols="12">
<v-row no-gutters>
<v-col cols="12">
<v-card flat tile>
<template
v-for="(item, index) in newIngredientsItem.subIgredients"
>
<v-list-item :key="index" class="mr-0 pr-0">
<v-list-item-content>
<v-list-item-title>
<v-edit-dialog #click.native.stop>
{{ item }}
<v-text-field
slot="input"
v-model="newIngredientsItem.subIgredients[index]"
></v-text-field>
</v-edit-dialog>
</v-list-item-title>
</v-list-item-content>
<v-list-item-action>
<v-btn icon #click="removeIgredient(index)">
<v-icon small>
mdi-delete
</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
<v-divider
v-if="index + 1 < newIngredientsItem.subIgredients.length"
:key="item + index"
></v-divider>
</template>
</v-card>
</v-col>
</v-row>
</v-col>
</v-row>
</v-card-text>
<v-card-actions>
<v-btn color="primary" #click="AddIngredients">
Save
</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
props: {
newIngredientsItem: {
type: Object,
default() {
return {
title: "",
subIgredients: [ ]
};
}
}
},
data: () => ({
newIgredient: ""
}),
methods: {
addNewIgredient() {
this.newIngredientsItem.subIgredients.push(this.newIgredient);
this.newIgredient = "";
},
AddIngredients() {
this.$emit("addIngredient", this.newIngredientsItem);
},
removeIgredient(index) {
this.newIngredientsItem.subIgredients.splice(index, 1);
}
}
};
</script>
My Problem:
At the moment im only trying to use the SaveNewIgredient() method.
After 1st time of adding item the item is added as it should and the parent defaultItem state remain as is which is good:
defaultItem: {
title: "",
subIgredients: []
},
After adding a second item the defaultItem changes and takes the editedItem properties.
For example if i add at the second time
{
title:'Test 1',
subIgredients: [
'Test 1 - 1',
'Test 1 - 2',
'Test 1 - 3',
]
}
That is what the defaultItem will be and then this assignment causes a bug
this.editedIgredient = Object.assign({}, this.defaultItem);
because editedItem should be:
{
title: "",
subIgredients: []
}
I tried to solve your problem. To do this I modified and in some places simplified your code to keep only what was close to the SaveNewIgredient() function. So here is my code.
Parent Component (for me App.vue):
<template>
<AddItemsForm #addIngredient="SaveNewIgredient" />
</template>
<script>
import AddItemsForm from "./AddItemsForm"; //Child Component
export default {
name: "App",
components: { AddItemsForm },
data() {
return {
article: {
igredients: [], //List to add/edit item at AddItemsForm child component
},
editedIgredient: {
//Item to use for editing or adding new item to article.igredients
title: "",
subIgredients: [],
},
defaultItem: {
//Item used for resetting editedIgredient item
title: "",
subIgredients: [],
},
};
},
methods: {
SaveNewIgredient(newItem) {
console.log("Received: ", newItem);
this.editedIgredient = newItem;
this.article.igredients.push({ ...this.editedIgredient });
console.log("defaultClear: ", this.defaultItem);
console.log("infoItem: ", this.editedIgredient);
this.editedIgredient = this.defaultItem;
console.log("defaultClear: ", this.defaultItem);
console.log("editedWillClear: ", this.editedIgredient);
console.log("listFinal: ", this.article.igredients);
},
},
};
</script>
Child Component (for me AddItemsForm.vue):
<template>
<div>
<input v-model="newIgredient" placeholder="New Igredient" />
<button #click="addNewIgredient">ADD</button>
<div>
<button color="primary" #click="AddIngredients">Save</button>
</div>
</div>
</template>
<script>
export default {
props: {
IngredientsItem: {
type: Object,
default() {
return {
title: "",
subIgredients: [],
};
},
},
},
data() {
return {
newIgredient: "",
title: "TEST",
titleNbr: 0,
resetIgredient: false,
};
},
computed: {
newIngredientsItem() {
return this.IngredientsItem;
},
},
methods: {
addNewIgredient() {
if (this.resetIgredient === true) {
this.newIngredientsItem.subIgredients = [];
}
this.newIngredientsItem.subIgredients.push(this.newIgredient);
this.newIgredient = "";
this.resetIgredient = false;
console.log("ADD: ", this.newIngredientsItem.subIgredients);
},
AddIngredients() {
this.newIngredientsItem.title = this.title + this.titleNbr;
this.titleNbr++;
console.log("EMIT: ", this.newIngredientsItem);
this.$emit("addIngredient", this.newIngredientsItem);
this.resetIgredient = true;
},
},
};
</script>
I have a problem that when using the post method using axes I would need to send the data in the following json format:
{
"id":"1",
"firstName":"Faabio",
"lastName":"Mendes de Jesus",
"phone":"11941649284",
"mobilePhone":"11941649284",
"email":"art7design2013#gmail.com",
"gender":
{"name":"masculino"}
}
However, when saving, sex is stored only in the front, but it is not saved in the database, my console.log records the following situations: In object: config the data is correct and with the association to the gender, but in config: data the association no longer appears indicating that something is missing to persist the data and I'm going crazy about it, follow the console:
This line that was saved, in json format, gender is getting null and data table image with the gender field empty:
{
"id":"3",
"firstName":"ana",
"lastName":"lucia",
"phone":"1188888888",
"mobilePhone":"1188888888",
"email":"analu#gmail.com",
"gender":null
}
My file .vue
<template>
<v-data-table
:headers="headers"
:items="clients"
sort-by="firstName"
class="elevation-2"
>
<template v-slot:top>
<v-toolbar flat color="white">
<v-icon medium>mdi-account-supervisor</v-icon>
<v-toolbar-title> Clients</v-toolbar-title>
<v-divider
class="mx-4"
inset
vertical
></v-divider>
<v-spacer></v-spacer>
<v-dialog v-model="dialog" max-width="600px">
<template v-slot:activator="{ on }">
<v-btn
color="blue"
dark class="mt-6 mb-4"
v-on="on"
rounded
><v-icon medium>mdi-plus</v-icon>Add new</v-btn>
</template>
<v-card>
<v-card-title>
<span class="headline">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container>
<v-form>
<v-row>
<v-col cols="12" sm="6" md="12">
<v-text-field v-model="editedItem.firstName" label="First Name"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field v-model="editedItem.lastName" label="Last Name"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field v-model="editedItem.email" label="E-Mail"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field v-model="editedItem.phone" label="Phone"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field v-model="editedItem.mobilePhone" label="Mobile Phone"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="12">
<!-- select options-->
<v-select
label='Gender'
v-model='editedItem.gender'
:items='genders'
item-text='name'
return-object
>
</v-select>
</v-col>
</v-row>
</v-form>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="error" rounded #click="close">Cancel</v-btn>
<v-btn color="primary" rounded #click="save">Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-toolbar>
</template>
<template v-slot:item.action="{ item }">
<v-icon
small
color="green"
class="mr-2"
#click="editItem(item)"
>
mdi-pencil
</v-icon>
<v-icon
small
color="red"
#click="deleteItem(item)"
>
mdi-delete
</v-icon>
</template>
<template v-slot:no-data>
<v-btn color="primary" #click="initialize">Reset</v-btn>
</template>
</v-data-table>
</template>
<script>
import axios from 'axios'
import Client from '../../services/clients';
import Gender from '../../services/genders';
export default {
data: () => ({
dialog: false,
headers: [
{
text: 'First Name',
align: 'start',
sortable: false,
value: 'firstName',
},
{ text: 'Last Name', value: 'lastName' },
{ text: 'Email', value: 'email' },
{ text: 'Phone', value: 'phone' },
{ text: 'Mobile Phone', value: 'mobilePhone' },
{ text: 'Gender', value: 'gender.name' },
{ text: 'Actions', value: 'action', sortable: false },
],
clients: [],
genders: [],
errors: [],
editedIndex: -1,
editedItem: {
firstName: '',
lastName: '',
email: '',
phone: '',
mobilePhone: '',
gender: '',
},
defaultItem: {
firstName: '',
lastName: '',
email: '',
phone: '',
mobilePhone: '',
gender: '',
},
}),
computed: {
formTitle () {
return this.editedIndex === -1 ? 'New Item' : 'Edit Item'
},
},
watch: {
dialog (val) {
val || this.close()
},
},
created () {
this.initialize()
},
methods: {
initialize () {
Client.list().then(response => {
this.clients = response.data
}).catch(e => {
console.log(e)
});
Gender.list().then(response => {
this.genders = response.data
}).catch(e => {
console.log(e)
});
},
editItem (item) {
this.editedIndex = this.clients.indexOf(item)
this.editedItem = Object.assign({}, item)
this.editedID = this.editedItem.id
this.dialog = true
axios.put('http://192.168.26.130:3000/client/' + item.id)
.then(response => {
this.response = response
}).catch(error => {
console.log(error.response)
});
},
deleteItem (item) {
if (confirm("Do you really want to delete?")) {
const index = this.clients.indexOf(item)
this.deletedItem = Object.assign({}, item)
this.deletedID = this.deletedItem.id
this.clients.splice(index, 1);
axios.delete('http://192.168.26.130:3000/client/' + item.id)
.then(response => {
this.response = response
}).catch(error => {
console.log(error.response)
});
}
},
close () {
this.dialog = false
setTimeout(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.editedIndex = -1
}, 300)
},
save () {
if (this.editedIndex > -1) {
Object.assign(this.clients[this.editedIndex], this.editedItem)
} else {
this.clients.push(this.editedItem)
axios.post('http://192.168.26.130:3000/client/', this.editedItem)
.then(response => {
console.log(response)
}).catch(error => {
console.log(error.response)
});
}
this.close()
},
},
}
</script>
The code snippet that saves to the database:
this.clients.push(this.editedItem)
axios.post('http://192.168.26.130:3000/client/', this.editedItem)
.then(response => {
console.log(response)
}).catch(error => {
console.log(error.response)
Could someone save me? Thank you very much in advance .
I would like to kindly ask you about Vuetify and its Data Table. I am using Vuex for state managing. When I open the page Vuex loads all the data from API. It works perfectly. Then I have the Data Table which also works (update, add, delete), but only one column does not... Data Table is filled with GET_CENTERS and the "one column" is an object (center.customer). When I change center.customer.name state is updated, database is updated, but the value in Data Table is not. (I have tried to just create a list of customers on same page and this list changes if :key is set).
CentersTable
<template>
<div>
<v-data-table
:headers="headers"
:items="GET_CENTERS"
sort-by="name"
class="elevation-1"
>
<template v-slot:top>
<v-toolbar flat color="white">
<v-toolbar-title>My CRUD</v-toolbar-title>
<v-divider
class="mx-4"
inset
vertical
></v-divider>
<div class="flex-grow-1"></div>
<v-dialog v-model="dialog" max-width="500px">
<template v-slot:activator="{ on }">
<v-btn color="primary" dark class="mb-2" v-on="on">Nový Záznam</v-btn>
</template>
<v-card>
<v-card-title>
<span class="headline">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col cols="12" sm="6" md="6">
<v-text-field v-model="editedItem.name" label="Název"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="6">
<v-text-field v-model="editedItem.address" label="Adresa"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="6">
<v-text-field v-model="editedItem.city" label="Město"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="6">
<v-text-field v-model="editedItem.zip" label="PSČ"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="6">
<v-text-field v-model="editedItem.email" label="Email"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="6">
<v-text-field v-model="editedItem.phone" label="Telefon"></v-text-field>
</v-col>
<v-col cols="12" sm="12" md="12">
<v-combobox
v-model="editedItem.customer"
:items="GET_CUSTOMERS"
:search-input.sync="search"
item-text="name"
item-value="_id"
:hide-selected="hideSelected"
label="Zákazník"
persistent-hint
:clearable="clearable"
return-object
>
<template v-if="noData" v-slot:no-data>
<v-list-item>
<v-list-item-content>
<v-list-item-title>
No results matching "<strong>{{ search }}</strong>". Press <kbd>enter</kbd> to create a new one
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</template>
</v-combobox>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<div class="flex-grow-1"></div>
<v-btn color="blue darken-1" text #click="close">Cancel</v-btn>
<v-btn color="blue darken-1" text #click="save">Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-toolbar>
</template>
<template v-slot:item.action="{ item }">
<v-icon
small
class="mr-2"
#click="editItem(item)"
>
edit
</v-icon>
<v-icon
small
#click="deleteItem(item)"
>
delete
</v-icon>
</template>
</v-data-table>
<template>
<v-list-item v-for="item in GET_CUSTOMERS" :key="item._id">
<v-list-item-content>{{item}}</v-list-item-content>
</v-list-item>
</template>
</div>
</template>
<script>
import {mapActions, mapGetters} from 'vuex'
export default {
name: "CentersTable",
data: () => ({
dialog: false,
editedItem: {},
headers: [
{
text: 'Název',
align: 'left',
sortable: true,
value: 'name',
},
{
text: 'Adresa',
sortable: true,
value: 'address',
},
{
text: 'Město',
sortable: true,
value: 'city',
},
{
text: 'PSČ',
sortable: true,
value: 'zip',
},
{
text: 'Email',
sortable: true,
value: 'email',
},
{
text: 'Telefon',
sortable: true,
value: 'phone',
},
{
text: 'Zákazník',
sortable: true,
value: 'customer.name',
},
{ text: 'Akce', value: 'action', sortable: false, align: 'right' },
],
search: null,
chips: true,
multiple: true,
hideSelected: true,
noData: true,
clearable: false,
}),
watch: {
dialog (val) {
val || this.close()
},
},
computed: {
formTitle() {
return this.editedItem._id === undefined ? 'Nový Záznam' : 'Upravit Záznam'
},
...mapGetters([
'GET_CUSTOMERS',
'GET_CENTERS'
]),
},
methods: {
...mapActions([
'createCenter',
'updateCenter',
'deleteCenter',
]),
editItem (item) {
this.editedItem = Object.assign({}, item)
this.dialog = true
},
deleteItem (item) {
confirm('Opravdu chcete smazat tento záznam?') && this.deleteCenter(item).then(() => {
this.$noty.success('Záznam byl smazán')
}).catch(() => {
this.$noty.alert('Při mazání záznamu došlo k chybě')
})
},
close () {
this.dialog = false
this.editedItem = {}
setTimeout(() => {
}, 300)
},
save () {
if (this.editedItem._id === undefined) {
this.createCenter(this.editedItem).then(() => {
this.$noty.success('Nový zákazník byl vytvořen')
}).catch(() => {
this.$noty.alert('Při vytváření zákazníka došlo k chybě')
})
} else {
this.updateCenter(this.editedItem).then(() => {
this.$noty.success('Záznam byl upraven')
}).catch(() => {
this.$noty.alert('Při ukládání záznamu došlo k chybě')
})
}
this.close()
},
}
}
</script>
<style scoped>
</style>
And Vuex store
import axios from "axios";
import Vue from "vue";
const state = {
customers: []
};
const mutations = {
SET_CUSTOMERS(state, payload) {
state.customers = payload;
},
UPDATE_CUSTOMER(state, payload) {
const customer = state.customers.findIndex(x => x._id === payload._id);
Vue.set(state.customers, customer, payload);
},
ADD_CUSTOMER(state, payload) {
state.customers.push(payload);
},
REMOVE_CUSTOMER(state, payload) {
const customer = state.customers
.map(customer => customer._id)
.indexOf(payload);
state.customers.splice(customer, 1);
}
};
const actions = {
loadCustomers({ commit }) {
axios.get("/api/customers").then(data => {
commit("SET_CUSTOMERS", data.data);
});
},
updateCustomer({ commit }, payload) {
axios.put(`/api/customers/${payload._id}`, payload).then(response => {
commit("UPDATE_CUSTOMER", response.data);
});
},
createCustomer({ commit }, payload) {
axios.post("/api/customers", payload).then(data => {
commit("ADD_CUSTOMER", data.data);
});
},
deleteCustomer({ commit }, payload) {
axios.delete(`/api/customers/${payload._id}`).then(() => {
commit("REMOVE_CUSTOMER", payload);
});
}
};
const getters = {
GET_CUSTOMERS: state => state.customers
};
export default {
state,
mutations,
actions,
getters
};