Move row from one dynamic table to another dynamic table in vuetify - vue.js

I haven't found a question that addresses this problem using vuetify/vue.
I have a dynamic table, and on that page is an add item button. Clicking button pops up a dialog with anther dynamic table. I want to be able to click an add icon for each specific table row. Clicking the icon would move it to the original dynamic table.
I tried using something similar to the delete row function. I ended up getting two empty rows added, with the error " Invalid prop: type check failed for prop "item". Expected Object, got Number with value 0"
Here is what I have that creates that error.
HTML
<v-data-table
:headers="headers"
:items="agents"
sort-by="calories"
class="elevation-1"
>
<template v-slot:top>
<v-toolbar flat color="white">
<v-spacer></v-spacer>
<v-dialog v-model="dialog" max-width="800px">
<template v-slot:activator="{ on }">
<v-btn color="primary" dark class="mb-2" v-on="on">Add Agent</v-btn>
</template>
<v-card>
<v-card-title>
<span class="headline">New Agent</span>
</v-card-title>
<v-data-table :headers="headers2" :items="newAgents">
<template v-slot:item.action="{ item }">
<v-icon small #click="addItem(item)">
mdi-plus-circle-outline
</v-icon>
</template>
</v-data-table>
<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-toolbar>
</template>
<template v-slot:item.action="{ item }">
<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>
import axios from "axios";
export default {
data: () => ({
dialog: false,
isLoading: true,
headers: [
{ text: "Host IP Address", value: "host_ip" },
{ text: "Hostname", value: "host_name" },
{ text: "Agent Version", value: "agent_version" },
{ text: "Agent Install Location", value: "install_location" },
{ text: "Agent Status", value: "agent_status" },
{ text: "Actions", value: "action", sortable: false }
],
headers2: [
{ text: "Host IP Address", value: "host_ip" },
{ text: "Hostname", value: "host_name" },
{ text: "Agent Version", value: "agent_version" },
{ text: "Agent Install Location", value: "install_location" },
{ text: "Agent Status", value: "agent_status" },
{ text: "Add", value: "action", sortable: false }
],
agents: [],
newAgents: []
}),
watch: {
dialog(val) {
val || this.close();
}
},
created() {
this.initialize();
axios
.get("https://my.api.mockaroo.com/add_new_agent.json?key=88c9bdc0")
.then(res => (this.newAgents = res.data))
.then(res => {
console.log(res);
})
.catch(err => console.log(err));
},
methods: {
initialize() {
this.agents = [
{
host_ip: "Frozen Yogurt",
host_name: 159,
agent_version: 6.0,
install_location: 24,
agent_status: 4.0
},
{
host_ip: "Ice cream sandwich",
host_name: 237,
agent_version: 9.0,
install_location: 37,
agent_status: 4.3
}
];
},
changeColor() {
this.isLoading = !this.isLoading;
},
deleteItem(item) {
const index = this.agents.indexOf(item);
confirm("Are you sure you want to delete this item?") &&
this.agents.splice(index, 1);
},
addItem(item) {
const index = this.newAgents.indexOf(item);
confirm("Are you sure you want to add this item?") &&
this.agents.push(index, 1);
},
close() {
this.dialog = false;
setTimeout(() => {
this.editedItem = Object.assign({}, this.defaultItem);
this.editedIndex = -1;
}, 300);
},
save() {
if (this.editedIndex > -1) {
Object.assign(this.agents[this.editedIndex], this.editedItem);
} else {
this.agents.push(this.editedItem);
}
this.close();
}
}
}

I need to add a function to pull the id from the row. then use that id to push the row into another array.
added:
addItem(item) {
this.newAgentId(item.id);
console.log(item);
confirm("Are you sure you want to add this item?") &&
this.agents.push(item);
},
newAgentId(keyID) {
if (this.selectedRows.includes(keyID)) {
this.selectedRows = this.selectedRows.filter(
selectedKeyID => selectedKeyID !== keyID
);
} else {
this.selectedRows.push(keyID);
}
}

Related

cannot get all elements of array using Axios get in Javascript (Loop through an array in JavaScript)

/*
My task is to get the user's daily work activity information from the API on this localhost page. If the user is involved in several projects, it is necessary to get more than one line of information instead of just one. My current code is code that can only get the information of the first project from the API. In this case, only one line of information can be displayed as shown in the attached photo below. I want to display more than one line of information. Maybe because the list "time_cards" looks like "time_cards [0]", I can only get the first element. I'm guessing, "Loop through an array in JavaScript" I think this method works, but I don't know how to fix the code.
Please help me guys.*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.6/vue.js"></script>
<template>
<v-container class="container-padding">
<v-breadcrumbs class="px-0 pt-0" large>
<span class="breadcrumb-line rounded-pill mr-2"></span>
<v-breadcrumbs-item class="text-h5 mr-5">Timecard</v-breadcrumbs-item>
<span class="breadcrumb-divider rounded-pill mr-5"></span>
<v-breadcrumbs-item class="text-h6">View</v-breadcrumbs-item>
</v-breadcrumbs>
<v-card>
<v-container fluid>
<v-row>
<v-col cols="3">
<v-subheader>Insert your search date</v-subheader>
</v-col>
<v-col cols="3">
<v-layout row wrap justify-space-around>
<v-flex xs4 md3>
<v-text-field v-model="calendarVal" label="Date" type="date" value="2022-02-05"></v-text-field>
</v-flex>
<v-flex xs4 md3>
<v-btn #click="fetchWorkerTimeCard">enter</v-btn>
</v-flex>
</v-layout>
</v-col>
</v-row>
</v-container>
<v-data-table v-if="worker_time_card.length > 0" :headers="headers" :items="worker_time_card"></v-data-table>
</v-card>
</v-container>
</template>
<script>
export default {
data() {
return {
worker_time_card: [],
calendarVal: new Date().toISOString().substr(0, 10),
headers: [
{ text: 'Start Time', value: 'start_time' },
{ text: 'end_time', value: 'end_time' },
{ text: 'rest_time', value: 'rest_time' },
{ text: 'worked_time', value: 'worked_time' },
{ text: 'duration', value: 'duration' },
{ text: 'work_log', value: 'work_log' },
{ text: 'project_id', value: 'project_id' },
],
}
},
computed: {
calendarDisp() {
return this.calendarVal
},
},
mounted() {
// this.fetchWorkerTimeCard()
},
methods: {
submit() {
console.log(this.calendarVal)
},
compare(a, b) { //hamgiin suuliin uduriig ni deer ni
if (a.timesheet_date < b.timesheet_date) {
return -1
}
if (a.timesheet_date > b.timesheet_date) {
return 1
}
return 0
},
async fetchWorkerTimeCard() {
if (this.calendarVal == null) {
// get today
} else {
try {
await this.$axios.$get('/worker_time_card', { params: { work_date: this.calendarVal } }).then(data => {
console.log(data)
this.worker_time_card.push( {
start_time: data.start_time,
end_time: data.end_time,
rest_time: data.rest_time,
worked_time: data.worked_time,
duration: data.time_cards[0].duration, //worklogoo nemeh , axios - thenn ,try catch,
work_log: data.time_cards[0].work_log, //worklogoo nemeh , axios - thenn ,try catch, axios iin doc sain unsh, tutorial uz
project_id: data.time_cards[0].project_id, //worklogoo nemeh , axios - thenn ,try catch, axios iin doc sain unsh, tutorial uz
})
})
} catch (error) {
console.log(error)
this.worker_time_card = []
}
}
},
},
}
</script>
front end local host page image herecom/YxSjG.png
Ah, you are returning an object. But not an array of objects. So you have to pass in
Object_values()
in the api call. So something like this:
async fetchWorkerTimeCard() {
if (this.calendarVal == null) {
// get today
} else {
try {
await this.$axios.$get('/worker_time_card', { params: { work_date: this.calendarVal } }).then(Object_values(data) => {
this.worker_time_card.push( {
start_time: data.start_time,
end_time: data.end_time,
rest_time: data.rest_time,
worked_time: data.worked_time,
duration: data.time_cards[0].duration,
work_log: data.time_cards[0].work_log,
project_id: data.time_cards[0].project_id,
})
})
} catch (error) {
console.log(error)
this.worker_time_card = []
}
}
},

I want to add editing functions using Nuxt.js

What I want to come true
I am creating TodoLists.
I tried to implement the following editing features, but it didn't work and I'm having trouble.
Click the edit button to display the edit text in the input field
If you click the save button after entering the changes in the input field, the changes will be reflected in the first position.
Code
<v-row v-for="(todo,index) in todos" :key="index">
<v-text-field
filled
readonly
:value="todo.text"
class="ma-3"
auto-grow
/>
<v-menu
top
rounded
>
<template #activator="{ on, attrs }">
<v-btn
v-bind="attrs"
icon
class="mt-6"
v-on="on"
>
<v-icon>
mdi-dots-vertical
</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item
link
>
<v-list-item-title #click="toEdit(todos)">
<v-icon>mdi-pencil</v-icon>
Edit
</v-list-item-title>
</v-list-item>
</v-list>
<v-list>
<v-list-item
link
>
<v-list-item-title #click="removeTodo(todo)">
<v-icon>mdi-delete</v-icon>
Delete
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-row>
<v-text-field
v-model="itemText"
filled
color="pink lighten-3"
auto-grow
#keyup.enter="addTodo"
/>
<v-btn
:disabled="disabled"
#click="addTodo"
>
Save
</v-btn>
data () {
return {
editIndex: false,
hidden: false,
itemText: '',
items: [
{ title: 'Edit', icon: 'mdi-pencil' },
{ title: 'Delete', icon: 'mdi-delete' }
]
}
},
computed: {
todos () {
return this.$store.state.todos.list
},
disabled () {
return this.itemText.length === 0
}
},
methods: {
addTodo (todo) {
if (this.editIndex === false) {
this.$store.commit('todos/add', this.itemText)
this.itemText = ''
} else {
this.$store.commit('todos/edit', this.itemText, todo)
this.itemText = ''
}
},
toEdit (todo) {
this.editIndex = true
this.itemText = this.todos
},
removeTodo (todo) {
this.$store.commit('todos/remove', todo)
}
}
}
</script>
export const state = () => ({
list: []
})
export const mutations = {
add (state, text) {
state.list.push({
text
})
},
remove (state, todo) {
state.list.splice(state.list.indexOf(todo), 1)
},
edit (state, text, todo) {
state.list.splice(state.list.indexOf(todo), 1, text)
}
}
Error
Click the edit button and it will look like this
What I tried myself
//methods
toEdit (todo) {
this.editIndex = true
this.itemText = this.todos.text //add
},
// Cannot read property 'length' of undefined
For some reason I get an error that I couldn't see before
The properties/data types in your code are a bit mixed up.
Here you're accessing state.todos.list...
todos () {
return this.$store.state.todos.list
},
...but in your store the const state doesn't include todos:
export const state = () => ({
list: []
})
Furthermore, you're writing to itemText the content of todos, which should be a string but actually is an object - which leads to the output of [object Object].
toEdit (todo) {
this.editIndex = true
this.itemText = this.todos
},
Also, please check out kissu's comment about the mutations.

Vuetify v-dialog not showing the second time

I'm trying to to conditionally show a dialog. The dialog shows up the first time just fine.
But when second time I try to remount the component I can't see the dialog.
The dialog also fetches some data when it is mounted. I can see the logs that the dialog is being mounted and unmounted and also the network request on chrome devtools network tab but I can't see the dialog.
index.vue
<v-list-item-title #click="changeDialogState">
<TestDialog
v-if="showEditDialog"
:id="item.id"
#editDone="changeDialogState"/>
Edit
</v-list-item-title>
------------------------
//This is defined inside methods
changeDialogState() {
this.showEditDialog = !this.showEditDialog // this.showEditDialog is just a boolean value define inside data()
},
Testdialog.vue
<template>
<v-dialog v-model="dialog" width="700">
<v-progress-circular
v-if="fetching"
:size="70"
:width="7"
color="purple"
indeterminate
></v-progress-circular>
<v-card v-else>
<v-card-title> New Customer </v-card-title>
<v-divider></v-divider>
<v-card-text>
<customer-form
v-model="customer"
:errors="errors"
:initial-customer="customer"
#submit="editCustomer"
>
<template v-slot:footer>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn text #click="$emit('editDone')"> Cancel </v-btn>
<v-btn color="primary" type="submit" class="ma-1">
Save Customer
</v-btn>
</v-card-actions>
</template>
</customer-form>
</v-card-text>
</v-card>
</v-dialog>
</template>
<script>
import { formHandling, paginatedResponse } from '~/mixins'
export default {
mixins: [formHandling, paginatedResponse],
props: {
value: {
type: Object,
default: () => ({
//some stuff here
}),
},
error: {
type: Array,
required: true,
default: () => {
return []
},
},
id: {
type: String,
required: true,
},
},
async fetch() {
this.fetching = true
this.customer = await this.$axios.$get(`/customer/${this.id}/`)
this.fetching = false
},
data() {
return {
dialog: true,
customer: {
...
},
errors: {
...
},
fetching: true,
}
},
mounted() {
console.log('TestDialog - mounted')
},
beforeDestroy() {
console.log('TestDialog - unmounted')
},
methods: {
async editCustomer(customer) {
try {
await this.$axios.$put(`/customer/${this.id}/`, customer)
this.dialog = false
} catch (err) {
this.setErrors(err)
}
},
},
}
</script>

Add/Edit list item at parent from child component form

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>

Problem in POST and PUT request, with axios, vuetify datatable, vuejs

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!