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

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();
})
...

Related

V-model inside v-for is filling all the inputs

In few words I have multiple Todolists, once I try to post a new Todo inside the Todolist all the inputs of other Todolists gets fill in with the same words. How can I solve this?
Edit: I can post a new todo without problems and it will appear on the relative todolist (see addTodo method). The ONLY problem is that the v-model is for all the todolists on the field, not only for the one I'm writing in, so as soon as I start to write inside an input I got all the inputs filled.
<div class="todolist" v-for="todolist in todolists" :key="todolist.id">
<div class="td-title">
<h5 class="text-center m-0 py-2 text-light">
{{ todolist.title }}
</h5>
</div>
<form
#submit.prevent="addTodo(todolist.id)"
class="td-inputs d-flex align-items-center justify-content-center"
>
// this is the v-model
<input v-model="todo.title" class="px-2" type="text" />
<button type="submit">
<i class="fas fa-plus fa-2x"></i>
</button>
</form>
<div>
<div v-for="todo in todolist.todos" :key="todo.id" class="todo">
{{ todo.title }}
</div>
<div>
<i class="fas fa-times" #click="cancel(todolist.id)"></i>
</div>
</div>
</div>
data
data() {
return {
todolists: [],
loading: true,
todo: {
title: "",
todolist_id: "",
user_id: ""
},
};
},
Methods
getTodoLists() {
axios
.get("http://127.0.0.1:8000/api/todolists")
.then((res) => {
this.todolists = res.data;
this.loading = false;
})
.catch((err) => {
console.log(err);
});
},
cancel(id) {
axios
.delete(`http://127.0.0.1:8000/api/todolists/${id}`)
.then(() => {
this.getTodoLists();
})
.catch((err) => {
console.log(err);
});
},
addTodo(todolist) {
axios
.post(`http://127.0.0.1:8000/api/${todolist}/todos`, this.todo)
.then(() => {
this.todo = {}
this.getTodoLists();
})
.catch((err) => {
console.log(err);
});
},
Like down here: I'm writing on the left input and it shows even on the right input.
SOLVED:
With this computed property (with setter and getter) I solved my problem, now just the input in which I'm typing in is filled, and the todo can be post without a problem.
computed: {
getTitle: {
get: function () {
return "";
},
set: function (value) {
this.todo.title = value;
},
},
},
And this is the v-model with the new computed property instead of todo.title
<form
#submit.prevent="addTodo(todolist.id)"
class="td-inputs d-flex align-items-center justify-content-center"
>
<input v-model="getTitle" class="px-2" type="text" />
<button type="submit">
<i class="fas fa-plus fa-2x"></i>
</button>
</form>
You have a variable in data called "todo" and then you are reusing that variable name inside your inner v-for:
<div v-for="todo in todolist.todos" :key="todo.id" class="todo">
{{ todo.title }}
</div>
I think todo is referring to the todo from your data, not from the v-for. Thus, all todo items refer to the same variable. Try to rename one of them and see if it solves the problem.
You are binding your input to your todo declared data object.
Instead, you should bind your input to your todolist object in this way:
<div class="todolist" v-for="todolist in todolists" :key="todolist.id">
....
<input v-model="todolist.title" class="px-2" type="text" />
....
</div>
SOLVED:
With this computed property (with setter and getter) I solved my problem, now just the input in which I'm typing in is filled, and the todo can be post without a problem.
computed: {
getTitle: {
get: function () {
return "";
},
set: function (value) {
this.todo.title = value;
},
},
},
And this is the v-model with the new computed property instead of todo.title
<form
#submit.prevent="addTodo(todolist.id)"
class="td-inputs d-flex align-items-center justify-content-center"
>
<input v-model="getTitle" class="px-2" type="text" />
<button type="submit">
<i class="fas fa-plus fa-2x"></i>
</button>
</form>

Method Updating Data Twice on Form Submission

I have a component that is a form that I input a name and it updates a value on a field on the backend based on which input the name is. Right now I have two inputs (host and scout) and they work fine if I just fill one input. My problem is, when I fill both inputs, the name on the host input will always get updated twice while the name on the scout field will work just fine. Not sure if I was clear enough.
Here is the code for the component so far
<template>
<div class="add-wave">
<h3>Add Wave</h3>
<div class="row">
<form #click.prevent="addwave()" class="col s12">
<div class="row">
<div class="input-field col s12">
<input type="text" v-model="host" />
<label class="active">Host</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input type="text" v-model="scout" />
<label class="active">Scout</label>
</div>
</div>
<button type="submit" class="btn">Submit</button>
<router-link to="/member" class="btn grey">Cancel</router-link>
</form>
</div>
</div>
</template>
<script>
import { db, fv } from "../data/firebaseInit";
export default {
data() {
return {
host: null,
scout: null
};
},
methods: {
addwave() {
this.addhost();
db.collection("members")
.where("name", "==", this.scout)
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
doc.ref.update({
scout: fv.increment(1),
total: fv.increment(1)
});
});
});
},
addhost() {
db.collection("members")
.where("name", "==", this.host)
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
doc.ref.update({
host: fv.increment(1),
total: fv.increment(1)
});
});
});
}
}
};
</script>
I'm not sure why is it updating twice only when I fill both input fields.

Cannot read property 'post' of undefined, in nuxt js

I am making registration form in nuxt js, it takes data from api, I have installed axios and auth module, I wrote base url in nuxt.config.js file. It shows TypeError: Cannot read property 'post' of undefined
```template>
<div>
<section class="content">
<div class="register_form m-auto text-center form-group">
<form method="post" #submit.prevent="register" >
<h1 class ="register_title">REGISTER</h1>
<h2 class="register_text">PLEASE REGISTER TO USE THIS WEBSITE</h2>
<input class="form-control" type="text" placeholder = 'USERNAME' v-model="username" name="username" required>
<input class="form-control" type="password" placeholder = 'PASSWORD' v-model="password" name="password" required>
<button type="submit" to="#" class="register_btn">
REGISTER
</button>
</form>
</div>
</section>
</div>
</template>
<script>
export default {
layout: 'loginLayout',
data(){
return {
username: '',
password: ''
}
},
methods: {
async register() {
try {
await this.$axios.post('register', {
username: this.username,
password: this.password
})
this.$router.push('/')
}
catch (e) {
console.log(e)
}
}
}
}
</script>```
try to use
await this.$axios.$post instead of await this.$axios.$post

How to show success message in vue js after inserting the date into database

I have a perfectly working form I can insert data into database using axios after form validation. I am just struggling to show a success message after inserting the data into the database. how to hide the form and display a succcess message in the same section after sending the data into the database??
here's my perfectly working code
<template>
<b-container>
<div class="update-info">
<div class="feature-text myinv-title">
<h5 class="title title-sm">Update your information</h5>
</div>
<div>
<form #submit.prevent="submit">
<p v-if="errors.length">
<b>Please fill in all the fields</b>
<ul>
<li v-for="error in errors" class="alert alert-danger">{{ error }}</li>
</ul>
</p>
<div class="form-row">
<div class="form-group col-md-3">
<label for="trx number">TRX No</label>
<input
type="text"
name="trx Number"
v-model="newUser.trx"
class="form-control trx-address-nooverflow"
placeholder="Copy paste your TRX no"
/>
<b-form-text id="input-formatter-help">
<a class="text-success">Your TRX address: {{trxNo}}</a>
</b-form-text>
</div>
<div class="form-group col-md-3">
<label for="name">Name</label>
<input
type="text"
name="name"
v-model="newUser.name"
class="form-control"
placeholder="Enter you name"
/>
</div>
<div class="form-group col-md-3">
<label for="email">Email</label>
<input
type="text"
name="email"
v-model="newUser.email"
class="form-control"
placeholder="Enter valid email address"
/>
</div>
<div class="form-group col-md-3">
<label for="country">Country</label>
<country-select
id="Country"
v-model="newUser.country"
:country="newUser.country"
topCountry="US"
class="form-control"
/>
</div>
<div class="form-group col-md-3">
<label for="mobile">Mobile No</label>
<input
id="mobile"
class="form-control"
v-model="newUser.mobile_no"
type="text"
placeholder="Enter your mobile no."
/>
<b-form-text id="input-formatter-help">
Please enter valid phone number
</b-form-text>
</div>
<div class="form-group col-md-3">
<div class="top-30">
<input type="submit" class="btn btn-btn btn-grad btn-submit" />
</div>
</div>
</div>
</form>
</div>
</div>
</b-container>
</template>
here's my vue js code
<script>
import axios from 'axios'
export default{
data(){
return{
errorMessage: "",
successMessage: "",
text: "success",
errors: [],
users: [],
newUser: {trx: "", name: "", country: "", email: "", mobile_no: ""}
}
},
computed: {
trxNo: function() {
return this.$store.state.myAddress;
}
},
mounted: function(){
this.getAllUsers();
},
methods:{
getAllUsers: function(){
axios.get('https://onex.tronpayer.com/api/update-info-form.php?action=read', { crossdomain: true })
.then((response) => {
if(response.data.error){
this.errorMessage = response.data.message;
}else{
this.users = response.data.users;
}
});
},
submit(){
this.checkForm()
if(!this.errors.length) {
var formData = this.toFormData(this.newUser);
axios.post('https://onex.tronpayer.com/api/update-info-form.php?action=update', formData, { crossdomain: true })
.then((response) => {
this.newUser = {trx: "", name: "", country: "", email: "", mobile_no: ""};
if(response.data.error){
this.errorMessage = response.data.message;
}else{
this.getAllUsers();
}
});
}
},
toFormData: function(obj){
var form_data = new FormData();
for(var key in obj){
form_data.append(key, obj[key]);
}
return form_data;
},
clearMessage: function(){
this.errorMessage = "";
this.successMessage = "";
},
//validation
checkForm: function (e) {
this.errors = [];
if (!this.newUser.trx) {
this.errors.push("Trx Number Required.");
}
if (!this.newUser.name) {
this.errors.push("Name Required.");
}
if (!this.newUser.country) {
this.errors.push("Country Required.");
}
if (!this.newUser.email) {
this.errors.push('Email Required.');
} else if (!this.validEmail(this.newUser.email)) {
this.errors.push('Valid Email Address Required.');
}
if (!this.newUser.mobile_no) {
this.errors.push("Mobile Number Required.");
}
if (!this.errors.length) {
return true;
}
},
validEmail: function (email) {
var re = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}
}
}
</script>
You can use the v-if conditional rendering for disabling the form and showing the message.
https://v2.vuejs.org/v2/guide/conditional.html
Just create a variable like savingSuccessful: false and set it to true when your ajax request was successful.
Use it now in your form like
<form #submit.prevent="submit" v-if="!savingSuccessful">
This means your form will be displayed until your variable is true.
For a success-message you can create something like this:
<div class="success" v-if="savingSuccessful">
{{ this.text }}
</div>
Your message will be rendered when the variable is true.
Here a JSFiddle:
https://jsfiddle.net/MichelleFuchs/nydruxzw/2/

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>