How to push data into an array from a v-form? - vue.js

At the moment, I have the following code:
<template>
<v-container>
<v-form v-model="valid" ref="form" v-for="(resposta,index) in formData.body" :key="index">
<v-row>
<v-col cols="8">
<v-text-field
v-model="resposta.answer"
:rules="idRules"
:counter="200"
label="Texto da Resposta"
required
></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col xl="2" lg="3" md="3" sm="4" class="mt-4">
<p class="grey--text text--darken-1">Resposta Correta:</p>
</v-col>
<v-radio-group
v-model="resposta.correction"
row
mandatory
>
<v-col md="4" sm="4">
<v-radio
label="0"
value="0"
></v-radio>
</v-col>
<v-col md="4" sm="4">
<v-radio
label="1"
value="1"
></v-radio>
</v-col>
</v-radio-group>
</v-row>
<v-row>
<v-col xl="2" lg="3" md="3" sm="4" class="mt-4">
<p class="grey--text text--darken-1">Resposta Obrigatória:</p>
</v-col>
<v-radio-group
v-model="resposta.mandatory"
row
mandatory
>
<v-col md="4" sm="4">
<v-radio
label="0"
value="0"
></v-radio>
</v-col>
<v-col md="4" sm="4">
<v-radio
label="1"
value="1"
></v-radio>
</v-col>
</v-radio-group>
</v-row>
<v-row>
<v-col xl="2" lg="3" md="3" sm="4" class="mt-4">
<p class="grey--text text--darken-1">Resposta Eliminatória:</p>
</v-col>
<v-radio-group
v-model="resposta.eliminative"
row
mandatory
>
<v-col md="4" sm="4">
<v-radio
label="0"
value="0"
></v-radio>
</v-col>
<v-col md="4" sm="4">
<v-radio
label="1"
value="1"
></v-radio>
</v-col>
</v-radio-group>
</v-row>
<v-row>
<v-col cols="5">
<v-select :items="pontos"
v-model="resposta.points"
label="Pontos"
dense
></v-select>
</v-col>
<v-col cols="7" align="center">
<v-btn #click="addAnswer" class="white--text" color="#2A3F54" grey--text>
Add Answer
</v-btn> {{formData.body}}
</v-col>
</v-row>
</v-form>
</v-container>
</template>
<script>
export default {
data(){
return{
formData:{
body: [{
answer: '',
correction: '',
mandatory: '',
eliminative: '',
points:''
}]
}
}
},
methods: {
addAnswer(){
this.formData.body.push({answer: '',
correction: '',
mandatory: '',
eliminative: '',
points:''})
alert("inserida")
}
},
watch: {
formData: {
handler: function() {
this.$emit('newdataRespostas', this.formData.body);
},
deep: true
}
},
}
</script>
The goal with this is to be able to get the information in the array in another component, which I'm being able to do. The problem here is that everytime I click on the Add Answer button, it creates a new identical form right under the previous one. The data is being pushed correctly into the array, the other component is being able to watch for the information inside that array, but I'm just not able to get rid of the new forms that get created. If I add 4 new answers, I'll have 5 forms by the end, which is clearly not optimal. Also any tips regarding any part of the code are welcome. I'm completely new to Vue.js and Vuetify.
Sorry for the long code, but almost all of it is just the different form components.

The form uses v-for on formData.body[], so each array element (each answer) renders a new form. It sounds like you want only the newest form to be shown, in which case you don't need v-for.
I would replace the v-for with a different data property (e.g., named resposta to match the current variable used in your template), and append that property to formData.body[] in addAnswer():
<template>
<v-form v-model="valid" ref="form">
<!--...-->
<v-text-field v-model="resposta.answer" />
</v-form>
</template>
<script>
export default {
data() {
return {
formData: {
body: [],
},
resposta: {},
};
},
methods: {
addAnswer() {
this.formData.body.push(this.resposta)
this.resposta = {}
},
},
}
</script>
demo

Related

Vuex store update but DOM is not

I've looked through all the posts about this subject and can't seem to find an answer. My Vuex store IS updating fine, but the DOM is not.
This is a screenshot of what is going on
I have a getter called returnAmazonCredentials
returnAmazonCredentials(state) {
return state.amazonCredentials
},
I import it like this:
computed: {
...mapGetters('amazonCredentials', [
'returnAmazonCredentials',
]),
returnAmazonCredentials is an array and so I use it in my DOM with a v-for
v-for="(cred, index) in returnAmazonCredentials"
And I also use getters and setters to update the elements in the array. Here is one example
sellerId: {
get() {
return this.returnAmazonCredentials.merchant_id
},
set(value) {
this.$set(this.returnAmazonCredentials[this.credIndex], 'merchant_id', value)
}
},
this.credIndex is set when an element is clicked
When I want to remove an element from the returnAmazonCredentials array I do this:
this.returnAmazonCredentials.splice(index, 1)
The Vuex store is updated perfectly, while the DOM still shows old data that no longer exists in the store. I've tried:
this.$nextTick() as well as this.$forceUpdate()
No luck.. Where did I go astray?
EDIT: This is all my code in my component
<template>
<v-container fluid v-resize="getHeight">
<v-row align="center" justify="center">
<v-col cols="12">
<v-card
class="purple_top"
color="#e1bee7"
>
<v-container>
<v-row>
<v-col cols="1" align="start">
<v-icon class="my_dark_purple_text pretty_icon mt-2" x-large>info</v-icon>
</v-col>
<v-col cols="11" align="start">
<h1 class="text-h6 mont bold pt-3 pb-2">You will not be charged until after you've entered all your credentials below</h1>
<h1 class="text-subtitle-1 mont font-weight-bold">After your 7 day free trial your costs will be:</h1>
<v-list class="purple_list" dense>
<v-list-item>
<v-list-item-icon class="mr-2">
<v-icon class="my_dark_purple_text">info</v-icon>
</v-list-item-icon>
<v-list-item-content>
<div class="text-body-1 mont">$25/month for the first marketplace</div>
</v-list-item-content>
</v-list-item>
<v-list-item>
<v-list-item-icon class="mr-2">
<v-icon class="my_dark_purple_text">info</v-icon>
</v-list-item-icon>
<v-list-item-content>
<div class="text-body-1 mont">$20/month for each additional marketplace</div>
</v-list-item-content>
</v-list-item>
</v-list>
</v-col>
</v-row>
</v-container>
</v-card>
</v-col>
</v-row>
<v-row>
<v-col cols="8">
<v-card
color="#f1e7df"
id="devIds"
>
<v-card-title>
<v-icon class="my_dark_purple_text">vpn_key</v-icon>
<h1 class="text-h6 oswald my_dark_purple_text pl-2">DEVELOPMENT IDS</h1>
</v-card-title>
<v-container>
<v-row>
<v-col cols="6" class="ml-10">
<h1 class="text-h6 mont">US, Canada, Mexico</h1>
</v-col>
<v-col cols="5">
<h1 class="text-h6 mont">UK and the EU</h1>
</v-col>
</v-row>
<v-row>
<v-col cols="3" class="ml-10">
<v-text-field readonly solo :value="us" class="mont"></v-text-field>
</v-col>
<v-col cols="3">
<v-btn height="48px" class="my_dark_purple_btn ml-n7" #click="copyCreds(us)">Copy</v-btn>
</v-col>
<v-col cols="3" class="">
<v-text-field readonly solo :value="eu" class="mont"></v-text-field>
</v-col>
<v-col cols="2">
<v-btn height="48px" class="my_dark_purple_btn ml-n7" #click="copyCreds(eu)">Copy</v-btn>
</v-col>
</v-row>
<v-row>
<v-col cols="6" class="ml-10">
<h1 class="text-h6 mont">Australia</h1>
</v-col>
<v-col cols="5">
<h1 class="text-h6 mont">Japan</h1>
</v-col>
</v-row>
<v-row>
<v-col cols="3" class="ml-10">
<v-text-field readonly solo :value="us" class="mont"></v-text-field>
</v-col>
<v-col cols="3">
<v-btn height="48px" class="my_dark_purple_btn ml-n7" #click="copyCreds(australia)">Copy</v-btn>
</v-col>
<v-col cols="3" class="">
<v-text-field readonly solo :value="eu" class="mont"></v-text-field>
</v-col>
<v-col cols="2">
<v-btn height="48px" class="my_dark_purple_btn ml-n7" #click="copyCreds(japan)">Copy</v-btn>
</v-col>
</v-row>
</v-container>
</v-card>
</v-col>
<v-col cols="4">
<v-card
color="#d9d6e1"
:height="matchingHeights + 'px'"
>
<v-container fluid fill-height>
<v-row class="pt-2">
<v-col cols="12" justify="center" align="center">
<a href="https://youtu.be/-iWlFyX0254" target="_blank">
<v-img
src="how.png"
max-width="153px"
contain
></v-img>
</a>
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<h1 class="mont text-h5 text-center">Do I retrieve my US Amazon credentials?</h1>
</v-col>
</v-row>
<v-row>
<v-divider class="mx-4"></v-divider>
</v-row>
<v-row class="pt-2">
<v-col cols="12" justify="center" align="center">
<a href="https://youtu.be/p4RwqegRc9s" target="_blank">
<v-img
src="how.png"
max-width="153px"
contain
></v-img>
</a>
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<h1 class="mont text-h5 text-center">Do I retrieve my Amazon credentials outside of the US?</h1>
</v-col>
</v-row>
</v-container>
</v-card>
</v-col>
</v-row>
<p>credentials are {{ returnAmazonCredentials }}</p>
<v-row
v-for="(cred, index) in returnAmazonCredentials"
:key="index"
>
<v-col cols="12">
<v-card
color="#e9daea"
>
<v-card-title>
<v-icon class="my_dark_purple_text">language</v-icon>
<h1 class="text-h6 oswald my_dark_purple_text pl-2">ENTER YOUR AMAZON CREDENTIALS BELOW</h1>
</v-card-title>
<v-container>
<v-form>
<v-row>
<v-col cols="6">
<v-row>
<v-col cols="12">
<v-text-field
color="#6a0080"
label="Amazon Seller Id"
prepend-icon="person"
v-model="sellerId"
#click="setIndex(index)"
:rules="[() => !!returnAmazonCredentials[credIndex]['merchant_id'] || 'Please provide your Amazon seller id', sellerIdValidation(!!returnAmazonCredentials[credIndex]['merchant_id']) ]"
></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<v-select
:items="marketplaces"
label="Select your Amazon Marketplace"
color="#6a0080"
prepend-icon="map"
v-model="marketplace"
#click="setIndex(index)"
:rules="[() => !!returnAmazonCredentials[credIndex]['marketplace'] || 'Please select your Amazon marketplace', marketValidation(!!returnAmazonCredentials[credIndex]['marketplace']) ]"
></v-select>
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<v-text-field
color="#6a0080"
label="Amazon Auth Token"
prepend-icon="https"
v-model="authToken"
#click="setIndex(index)"
:rules="[() => !!returnAmazonCredentials[credIndex]['auth_token'] || 'Please provide your Amazon auth token', authTokenValidation(!!returnAmazonCredentials[credIndex]['auth_token']) ]"
></v-text-field>
</v-col>
</v-row>
</v-col>
<v-col cols="1">
<v-divider vertical></v-divider>
</v-col>
<v-col cols="5">
<v-row class="mt-1">
<v-btn
color="#68007d"
outlined
block
x-large
:disabled="_.some(errors, (element) => _.includes(element, index))"
#click="saveMarketplace"
:loading="saveLoading"
>
<v-icon
left
>
check_circle
</v-icon>
SAVE THIS MARKETPLACE
</v-btn>
</v-row>
<v-row class="mt-11">
<v-btn
block
x-large
outlined
color="#388E3C"
#click="addMarketplace"
>
<v-icon
left
>
add_circle
</v-icon>
ADD ANOTHER MARKETPLACE
</v-btn>
</v-row>
<v-row class="mt-11">
<v-btn
block
x-large
outlined
color="#B71C1C"
:disabled="returnAmazonCredentials.length == 1"
#click="removeMarketplace(index)"
>
<v-icon
left
>
remove_circle
</v-icon>
REMOVE MARKETPLACE
</v-btn>
</v-row>
</v-col>
</v-row>
</v-form>
<v-row v-if="(returnAmazonCredentials.length - 1) == index">
<v-col cols="12">
<v-btn
class="white--text"
color="#68007d"
block
x-large
#click="sendCreds"
:loading="finishedLoading"
:disabled="errors.length > 0"
id="custom-disabled"
>
FINISHED
</v-btn>
</v-col>
</v-row>
</v-container>
</v-card>
</v-col>
</v-row>
<v-dialog
v-model="failDialog"
max-width="600px"
persistent
>
<v-card>
<v-card-title>
<span class="title font-weight-bold">Oh snap! It looks like your credentials are incorrect</span>
</v-card-title>
<v-card-text>
<v-row>
<v-col cols="12">
<h1
class="subtitle-1"
style="color: black !important;"
>Amazon let us know the following error:</h1>
</v-col>
</v-row>
<v-row
:class="spacing"
v-for="(reason, index) in failReasons"
:key="reason.marketplace"
>
<v-col cols="12">
<h1
class="subtitle-1"
>Your credentials failed in this marketplace: <strong>{{ reason.marketplace }}</strong></h1>
</v-col>
<v-col cols="12" class="mt-n5">
<h1
class="subtitle-1"
>For this reason: <strong>{{ reason.reason }}</strong></h1>
</v-col>
<v-col
cols="12"
justify="center"
align="center"
>
<a :href="whichVideoToShow(reason.marketplace)" target="_blank">
<v-img
src="blank_how.png"
max-width="100px"
contain
></v-img>
</a>
</v-col>
<v-col cols="12" class="mt-n5">
<h1 class="subtitle-1 text-center">Do I retrieve my Amazon credentials?</h1>
</v-col>
<v-divider class="mx-4 mt-3"></v-divider>
</v-row>
</v-card-text>
<v-card-actions class="">
<v-spacer></v-spacer>
<v-btn color="#68007d" large class="white--text" #click="closeDialog">I UNDERSTAND</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-container>
</template>
<script>
import axios from 'axios';
import { mapGetters, mapActions } from 'vuex'
export default {
data: function() {
return {
failDialog: false,
australia: "6078-0648-3237",
us: "7531-9706-4825",
eu: "4048-6340-0484",
japan: "1447-5438-8862",
matchingHeights: 295,
marketplaces:[
{ text: 'Australia', value: "A39IBJ37TRP1C6" },
{ text: 'Canada', value: "A2EUQ1WTGCTBG2" },
{ text: 'France', value: "A13V1IB3VIYZZH" },
{ text: 'Germany', value: "A1PA6795UKMFR9" },
{ text: 'Italy', value: "APJ6JRA9NG5V4" },
{ text: 'Japan', value: "A1VC38T7YXB528" },
{ text: 'Mexico', value: "A1AM78C64UM0Y8" },
{ text: 'Spain', value: "A1RKKUPIHCS9HS" },
{ text: 'United Kingdom', value: "A1F83G8C2ARO7P" },
{ text: 'United States', value: "ATVPDKIKX0DER" },
],
credIndex: 0,
errors: [],
finishedLoading: false,
saveLoading: false,
amazonError: '',
failReasons: [],
};
},
async mounted() {
await this.getRemoteAmazonCredentials()
},
computed: {
...mapGetters('amazonCredentials', [
'returnAmazonCredentials',
]),
sellerId: {
get() {
return this.returnAmazonCredentials.merchant_id
},
set(value) {
this.$set(this.returnAmazonCredentials[this.credIndex], 'merchant_id', value)
}
},
marketplace: {
get() {
return this.returnAmazonCredentials.marketplace
},
set(value) {
this.$set(this.returnAmazonCredentials[this.credIndex], 'marketplace', value)
}
},
authToken: {
get() {
return this.returnAmazonCredentials.auth_token
},
set(value) {
this.$set(this.returnAmazonCredentials[this.credIndex], 'auth_token', value)
}
}
},
methods: {
...mapActions('amazonCredentials', [
'getRemoteAmazonCredentials',
'testRemoteAmazonCredentials',
'removeAmazonCredential'
]),
setIndex(index) {
this.credIndex = index
},
getHeight() {
var devCard = document.getElementById("devIds");
this.matchingHeights = devCard.offsetHeight;
},
copyCreds(country) {
this.$clipboard(country);
},
sellerIdValidation(value) {
if(value){
_.pull(this.errors, `${this.credIndex}-id`)
}
else {
if(!_.includes(this.errors, `${this.credIndex}-id`)) {
this.errors.push(`${this.credIndex}-id`)
}
}
return true
},
marketValidation(value) {
if(value){
_.pull(this.errors, `${this.credIndex}-market`)
}
else {
if(!_.includes(this.errors, `${this.credIndex}-market`)) {
this.errors.push(`${this.credIndex}-market`)
}
}
return true
},
authTokenValidation(value) {
if(value){
_.pull(this.errors, `${this.credIndex}-auth`)
}
else {
if(!_.includes(this.errors, `${this.credIndex}-auth`)) {
this.errors.push(`${this.credIndex}-auth`)
}
}
return true
},
addMarketplace() {
this.returnAmazonCredentials.push({})
},
removeMarketplace(index) {
this.removeAmazonCredential(index)
this.credIndex = 0
},
async sendCreds() {
this.failReasons = []
this.finishedLoading = true
let me = this.returnAmazonCredentials
let response = await this.testRemoteAmazonCredentials()
this.addRemoveTestFailure(response)
},
async saveMarketplace() {
this.failReasons = []
this.saveLoading = true
let response = await this.testRemoteAmazonCredentials()
this.addRemoveTestFailure(response)
},
addRemoveTestFailure(response) {
response.forEach(element => {
if(element.result == "fail") {
this.failDialog = true
let failure = {
reason: element.reason,
marketplace: element.marketplace
}
this.failReasons.push(failure)
}
})
this.saveLoading = false
this.finishedLoading = false
},
closeDialog() {
this.failDialog = false
this.saveLoading = false
},
whichVideoToShow(marketplace) {
if(marketplace == "United States" || marketplace == "Mexico" || marketplace == "Canada") {
return 'https://youtu.be/-iWlFyX0254'
}
else {
return 'https://youtu.be/p4RwqegRc9s'
}
},
spacing() {
if(this.failReasons.length >= 1) {
return mt-n4
}
}
}
};
</script>
<style scoped>
#import '../../styles/global_styles.css';
#custom-disabled.v-btn--disabled {
background-color: rgba(104,0,125,.5) !important;
color: white !important;
}
</style>
I did add this mutation in my store to remove the element
removeCredential: (state, payload) => {
state.amazonCredentials.splice(payload, 1)
},
And this is the method that I've updated in the component itself:
removeMarketplace(index) {
this.removeAmazonCredential(index)
this.credIndex = 0
},
Where I send the index to be removed from the credentials array.
But yea I was already doing that in the component itself, and I'm getting the same effect. Data updated while the DOM is not..
You should dispatch an action that remove that item :
sellerId: {
get() {
return this.returnAmazonCredentials.merchant_id
},
set(value) {
this.$store.dispatch('removeCredential',this.credIndex)
}
},
store :
mutations: {
REMOVE_CREDENTIAL (state,index) {
state.amazonCredentials.splice(index, 1)
}
},
actions: {
removeCredential(context,index) {
context.commit('REMOVE_CREDENTIAL',index)
}
Wow, the answer surprises me. Its basically that if you have an array of objects in your Vuex store, you should NOT use getters / setters if you ALSO are stepping over that array in a v-for instead you can just get / set the values directly.
For example. If you do this:
<v-row
v-for="(cred, index) in myVuexStoreArrayOfObjects"
:key="index"
>
Then you should do this for your v-model
<v-text-field
v-model="cred.value"
></v-text-field>
So that finally you can remove an object from that array and maintain your reactivity. Like so:
removeObjectFromMyVuexStoreArray(index) {
this.myVuexStoreArrayOfObjects.splice(index, 1)
},
And there is no need to get/set. In fact if you get/set you will NOT be able to remove an item and remain reactive.

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:'/' })
}

How to display input with the click of a button in Vue?

I've been reading about text-fields but I can't figure it out.. I want to be able to type in a name and age, and then when I press the button "add", I want to be able to see the name and age displayed below. What is the easiest or best way of doing this?
My code:
<v-container>
<v-row>
<v-col cols="12" sm="6" md="3">
<v-text-field label="Name" solo></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="3">
<v-text-field label="Age" solo></v-text-field>
</v-col>
<div class="addbutton">
<v-btn color="green darken-1" large v-on:click="add">Add</v-btn>
</div>
</v-row>
First you should bind inputs to the component data using v-model.
script:
export default {
data(){
return {
name: null,
age: null
}
}
}
html:
<v-col cols="12" sm="6" md="3">
<v-text-field label="Name" solo v-model="name"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="3">
<v-text-field label="Age" solo v-model="age"></v-text-field>
</v-col>
Now you can display current inputs values: <p>{{ name + ', ' + age }}</p>
If you want to show/hide them with a button, you can add a data property to store their state, create a method to toggle it and bind their visibility to the property using v-if:
script:
export default {
data(){
return {
name: null,
age: null,
showValues: false
},
methods: {
toggle() {
this.showValues = !this.showValues
}
}
}
html:
<v-row>
<v-col cols="12" sm="6" md="3">
<v-text-field label="Name" solo v-model="name"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="3">
<v-text-field label="Age" solo v-model="age"></v-text-field>
</v-col>
<div class="addbutton">
<v-btn color="green darken-1" large #click="toogle">Add</v-btn>
</div>
<p v-if="showValues">{{ name + ', ' + age }}</p>
</v-row>
Store the variables in the data of your vue component and the use it to render
<v-row>
<v-col cols="12" sm="6" md="3">
<v-text-field label="Name" solo></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="3">
<v-text-field label="Age" solo></v-text-field>
</v-col>
<div class="addbutton">
<v-btn color="green darken-1" large v-on:click="add">Add</v-btn>
</div>
<v-col cols="12" sm="6" md="3" v-if="render!==null">
<p>{{ render.name }}</p>
<p>{{ render.age }}</p>
</v-row>
<script>
export default {
data(){
return {
name:null,
age:null,
render:null,
},
methods(){
add(){
const name = this.name;
const age = this.age;
this.render = {
name,
age
}
},
}
}
</script>

Push component in vue

I've been trying to push a text field whenever the "add button" is pressed.
This is my code so far.
<v-container fluid>
<v-row>
<v-col cols="7">
<v-row class= "mx-1 my-1">
<v-text-field outlined label="Test 1" v-model="test1"></v-text-field>
</v-row>
</v-col>
<v-col cols="5">
<v-row class= "mx-4 my-1">
<v-text-field type="number" outlined label="Test 2" v-model="test2"></v-text-field>
</v-row>
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<v-row class= "mx-1 my-n8">
<v-btn
#click="doWork()"
width = 100%
small
outlined
color="#0000b0"
>
<v-icon dark>mdi-plus</v-icon></v-btn>
</v-row>
</v-col>
</v-row>
</v-container>
Here is my javascript
<script>
export default {
data () {
return {
test1:'',
test2:''
}
},
methods: {
doWork () {
//just for debugging purposes
console.log(this.valor)
console.log(this.precio)
}
}
}
</script>
What should I add in the "doWork()" method in order to push another pair of text fields
Thanks in advance <3
You can transform your fields into a fields array:
data () {
return {
inputs: []
}
}
Your addWork method becomes a method that push a new value in this inputs array:
methods: {
doWork () {
this.inputs.push({
label: 'Test',
value: ''
})
}
}
And you display those inputs with a v-for directive:
<v-row>
<v-col cols="2" v-for="(input, index) in inputs" :key="index">
<v-row class="mx-1 my-1">
<v-text-field outlined :label="input.label" v-model="input.value"></v-text-field>
</v-row>
</v-col>
</v-row>
Working example: https://codesandbox.io/s/festive-dream-gbo6t?file=/src/App.vue

How can I combine vue tel input with input text vuetify?

My code like this :
<v-row>
<v-col cols="12" sm="6" md="3">
<v-text-field
label="Phone"
outlined
dense
></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="3">
<vue-tel-input v-model="phone"></vue-tel-input>
</v-col>
</v-row>
My codepen like this : https://codepen.io/positivethinking639/pen/qBBKYON?&editable=true&editors=101
I want to combine it to be like this :
The blue sign is taken from vue tel input. The text field next to it is taken from the vuetify component
How do I combine 2 different components into one like the image above?
Yes, it is possible to set the country code next to dropdown
Here is the working codepen: https://codepen.io/chansv/pen/pooZJey?editors=1010
<div id="app">
<v-app id="inspire">
<v-form>
<v-container>
<v-row>
<v-col cols="12" sm="6" md="3">
<v-text-field
label="Phone"
outlined
dense
></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="3">
<vue-tel-input v-model="phone" #country-changed="countrySelected">
<template v-slot:arrow-icon>
<v-icon>arrow_drop_down</v-icon>
<strong>+{{countryCode}}</strong>
</template>
</vue-tel-input>
</v-col>
</v-row>
</v-container>
</v-form>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
phone: null,
countryCode: null,
}
},
methods: {
countrySelected(val) {
this.countryCode = val.dialCode;
}
}
})