How can I call the edit component within another file? - vue.js

I have a project and this project is for the owners of the purchase for the purchase of cars and many other operations, but I have a table with several columns, and within these columns there is a column I listen to action and this column contains a button called Edit and I want when I click on the Edit button to be used The component of the modification within this file, how can I do this?
And it is the Edit file in which the Edit form is located.
Edit.vue:
<template>
<v-row justify="center">
<v-dialog v-model="editDialog" persistent max-width="1050px" height="400px">
<template v-slot:activator="{ on, attrs }">
<v-btn
fab
accent
class="grey lighten-1 margin pa-4"
dark
v-bind="attrs"
v-on="on"
>
<v-icon>
mdi-pencil
</v-icon>
</v-btn>
</template>
<v-card>
<v-layout>
<v-flex xs12>
<div class="myfont pl-5">
<v-card-title>
<span> Edit Car</span>
</v-card-title>
</div>
</v-flex>
</v-layout>
<v-divider xs12></v-divider>
<v-layout>
<v-flex xs12>
<v-card-text>
<v-container>
<v-row>
<v-col cols="12">
<v-text-field
name="name"
label="Name"
id="name"
class="colorLabel"
v-model="editedName"
multi-line
required
></v-text-field>
</v-col>
<v-col cols="12">
<v-text-field
name="priceOfSale"
label="Price Of Sale"
id="priceOfSale"
v-model="editedPrice"
class="colorLabel"
multi-line
required
></v-text-field>
</v-col>
<v-col cols="12">
<v-text-field
name="numberOfSeats"
label="NumberOfSeats"
id="numberOfSeats"
v-model="editedNumberOfSeats"
multi-line
required
></v-text-field>
</v-col>
</v-row>
</v-container>
</v-card-text>
</v-flex>
</v-layout>
<v-divider></v-divider>
<v-layout>
<v-flex xs12>
<v-card-actions>
<v-btn class="myfont pl-5 text-right" text #click="onSaveChanges">
Save
</v-btn>
<v-btn
class="myfont pl-5 text-center"
text
#click="editDialog = false"
>
Cancel
</v-btn>
</v-card-actions>
</v-flex>
</v-layout>
</v-card>
</v-dialog>
</v-row>
</template>
<script>
import { mapActions } from "vuex";
import ActionsTypes from "../store/types/actions-types";
export default {
props: ["car"],
data() {
return {
editedName: this.car.name,
editedPrice: this.car.price,
editedNumberOfSeats: this.car.seatsNumber,
};
},
methods: {
...mapActions({
editCarInformations: ActionsTypes.EDIT_CAR_ACTION,
}),
onSaveChanges() {
const UpdatedCar = { ...this.car };
UpdatedCar.name = this.editedName;
UpdatedCar.price = this.editedPrice;
UpdatedCar.seatsNumber = this.editedNumberOfSeats;
this.editCarInformations(UpdatedCar);
},
},
};
</script>
This file, in which there is a table containing several columns, and the last column is Action, which contains the Modify button, the Modify button, and when I press it, the universe of the amendment is called.
viewAllCars:
<template>
<v-app class="bg">
<v-container>
<v-card
class="mx-auto mt-5 pa-3"
max-width="100%"
id="limited-products"
:style="'border: 0px solid #D50000;'"
>
<v-btn class="red accent-4 color myfont pl-3" #click="onCreateCar">
evict Cashig
</v-btn>
<v-data-table
:headers="tableHeaders"
:items="loadedCarsGetter"
:page.sync="page"
:items-per-page="itemsPerPage"
hide-default-footer
class="elevation-1"
#page-count="pageCount = $event"
>
<template #[`item.actions`]="{ item }">
<v-btn icon #click="edit(item.id)">
<v-icon>mdi-pencil</v-icon>
</v-btn>
<v-btn icon #click="delete (item.id)">
<v-icon>mdi-delete</v-icon>
</v-btn>
</template>
</v-data-table>
<!-- pagination -->
<div class="text-center pt-2">
<v-pagination v-model="page" :length="pageCount"></v-pagination>
<v-text-field
:value="itemsPerPage"
label="Items per page"
type="number"
min="-1"
max="15"
#input="itemsPerPage = parseInt($event, 10)"
class="pl-7 pr-7"
></v-text-field>
</div>
</v-card>
</v-container>
</v-app>
</template>
<script>
import { mapActions, mapGetters } from "vuex";
import ActionsTypes from "../../store/types/actions-types";
import GettersTypes from "../../store/types/getters-types";
export default {
data() {
return {
page: 1,
pageCount: 0,
itemsPerPage: 10
};
},
created() {},
computed: {
...mapGetters({
loadedCarsGetter: GettersTypes.GET_CAR_FORM_GETTER,
tableHeaders: GettersTypes.GET_HEADERS_TABLE_GETTER,
}),
},
mounted() {
// this.loadedCarsGetter();
this.loadedCarsAction();
},
methods: {
...mapActions({
editcardispatcher: ActionsTypes.EDIT_CAR_ACTION,
deletecardispatcher: ActionsTypes.DELETE_CAR_ACTION,
loadedCarsAction: ActionsTypes.GET_ALL_CAR_ACTION
}),
edit() {
this.editcardispatcher({});
},
delete(){
this.deletecardispatcher(
this.car.id
)
}
},
};
</script>

First of all, you don't need the "v-row" in the Edit.vue. Remove it.
As you have the button as the activator, you should just add the component as Avraham mentioned. But you need to know that there are some caveats with this approach
This is gonna be increasing the memory usage by the browser. As a separate instance of Edit.vue will be added to the DOM for each row in your table.
Each Edit.vue instance will preserve the data in it with the changes that the user might make. And you'll have to handle the data resets.
A better solution would be to add only one instance of Edit.vue and add/remove the component from the DOM using a v-if.
This will keep your table using one instance of Edit.vue, and the addition and removal of the component will handle the data reset.
Something like this
In the file that contains the v-data-table, update the template as follows
<template>
......
<v-data-table ...>
...
<template #[`item.actions`]="{ item }">
<v-btn icon #click="edit(item.id)">
<v-icon>mdi-pencil</v-icon>
</v-btn>
<v-btn icon #click="delete(item.id)">
<v-icon>mdi-delete</v-icon>
</v-btn>
</template>
...
</v-data-table>
<edit :car="item" v-if="showEditDialog = true" #closed="showEditDialog = false" />
......
</template>
<script>
import Edit from 'Edit.vue'
export default {
components: { Edit },
data: () =({
item: {},
showEditDialog: false,
}),
methods: {
edit(item) {
this.item = item
this.showEditDialog = true
}
}
}
</script>
In your Edit.vue, add a watcher for the "editDialog" property to emit an event to remove the edit dialog from the DOM.
watch: {
editDialog(val){
if(!val)
this.$emit('closed')
}
}
And remove this part from the Edit.Vue
<template v-slot:activator="{ on, attrs }">
<v-btn
fab
accent
class="grey lighten-1 margin pa-4"
dark
v-bind="attrs"
v-on="on"
>
<v-icon>
mdi-pencil
</v-icon>
</v-btn>
</template>
Good luck.

You should import the Edit.vue component in the car viewer component and use it instead of the edit button:
...
<template #[`item.actions`]="{ item }">
<!-- Pass the item to the `car` prop -->
<edit :car="item" />
<v-btn icon #click="delete (item.id)">
<v-icon>mdi-delete</v-icon>
</v-btn>
</template>
...
<script>
import Edit from 'Edit.vue' // make sure the path to the component is correct
export default {
components: { Edit },
...
};
</script>

Related

Vuetify v-dialog would not open - :value property does not work

I just tried to create a separate form using Vue and vuetify's v-dialog. Unfortunately, once taken into separate component the thing stopped working without any error.
Here's the code to my component:
<template>
<v-dialog :value="dialogOpen" persistent>
<template v-slot:activator="{ props }">
<v-btn color="primary" v-bind="props">Add new</v-btn>
</template>
<v-card>
<v-card-title>
<span class="text-h5">Subscriber</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col cols="12" sm="6">
<v-text-field v-model="activeSubscriber.name" label="Name" required></v-text-field>
</v-col>
<v-col cols="12" sm="6">
<v-text-field v-model="activeSubscriber.email" label="Email" required></v-text-field>
</v-col>
<v-col cols="12" sm="6">
<v-select
v-model="activeSubscriber.state"
:items="['active', 'unsubscribed', 'junk', 'bounced', 'unconfirmed']"
label="State*"
required>
</v-select>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue-darken-1" variant="text">
Close
</v-btn>
<v-btn color="blue-darken-1" variant="text" #click="createSubscriber(activeSubscriber)">
Save
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
name: 'SubscriberForm',
props: {
id: null,
dialogOpen: false,
},
methods: {
createSubscriber(subscriber) {
this.$store.dispatch('subscribers/createSubscriber', subscriber).then(() => this.dialogOpen = false).then(() => alert(1));
}
},
watch: {
id: function(newId) {
if (newId !== null) {
this.$store.dispatch('subscribers/getSubscriber', newId);
}
},
},
computed: {
...mapGetters('subscribers', ['activeSubscriber']),
}
}
</script>
Basically, the only thing that I changed compared to examples on their website was switch v-model to :Value because we are actually passing the properties to the component.
The component is called like that
<SubscriberForm :id="subscriberId" :dialog-open="dialogOpen"/>
....
methods: {
openEditModal(id) {
this.subscriberId = id;
this.dialogOpen = true;
},
},
I tried watching the property dialogOpen and it gets passed perfectly fine.
What could be the issue?
UPDATE: tried the top voted solution at vuetify: programmatically showing dialog
It resolved the issue, however broke the activator button. So that does not fly as well

Passing props from parent component to child component on dialog box vue

So I want to bind batch_code data from dashboard.vue parent to review.vue child component
so, the dashboard contains details like the batch_code, then I have trouble passing the data to the review component, of which it will get the batch_code upon clicking the "Rate and Review" button
when I did try, I am just getting null values from returning said data. any suggestions?
dashboard.vue
<template>
<div>
<v-col cols="10" class="mx-auto">
<v-card class="pa-4" outlined>
<v-card-title class="pb-0 pt-2">Dashbard</v-card-title>
<div v-if="checkifEmpty()">
<v-row>
<v-col
v-for="item in myBatch.all_batch"
:key="item.batch_code"
cols="6"
>
<v-card class="ma-2" outlined>
<div class="d-flex">
<v-avatar class="ma-3" size="150" tile>
<v-img :src="item.image"></v-img>
</v-avatar>
<div>
<v-card-title class="pb-0 pt-2"
>{{ item.offer }} ({{ item.level }})</v-card-title
>
<v-card-text>
<div class="mt-0">{{ item.techer_name }}</div>
<div class="mt-0">{{ item.batch_name }}</div>
<div class="Heading 6 pb-0">
{{ item.start_date }} -
{{ item.end_date }}
</div>
<div class="subtitle-1 pb-0">{{ item.type }}</div>
</v-card-text>
</div>
<v-btn elevation="3" v-on:click="openReviewDialog"
>Rate and Review!</v-btn
>
</div>
</v-card>
</v-col>
</v-row>
</div>
<div v-else>
<v-card-text class="pb-0 pt-2"
>You have no enrolled offers</v-card-text
>
</div>
</v-card>
</v-col>
<review />
</div>
</template>
<script>
import store from "../../store/index";
import review from "./review"
export default {
name: "Dashboard",
components:{
review,
},
computed: {
myBatch() {
return store.getters.getMyOffers;
},
},
methods: {
checkifEmpty() {
let batch = this.myBatch;
if (batch == null || batch.all_batch.length == 0) {
return false;
} else {
return true;
}
},
openReviewDialog() {
this.$store.dispatch("setreviewDialog");
this.sidebarFront = false;
}
},
};
</script>
<style>
</style>
‍‍‍review.vue
<template>
<v-row justify="center">
<v-dialog v-model="reviewDialog" persistent max-width="900px">
<v-card>
<v-card-title class="justify-center">
<span class="headline font-weight-bold"
>Rate and Review this Course!</span
>
</v-card-title>
<v-card-text>
<v-container fluid>
<v-row>
<v-col cols="12" sm="12" md="12">
<v-form
ref="userReview"
v-model="userReviewForm"
lazy-validation
>
<v-text-field
rounded
outlined
v-model="subject"
label="Subject"
required
></v-text-field>
<v-text-field
rounded
outlined
v-model="batch_code"
label="batch_code"
readonly
></v-text-field>
<v-textarea
rounded
outlined
v-model="review"
counter="250"
label="Review"
required
></v-textarea>
<v-rating v-model="rating">
<template v-slot:item="props">
<v-icon
:color="props.isFilled ? 'orange lighten-1' : 'grey lighten-1'"
size = "30"
#click="handleRatingChange(props)">mdi-star</v-icon>
</template>
</v-rating>
<div>
<v-btn
:loading="loginLoader"
large
block
rounded
elevation="0"
color="primary"
#click="submit"
>
Submit
</v-btn>
</div>
</v-form>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<div class="close"> <v-btn color="error" text #click="closeReviewDialog()"> Close </v-btn></div>
</v-card-actions>
</v-card>
</v-dialog>
</v-row>
</template>
<script>
import store from "../../store/index";
export default {
props: {
item:{
batch_code: null;
}
},
name: "review",
data() {
return {
getters: store.getters,
rating: null
};
},
computed: {
reviewDialog: function () {
return this.getters.getreviewDialog;
},
},
methods: {
closeReviewDialog: function () {
//this.show = false;
//this.$refs.card.hide();
//store.dispatch("removeLoginError");
store.dispatch("setreviewDialog");
},
handleRatingChange(props){
console.log(props.index + 1)
this.rating = props.index +1
}
},
};
</script>
'''
p.s: i don't know if it's different when calling props for a component than to a dialog box.
just update your code like below tips,
openReviewDialog() {
this.$store.dispatch("setreviewDialog", **your_rating_data**);
this.sidebarFront = false;
}
so update your dispatch/action accordingly in store.
and when loading your form just pull data from the store using getter and show on dialog.

how to save user input data in vue

I am creating my first website with Vue so I am creating a website for saving recipes I have a home page where you click to add new recipes and it takes you to a page where you can write your recipes and it will save on the home page kind of like a ( to do list ), so I am having troubles with saving the data that the user inputs. how can I get back the saved data from getters? ps. I know this is very simple but I am new to Vue
here are my codes (newrecp page) :
<template>
<div class="container">
<v-text-field
class="mx-1 my-1"
label=" food name"
color="black"
outlined
v-model="data . title"
></v-text-field>
<v-timeline :dense=" $vuetify . breakpoint . s m And Down">
<v-timeline-item
color="purple lighten-2"
fill-dot
right
>
<v-card>
<v-card-title class="purple lighten-2">
<h2 class="display-1 white--text font-weight-light">Step 1</h2>
</v-card-title>
<v-container>
<v-row>
<v-col cols="12" md="10">
<v-text area
auto-grow
rows="4"
row-height="20"
shaped
v-model="data.one"
></v-text area>
</v-col>
</v-row>
</v-container>
</v-card>
</v-timeline-item>
<v-timeline-item
color="amber lighten-1"
fill-dot
left
small
>
<v-card>
<v-card-title class="amber lighten-1 justify-end">
<h2 class="display-1 mr-4 white--text font-weight-light">Step 2</h2>
</v-card-title>
<v-container>
<v-row>
<v-col cols="12" md="8">
<v-text area
auto-grow
rows="4"
row-height="20"
shaped
v-model="data. two"
></v-text area>
</v-col>
</v-row>
</v-container>
</v-card>
</v-timeline-item>
<v-timeline-item
color="cyan lighten-1"
fill-dot
right
>
<v-card>
<v-card-title class="cyan lighten-1">
<h2 class="display-1 white--text font-weight-light">Step 3</h2>
</v-card-title>
<v-container>
<v-row>
<v-col >
<v-text area
auto-grow
rows="4"
row-height="20"
shaped
v-model="data .three"
></v-text area>
</v-col>
</v-row>
</v-container>
</v-card>
</v-timeline-item>
<v-timeline-item
color="red lighten-1"
fill-dot
left
small
>
<v-card>
<v-card-title class="red lighten-1 justify-end">
<h2 class="display-1 mr-4 white--text font-weight-light">Step 4</h2>
</v-card-title>
<v-container>
<v-row>
<v-col cols="12" md="10">
<v-text area
auto-grow
rows="4"
row-height="20"
shaped
v-model="data .four"
></v-text area>
</v-col>
</v-row>
</v-container>
</v-card>
</v-timeline-item>
</v-timeline>
<v-layout row wrap>
<v-flex mx-3 >
<v-b t n block color="secondary" dark #click="addnew">Save</v-b t n>
</v-flex>
</v-layout>
</div>
</template>
<script>
export default {
data (){
return{
data: {
title:'',
one: '',
two: '',
three: '',
four: '',
}
},
methods: {
addnew(){
let savedrecp = this.data
this.$store.commit('newrecp', savedrecp)
this.$router.push({ path:'/' })
}},
}
</script>
In my store:
state: {
data : [],
},
mutations: {
newrecp(state, data) {
// mutate state
state. data .push(data)
}
},
getters: {
data(s){
return s .data
},
}
Script for my saved recipe page:
<script>
export default {
data (){
return{
data: {
title: '',
one: '',
two: '',
three: '',
four: ''
},
}
},
computed: {
item(){
return this. $store.getters.data
}
},
mounted() {
console.log(this. data);
},
}
</script>
Home page:
<template>
<div class="home">
<v-container grid-list-xs>
<v-btn bottom fixed to="/new" > Click to add new Recipes
<v-icon>fas fa-home</v-icon>
</v-btn>
<v-layout row wrap>
<v-flex xs12 x13 lg12 v-for="(item, index) in data" :key="index">
<v-card
>
<v-list-item three-line>
<v-list-item-content>
<div class="overline mb-4">Recipe </div>
<h1>{{item.title}}</h1>
<v-list-item-title class="headline mb-1">pizza</v-list-item-title>
<v-list-item-subtitle >Greyhound divisely hello coldly fonwderfully</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
<v-card-actions>
<v-btn class="button3" text>remove</v-btn>
<v-btn class="button1" text :to="'/savedrecp/'+item.title">open</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-container>
</div>
</template>
<script>
In general we use two-way bindings on form input, textarea, and select elements inorder to save input data you can read official document here.
regarding you'r code i don't see any problems in it unless there is something that you haven't shared right now you must be able to use you'r data like this:
savedRecipe() {
console.log(this.data) // => you can check you'r data in console.
}
UPDATE
You are trying to modify the vuex state from the vue component, You can not do it. You can only modify vuex store from a mutation.
In you'r store:
mutations: {
addRecipe(state, recipe) {
// mutate state
state.data.push(recipe)
}
and commit to mutation:
savedrecp(){
let savedrecp = this.data
this.$store.commit('addRecipe', savedrecp)
this.$router.push({ path:'/' })
}

Vue.js “Maximum call stack size exceeded” error. Use dialog for child and passing data from parent to child failing

I am working on Vuetify.js and I am a newbie in Vue, I referred this document Vuetify Dialogs for creating dialog and solution of Matheus Dal'Pizzol from this link Open a Vuetify dialog from a component template in VueJS
to separate it to the component.
The result I have child component as dialog as below
Parent
<template>
<v-container fluid>
<v-row dense>
<v-col cols="12">
<v-btn large color="success">Add product</v-btn>
</v-col>
<v-col cols="3" v-for="product in products" :key="product.id">
<v-card class="mx-auto" outlined>
<v-list-item three-line>
<v-list-item-content>
<v-list-item-title class="headline mb-1">{{product.name}}</v-list-item-title>
<v-list-item-subtitle>{{product.title}}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
<v-card-actions>
<v-btn dark color="cyan" #click.stop="showScheduleForm = true">
<v-icon dark>mdi-television</v-icon>
</v-btn>
<v-btn color="primary">Detail</v-btn>
</v-card-actions>
</v-card>
<modal-detail v-model="showScheduleForm" :productDetailInfo="product"></modal-detail>
</v-col>
</v-row>
</v-container>
</template>
<script>
import axios from "axios";
import ModalDetail from "./ModalDetail.vue";
export default {
name: "HelloWorld",
components: {
ModalDetail
},
data: function() {
return {
showScheduleForm: false,
products: [],
errors: []
};
},
...
Child
<template>
<v-dialog v-model="show" max-width="500" v-if="Object.keys(productDetailInfo).length !== 0">
<v-card>
<v-card-title class="headline grey lighten-2" primary-title>{{ productDetailInfo.name }}</v-card-title>
<v-card-text>{{ productDetailInfo.title }}</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="green darken-1" text #click.stop="show = false">Close</v-btn>
<v-btn color="primary">Detail</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
export default {
name: "ModalDetail",
props: {
productDetailInfo: {
type: Object
},
value: Boolean
},
computed: {
show: {
get() {
return this.value;
},
set(value) {
this.$emit("input", value);
}
}
}
};
</script>
However, I am getting an exception when I click icon-button "Maximum call stack size exceeded".
It seems there is a continuous loop happening.
Please help! Am I missing something?
That's because your v-dialog is in v-for loop, it's common problem. To workaround it add :retain-focus="false" as a prop to your v-dialog
Maybe try to use v-on:click.stop instead of #click.stop in the v-btn as it's the recommended syntax for Vue 2.x.

v-layout v-flex with fill-height overflows the screen if i add a second element like v-card or v-toolbar

I have the problem that i want to stack a v-toolbar and a v-calendar and i want that the calendar to takes the remaining space. It works good if i add just calendar, but if i add something else above, the calendar overflows the screen. (See picture the white space at the bottom )
Screenshot:
https://drive.google.com/open?id=1dOU6IMzWHUqZk5H2e-2-zTez-l17FLG5
I'm sure the problem is somewhere withe the fill-height attr., but i don't know how to solve it. Does some on have any idea ?
<template>
<v-container fill-height fluid ma-0 pa-0>
<v-layout row wrap align-content-start>
<v-flex xs12>
<v-toolbar flat>
<v-flex shrink>
<for-and-backward-arrows v-model="selectedDate" />
</v-flex>
</v-toolbar>
</v-flex>
<v-flex shrink>
<MonthOverView #click="setDate" />
</v-flex>
<v-flex fill-height>
<v-calendar
ref="calendar"
type="month"
color="primary"
:start="selectedDate.format('YYYY-MM-DD')"
>
<template v-slot:day="day">
<v-sheet class="d-flex px-1 caption" :color="color"
>day slot</v-sheet
>
</template>
</v-calendar>
</v-flex>
</v-layout>
<AddButtons></AddButtons>
</v-container>
</template>
<script>
import MonthOverView from '#/plugins/Goole-Calendar/src/components/MonthOverView.vue'
import AddButtons from '#/plugins/Goole-Calendar/src/components/AddButtons.vue'
import ForAndBackwardArrows from '#/plugins/Goole-Calendar/src/components/ForAndBackwardArrows.vue'
import moment from 'moment'
export default {
props: {
color: {
type: String,
default: 'primary lighten-3'
}
},
data() {
return {
selectedDate: moment()
}
},
methods: {
setDate(date) {
log.debug(date)
this.selectedDate = date
}
},
components: {
MonthOverView,
AddButtons,
ForAndBackwardArrows
}
}
</script>
I just ran into this myself. Solution was to use flex-column.
<v-content>
<v-row no-gutters class="fill-height">
<v-col class="d-flex flex-column">
<v-toolbar></v-toolbar>
<v-calendar></v-calendar>
</v-col>
</v-row>
</v-content>