Vuejs 2 Form Saves Twice - vue.js

I'm trying to save data with VueJS to a Go backend API.
When I click submit, the data is saved twice. I've tried to prevent this but something is missing.
I've tested the endpoint with Postman and it's saving normally.
Here is the component:
<template>
<div class="row">
<form #submit.prevent="PostDominio">
<hr />
<label id="lbldom">Dominio </label>
<input v-model="form.Titulo" type="text" />
<button
id="sendom"
class="btn btn-outline-primary btn-sm shadow-sm p-1 mb-1"
#click="PostDominio"
>
Gravar
</button>
<hr />
</form>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
form: {
Titulo: '',
},
}
},
methods: {
PostDominio() {
axios
.post('http://localhost:3000/dominios', this.form)
.bind(this)
.catch((error) => {
console.log(error)
})
},
},
}
</script>

I added e.preventDefault to the PostDominio(e) function and it solved my issue!

Related

How to submit a form data using vue composition api with ajax

I had a form which contain several radio input type, when I try to submit the form data to mongoDB, it failed. Something wrong in onSubmit? Thanks!
The form:
<form #submit="onSubmit">
<fieldset>
<legend>What is your favourite Color? </legend>
<div>
<div><input type="radio" name="color" value="Red" checked><label>
Red</label>
</div>
<div><input type="radio" name="color" value="Blue"><label>
Blue</label>
</div>
</fieldset>
<button type="submit" class="btn btn-primary">Submit Survey</button>
</form>
Vue:
<script>
import { ref, onMounted } from "vue";
export default {
name: 'SurveyView',
setup() {
const onSubmit = (event) => { fetch("/survey", {
method: "post",
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(event.target.value)
})};
onMounted();
return {
onSubmit
}
}
You aren't binding any data property to your template. You can use v-model to bind your radio button then use the data to submit to server/db.
<script type="importmap">
{
"imports": {
"vue": "https://unpkg.com/vue#3/dist/vue.esm-browser.js"
}
}
</script>
<div id="app">
<form #submit.prevent="onSubmit">
<fieldset>
<legend>What is your favourite Color?</legend>
<div>
<div>
<input type="radio" name="color" value="Red" v-model="color" /><label>
Red</label
>
</div>
<div>
<input
type="radio"
name="color"
value="Blue"
v-model="color"
/><label> Blue</label>
</div>
</div>
</fieldset>
<button type="submit" class="btn btn-primary">Submit Survey</button>
</form>
</div>
<script type="module">
import { createApp, ref } from 'vue'
createApp({
name: "App",
setup() {
const color = ref(null);
const onSubmit = () => {
console.log(color.value);
// make server call with appropriate data
};
return { color, onSubmit };
},
}).mount('#app')
</script>

how can I update a vue child-component from the vuex-store

My application shows a window where player can enter name and passcode to enter
When the player exists and has a card, I want to show the card as well.
When the player exists, I make the card visible. Then in 'created'I call fetchSpelerCards. This is successful but shows in the VUE console as pending...
I hope some experienced vue user reads this and can help me with a hint, reference or explanation.
For that I have in the following code:
<h2>Meld je aan</h2>
<form #submit.prevent="register" class="mb-3">
<div class="form-group">
<input type="text" class="form-control m-2" placeholder="naam" v-model="name">
</div>
<div class="form-group">
<input type="text" class="form-control m-2" placeholder="kies inlogcode" v-model="pass_code">
</div>
<button type="submit" #click="checkSpeler()" class="btn btn-primary btn-block" style="color:white">Save</button>
</form>
<p class="alert alert-danger" v-if="errorMessage !== ''"> {{errorMessage}} </p>
<p class="alert alert-success" v-if="successMessage !== ''"> {{successMessage}} </p>
<CardsSpeler v-if="spelerCorrect"></CardsSpeler>
</div>
</template>
The component looks as follows:
<h2>Cards 1</h2>
<form #submit.prevent="addCard" class="mb-3">
<div class="form-group">
<input type="text" class="form-control" placeholder="title" v-model="card.title">
</div>
<div class="form-group">
<textarea class="form-control" placeholder="description" v-model="card.description">
</textarea>
</div>
<div>
<input type="file" v-on:change="onFileChange" ref="fileUpload" id="file_picture_input">
</div>
<button type="submit" class="btn btn-primary btn-block" style="color:white">Save</button>
</form>
<div class="card card-body mb-2" v-for="card in cards" v-bind:key="card.id">
<h3> {{currentSpelerCard.title}} </h3>
<p> {{currentSpelerCard.description}}</p>
<img class="img-circle" style="width:150px" v-bind:src="currentSpelerCard.picture" alt="Card Image">
</div>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
export default {
mounted(){
console.log('component mounted');
},
computed: {
...mapState([
'currentSpeler' ,'currentSpelerCard'
]),
},
data() {
return{
cardExists:false,
successMessage:'',
errorMessage:'',
}
},
created(){
this.fetchSpelerCards();
},
methods: {
...mapActions([ 'getGames', 'addGame', 'fetchSpelerCards' ]),
fetchSpelerCards(){
this.$store.dispatch('fetchSpelerCards', this.currentSpeler.speler.id )
.then(res => {
this.cardExists = true;
this.successMessage = res;
console.log(res);
})
.catch(err => {
this.errorMessage = err;
this.cardExists = false;
});
},
The corresponding action, in actions.js is:
export const fetchSpelerCards = ({commit}, speler_id) => {
return new Promise((resolve, reject) => {
let status = '';
let data ={};
fetch(`api/cardsBySpeler/${speler_id}`)
.then(res => {
status = res.status;
data = res.json();
})
.then(res=>{
if ( status === 200) {
commit('SET_PLAYER_CARD', data);
resolve('Kaart gevonden');
}
else {
reject('Er is geen kaart beschikbaar')
}
});
})
}
In the vuex-store I see (viewed with VUE add-on of chrome browser):
currentSpelerCard: Promise
Yet, the response of the fetch command was successful, and the card was pulled in, as I see also in the console: status 200, I can see name, title, image address etc..
I was under the assumption that, when the promise eventually resolves, the store is updated and the card becomes available because of the:
computed: { ...mapState([ 'currentSpeler' ,'currentSpelerCard' ]),
Can anyone help me and explain what I am doing wrong?
fetchSpelerCards in Vuex commits SET_PLAYER_CARD with data, this will be a pending promise. You need to await the promise.
You can solve this in a few different ways.
Making the function async and await res.json() would be the easiest.
...
fetch(`api/cardsBySpeler/${speler_id}`)
.then(async res => {
status = res.status;
data = await res.json();
})
...

How to access prop by property name from in vuejs

I want to access the error message returned from my api if error exists for its corresponding input field. With what I have tried, all errors returned from the api shows below all input fields as in the image below.
Below are the parent and child vue components.
InputField.vue
<template>
<div class="form-group basic">
<div class="input-wrapper">
<label class="label" :for="name">{{label}}</label>
<input :type="type"
class="form-control"
:class="errorClassObject()"
:id="name" :placeholder="placeholder"
:v-model="value" #input="updateField">
<i class="clear-input">
<ion-icon name="close-circle" role="img" class="md hydrated" aria-label="close circle"></ion-icon>
</i>
</div>
<div v-text="errorMessage(name)" class="input-info text-danger">Error here</div>
</div>
</template>
<script>
export default {
name: "InputField",
props: [
'name', 'value', 'type', 'label', 'placeholder', 'errors'
],
data: function() {
return {
}
},
computed: {
hasError: function(){
return this.errors
//return this.errors.name throws an error name is undefined
}
},
methods: {
updateField (){
this.$emit('input', event.target.value)
},
errorMessage(name){
if(this.hasError){
return this.errors;
//return this.errors.name throws undefined name
}
},
errorClassObject (){
return{
'error-field': this.hasError
}
}
}
}
</script>
<style scoped>
</style>
ChangePassword.vue
<template>
<form #submit.prevent="onSubmit">
<form-input
required
name="current_password"
type="password"
label="Current Password"
:errors="errors"
placeholder="Enter current password"
v-model="passwordForm.current_password"
/>
<form-input .../>
<form-input.../>
<div class="form-button-group transparent">
<button type="submit" class="btn btn-primary btn-block btn-lg">Update Password</button>
</div>
</form>
</template>
Presently, if there are any errors from the request, the response is returned in the format below
You could get access to it using the square brackets like :
errorMessage(name){
if(this.hasError){
return this.errors[name];
}
},

Vee-Validate Showing a BlankPage when doing the configurations

I using Vue3.0 and also use Vee-validate to validate my form. But I don't know why it keep showing blank page just like in this picture
I already do what they said in the documentations, here's my code
<form class="wrap" id="signup-form col-lg-5" #submit.prevent="processForm">
<div class="row mb-5">
<router-link :to="{'name': 'Home'}">
<span class="iconify" data-icon="ion:return-up-back-outline" data-width="25" data-height="25"></span>
<button class="btn">Back</button>
</router-link>
</div>
<!-- full name -->
<div class="form-group row">
<label for="name">Full Name <span class="text-danger">*</span></label>
<ValidationProvider rules="positive|odd" v-slot="err">
<input type="text" class="form-control" v-model.trim="name">
<span>{{ err.errors[0] }}</span>
</ValidationProvider>
</div>
<!-- submit button -->
<div class="row d-flex align-items-center">
<button type="submit" class="btn btn-outline-dark col-sm-4">Submit</button>
<p style="cursor:pointer;" class="col-sm-7">
<router-link :to="{name:'Login'}">Has an account? Login</router-link>
</p>
</div>
</form>
And here's my script
<script>
import { ValidationProvider } from 'vee-validate';
import { extend } from 'vee-validate';
extend('odd', value => {
return value % 2 !== 0;
});
extend('positive', value => {
return value >= 0;
});
export default {
name: 'RegisterForm',
components: {
ValidationProvider
},
data: function(){
return{
name: '',
}
},
methods: {
processForm() {
this.$emit('form-submit',
{
'name': this.email,
'password': this.password,
})
}
}
}
</script>
What should I change from the code? By the way, Is Vee-Validator should be assigned in main.js?
Looks like you are using vee-validate v3.x, it isn't compatible with Vue 3
vee-validate v4 was released recently that supports Vue 3, but with a completely different API
https://vee-validate.logaretm.com/v4/

Show child component when promise data is exists and also render the data in child omponent

I am trying to implement search component for my application, parent component have the search text box and button. When the user provide some value i want to send the data to api and show the result in child component. I am bit confused where to call the api and also how to populate the data in child component. Also, initially my child component should not render in the parent component, when the search get some result then it can render. Please help me how to implement a search functionality in vue js 2.
Parent Component
<template>
<div><h3> Search </h3></div>
<div class="row">
<form role="search">
<div class="form-group col-lg-6 col-md-6">
<input type="text" v-model="searchKey" class="form-control">
</div>
<div class="col-lg-6 col-md-6">
<button type="button" id="btn2" class="btn btn-danger btn-md" v-on:click="getInputValue">Search</button>
</div>
</form>
</div>
<result :searchdataShow='searchData'></result>
</template>
<script>
import resultView from './result'
export default {
components: {
'result': resultView
},
data () {
return {
searchKey: null,
searchData: null
}
},
methods: {
getInputValue: function(e) {
console.log(this.searchKey)
if(this.searchKey && this.searchKey != null) {
this.$http.get('url').then((response) => {
console.log(response.data)
this.searchData = response.data
})
}
}
}
</script>
Search Result component(child component)
<template>
<div>
<div class="row"><h3> Search Results</h3></div>
</div>
</template>
<script>
export default {
props: ['searchdataShow']
}
</script>
Create a boolean variable that keeps track of your ajax request, i usually call it loading, or fetchedData, depending on the context. Before the ajax call, set it to true, after the call, set it to false.
Once you have this variable working, you can then conditionally render the result component with v-if. I like to show a loading icon with the corresponding v-else.
Also your template doesn't seem to have a root element, which is required.
<template>
<div><h3> Search </h3></div>
<div class="row">
<form role="search">
<div class="form-group col-lg-6 col-md-6">
<input type="text" v-model="searchKey" class="form-control">
</div>
<div class="col-lg-6 col-md-6">
<button type="button" id="btn2" class="btn btn-danger btn-md" v-on:click="getInputValue">Search</button>
</div>
</form>
</div>
<result v-if="!loading" :searchdataShow='searchData'></result>
<div v-else>loading!!</div>
</template>
<script>
import resultView from './result'
export default {
components: {
'result': resultView
},
data () {
return {
loading: false,
searchKey: null,
searchData: null
}
},
methods: {
getInputValue: function(e) {
console.log(this.searchKey)
this.loading = true;
if(this.searchKey && this.searchKey != null) {
this.$http.get('url').then((response) => {
console.log(response.data)
this.loading = false;
this.searchData = response.data
})
}
}
}
</script>