I'm trying to reach the content of matchData from a Vue method. I'm able to console.log(this.matchData), but not able to get its content.
When I console.log(this.matchData[0].matchScores[0]) under method readMatchPlayerScoreIds() I get:
vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in mounted hook: "TypeError: Cannot read property 'matchScores' of undefined"
export default {
data() {
return {
matchData: [],
};
},
methods: {
readMatches() {
db.collection("matches")
.get()
.then((queryMatchSnapshot) => {
queryMatchSnapshot.forEach((doc) => {
this.matchData = [];
this.matchData.push({
awayscore: doc.data().awayscore,
homeScore: doc.data().homeScore,
matchScores: doc.data().matchscores,
})
});
console.log(this.matchData[0].matchScores[0])
});
},
readMatchPlayerScoreIds() {
console.log(this.matchData[0].matchScores[0])
}
},
mounted() {
this.readMatches();
this.readMatchPlayerScoreIds();
},
};
Since you are fetching data from the db asynchronously, the data will be empty until the db call was completed. You should read the data after the Promise has been resolved. (reformulating my comment as answer).
One way to do it, could be to return the Promise from readMatches:
export default {
data() {
return {
matchData: [],
};
},
methods: {
readMatches() {
return db.collection("matches")
.get()
.then((queryMatchSnapshot) => {
queryMatchSnapshot.forEach((doc) => {
// this.matchData = []; // <= why would you reset it in each loop?
this.matchData.push({
awayscore: doc.data().awayscore,
homeScore: doc.data().homeScore,
matchScores: doc.data().matchscores,
})
});
console.log(this.matchData[0].matchScores[0])
});
},
readMatchPlayerScoreIds() {
console.log(this.matchData[0].matchScores[0])
}
},
mounted() {
this.readMatches()
.then(() => this.readMatchPlayerScoreIds());
},
};
But it depends on what you want do to in readMatchPlayerScoreIds method body.
Also, be aware not to reset matchData in the forEach loop.
Related
First I defined Types, Severities, and Statuses as [] and returned them in data().
Then I filled them with data in the methods getTypes(), getSeverities(), and getStatuses().
I want to use Types, Severities, and Statuses in the method getName()(just has console.log() as an example for now).
I noticed when debugging getNames(), type in the second for loop is undefined. Is it because the method is using Type before it was assigned values in getTypes()? How can I make it work?
Note: Types, Severities, and Statuses do get assigned values in the methods getTypes(), getSeverities(), and getStatuses(), the issues is how to use the data in other methods.
<script>
import IssuesTable from '../MyIssuesPage/IssuesTable.vue'
import AddIssue from '../MyIssuesPage/AddIssue.vue'
import axios from 'axios'
export default {
props: ['id', 'project', 'issuesList', 'index'],
components: { IssuesTable, AddIssue },
data() {
return {
Issues: this.issuesList[this.index],
tab: null,
items: [{ tab: 'Issues' }, { tab: 'Calender' }, { tab: 'About' }],
Types: [],
Severities: [],
Statuses: [],
}
},
setup() {
return {
headers: [
{ text: 'Title', value: 'title' },
{ text: 'Description', value: 'description' },
{ text: 'Estimate', value: 'time_estimate' },
{ text: 'Assignees', value: 'userid' },
{ text: 'Type', value: 'issueTypeId' },
{ text: 'Status', value: 'issueStatusId' },
{ text: 'Severity', value: 'issueSeverityId' },
],
}
},
mounted() {
this.getTypes(), this.getSeverities(), this.getStatuses(), this.getNames()
},
methods: {
getTypes() {
axios
.get('http://fadiserver.herokuapp.com/api/v1/my-types')
.then(response => {
this.Types = response.data
})
.catch(error => {
console.log(error)
})
},
getSeverities() {
axios
.get('http://fadiserver.herokuapp.com/api/v1/my-severities')
.then(response => {
this.Severities = response.data
})
.catch(error => {
console.log(error)
})
},
getStatuses() {
axios
.get('http://fadiserver.herokuapp.com/api/v1/my-status')
.then(response => {
this.Statuses = response.data
})
.catch(error => {
console.log(error)
})
},
getNames() {
for (var issue of this.Issues) {
for (var type of this.Types) {
if (issue.issueTypeId == type.id) console.log('test')
}
}
},
},
}
</script>
First of all, use created() instead of mounted() for calling methods that fetch data.
Next, you need to call getNames() only after all fetch methods complete.
created() {
this.getTypes()
.then(this.getSeverities())
.then(this.getStatuses())
.then(this.getNames());
}
In order to chain methods like this you need to put return statement before each axios like this
getTypes() {
return axios
.get("https://fadiserver.herokuapp.com/api/v1/my-types")
.then((response) => {
this.Types = response.data;
})
.catch((error) => {
console.log(error);
});
}
In this component, I see you are receiving issuesList and index props from the outside. I cannot know those values but you can console.log both of them inside created() and see what is happening because issuesList[index] is undefined.
That probably means issuesList is an array and that index does not exist in that array.
So I have the following code in one of my components:
export default {
name: 'section-details',
components: {
Loading
},
mounted() {
if (!this.lists.length || !this.section_types.length) {
this.$store.dispatch('section/fetch_section_form_data', () => {
if (this.section) {
this.populate_form();
}
});
}
else if (this.section) {
this.populate_form();
}
},
computed: {
section_types() {
return this.$store.state.section.section_types;
},
lists() {
return this.$store.state.list.lists;
},
loading() {
console.log(this.$store.state.section.loading);
this.$store.state.section.loading;
}
},
.
.
.
}
As you can see I have a computed property for "loading" that retrieves the attribute from my vuex store for when doing an ajax request.
in my section vuex module i have this:
fetch_section_form_data({ commit }, callback) {
commit("isLoading", true);
sectionService
.fetch_form_data()
.then((data) => {
commit("isLoading", false);
commit("fetch_section_types_success", data.section_types);
commit("list/fetch_lists_success", data.lists, { root: true});
if (callback) {
callback();
}
})
.catch((err) => {
commit("isLoading", false);
})
;
}
then in my mutations for the module i have the following code:
mutations: {
isLoading(state, status) {
state.loading = status;
},
}
Finally in my component where I store the loading property I have this:
<Loading v-if="loading"></Loading>
Anyways, for some reason the Loading component isn't showing up. the console.log in the loading() method however, is returning true for this.$store.state.section.loading. So for some reason Vue isn't picking up that loading == true in the actual DOM. Any help would be appreciated.
You need to return the value from the computed property method:
loading() {
return this.$store.state.section.loading;
}
i have application that calls several requests and displays that data. Everything is working, but I getting some errors that I can't figure out where is the problem..
So I have two components:
--App :Parent
---Events :Children
In App.vue calling children component:
<Events :events="gameInfo" :results="results" #startNewGame="startNewGame" />
Giving as a props "gameInfo", "results" and listening for "startNewGame" event.
When application loads first time in App.vue i'm calling function:
// Get Next Game
getNextGame() {
this.gameInfo = [];
RouletteApi.getNextGame().then(response => {
this.gameInfo.push({ response });
});
}
That children component receives and displays data.
In children component:
<script>
export default {
name: "Events",
props: ["events", "results"],
data() {
return {
GameStartTime: null,
GameId: null,
GameUUID: null
};
},
watch: {
events: function(newVal, oldVal) {
this.GameStartTime = newVal[0]["response"].fakeStartDelta--;
this.GameId = newVal[0]["response"].id;
this.GameUUID = newVal[0]["response"].uuid;
}
},
created() {
setInterval(() => {
if (this.GameStartTime > 0) {
this.GameStartTime = this.events[0]["response"].fakeStartDelta--;
} else {
this.$emit("startNewGame", this.GameUUID); -- call to parent function
}
}, 1000);
}
};
</script>
I watching, getting the data and setting timer, to execute "startNewGame" function from parent, that will make another api call and give children new data.
After timer expires I'm calling "startNewGame" function from parent:
startNewGame(uuid) {
this.startSpinning();
RouletteApi.startNewGame(uuid).then(response => {
if (response.result == null) {
setTimeout(function() {
startNewGame(uuid);
}, 1000);
} else {
this.results.push({ response });
this.gameInfo = []; -- resetting that previous dat
this.getNextGame(); -- call to first function in example
}
});
That checks if response is null then setting timeout and calling that function until response will be not null. If response came not null than I pushing to children result, resetting that gameInfo array and calling again getNextGame() function that will call request and set new value for timer in children component.
RouletteApi.js:
import axios from 'axios'
export default {
getLayout() {
return axios.get('/configuration')
.then(response => {
return response.data
})
},
getStats() {
return axios.get('/stats?limit=200')
.then(response => {
return response.data
})
},
getNextGame() {
return axios.get('/nextGame')
.then(response => {
return response.data
})
},
startNewGame(uuid) {
return axios.get('/game/' + uuid)
.then(response => {
return response.data
})
}
}
Errors:
Error in callback for watcher "events": "TypeError: Cannot read property 'response' of undefined"
TypeError: Cannot read property 'response' of undefined
at VueComponent.events (Events.vue?5cf3:30)
Uncaught ReferenceError: startNewGame is not defined
First two errors i'm getting from children component in "watch" part.
Last one when calling function in setInterval in parent component.
It looks like the watcher is running before the api call finished. Console log the new value to see what your get. Try to check if the newVal is not null or an empty array and then set the values.
I'm trying to access my data property in my Vue.js component. Looks like I'm missing something obvious.
Here is a short version of my code. StoreFilter.vue is a wrapper for matfish2/vue-tables-2.
<template>
<store-filter :selected.sync="storeIds"></store-filter>
</template>
<script>
import StoreFilter from './Filters/StoreFilter';
export default {
components: {
StoreFilter
},
data() {
return {
options : {
requestFunction(data) {
console.log(this.storeIds); //undefined
return axios.get('/api/orders', {
params: data
}).catch(function (e) {
this.dispatch('error', e);
}.bind(this));
},
},
storeIds: [],
}
},
watch : {
storeIds(storeIds) {
this.refreshTable();
}
},
methods : {
refreshTable() {
this.$refs.table.refresh();
}
}
}
</script>
How to get storeIds from requestFunction?
Use a closure, see rewrite below.
data() {
let dataHolder = {};
dataHolder.storeIds = [];
dataHolder.options = {
requestFunction(data) {
// closure
console.log(dataHolder.storeIds); // not undefined
return axios.get('/api/orders', {
params: data
}).catch(function (e) {
this.dispatch('error', e);
}.bind(this));
}
}
return dataHolder;
}
I recommend using the created() way to handle this.
export default {
// whatever you got here
data () {
return {
options: {}
}
},
created () {
axios.get('/api/orders', { some: params }).then(response => this.options = response.data)
}
}
I'm stuck at a crossroads with a component I am working on.
I have the following component "RecentUpdates"
Within it I am passing props down to a few other components, as you can see from the top of the file.
My problem is when adding a new post, I can not figure out how to get the correct update object array back and i also can not figure out the correct 'Vue way' to update the data prop that is being passed down to the "PostList" component.
<template>
<div>
<PostFilter v-on:selectedCategory="getSelectedPosts" v-on:showAllPosts="showAllPosts" :user="user" :categories="categories"/>
<PostList v-if="recent_posts[0]" :categories="categories" :posts="recent_posts[0]" :user="user"/>
<Pagination v-on:getPreviousPage="getPreviousPage" v-on:getNextPage="getNextPage"/>
</div>
</template>
<script>
import PostList from './PostList';
import PostFilter from './PostFilter';
import Pagination from './Pagination';
import EventBus from '../event-bus';
export default {
name: 'RecentUpdates',
data: () => ({
errors: [],
recent_posts: [],
}),
props: ['categories', 'user'],
components: {
PostList,
PostFilter,
Pagination
},
created() {
if (this.user.meta.selected_categories[0] == 0) {
this.showAllPosts();
}
// do not call here, not working as expected
// is switching selected category to an incorrect one
// this.updateList();
this.getSelectedCategory();
},
watch: {
recent_posts: function(newValue) {
EventBus.$on('addPost', function(newPost) {
console.log(newPost);
this.$forceUpdate();
//this.recent_posts.push(newPost);
//this.$set(this.recent_posts, newPost, newPost);
// this.$nextTick(function () {
// this.recent_posts.push(newPost);
// });
});
console.log(this.recent_posts[0]);
// this.$nextTick(function () {
// console.log(this.recent_posts[0]) // => 'updated'
// });
// if (this.user.meta.selected_categories[0] == 0) {
// EventBus.$on('addPost', this.showAllPosts);
// } else {
// EventBus.$on('addPost', this.getSelectedCategory);
// }
//this.updateList();
}
},
methods: {
// updateList() {
// if (this.user.meta.selected_categories[0] == 0) {
// EventBus.$on('addPost', this.showAllPosts);
// //EventBus.$emit('newPost');
// } else {
// EventBus.$on('addPost', this.getSelectedCategory);
// //EventBus.$emit('newPost');
// }
// },
getSelectedCategory() {
let categoryId = this.user.meta.selected_categories[0];
this.getSelectedPosts(categoryId);
},
showAllPosts() {
axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]',
{headers: {'X-WP-Nonce': portal.nonce}})
.then(response => {
this.recent_posts = [];
//this.recent_posts = response.data;
//console.log(response.data);
this.recent_posts.push(response.data);
console.log(this.recent_posts[0]);
})
.catch(e => {
this.errors.push(e);
});
},
getSelectedPosts(categoryId) {
axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&categories=' + categoryId,
{headers: {'X-WP-Nonce': portal.nonce}})
.then(response => {
this.recent_posts = [];
//console.log(response.data);
this.recent_posts.push(response.data);
console.log(this.recent_posts[0]);
})
.catch(e => {
this.errors.push(e);
});
},
/**
* Pagination methods
*
*/
getPreviousPage(page) {
axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&page=' + page,
{headers: {'X-WP-Nonce': portal.nonce}})
.then(response => {
this.recent_posts = response.data;
})
.catch(e => {
this.errors.push(e);
});
},
getNextPage(page) {
axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&page=' + page,
{headers: {'X-WP-Nonce': portal.nonce}})
.then(response => {
this.recent_posts = response.data;
})
.catch(e => {
this.errors.push(e);
});
}
},
}
</script>
<style>
</style>
So there are a number of issues I see reading through your code.
You have a recent_posts data property, which is an array. When you make your ajax call to get the posts you push the response which is also an array into the recent_posts array. Why? Why not just set recent_posts = response.data? Then you won't have to be passing recent_posts[0] around.
You're setting up your EventBus handler inside a watcher. This is really unusual. Typically you would set up a handler inside created or mounted.
this inside the EventBus handler likely refers to the EventBus and not your Vue. Ideally, you would set the handler to be a method on the component, which is already bound to the Vue. Something like EventBus.$on("addPost", this.addPost).
Once you've done all that, adding a new post should be as simple as this.recent_posts.push(newPost).
Here is what I might recommend.
export default {
name: 'RecentUpdates',
data(){
return {
errors: [],
recent_posts: []
}
},
props: ['categories', 'user'],
components: {
PostList,
PostFilter,
Pagination
},
created() {
if (this.user.meta.selected_categories[0] == 0) {
this.showAllPosts();
}
this.getSelectedCategory();
EventBus.$on("addPost", this.addPost)
},
beforeDestroy(){
EventBus.$off("addPost", this.addPost)
},
methods: {
getPosts(url){
axios.get(url, {headers: {'X-WP-Nonce': portal.nonce}})
.then(response => this.recent_posts = response.data)
.catch(e => this.errors.push(e))
},
showAllPosts() {
const url = '/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]';
this.getPosts(url);
},
getSelectedPosts(categoryId) {
const url = '/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&categories=' + categoryId;
this.getPosts(url);
},
addPost(newPost){
this.recent_posts.push(newPost)
},
... //other methods
},
}
Try using kebab-case in your event listeners instead of camelCase:
Example: v-on:selectedCategory="getSelectedPosts" should be v-on:selected-category="getSelectedPosts".
Example: v-on:showAllPosts="showAllPosts" should be v-on:show-all-posts="showAllPosts" or even using the shortcut #show-all-posts="showAllPosts".
UPDATE: If you can provide the code of the other components so we can have a clearer vision of your problem, But you only want to track changes that happens on an object or an array in vue.js you need to deep watch them.
your watcher should be :
watch: {
recent_posts: {
deep: true,
handler: function( oldValue, newValue) {
console.log( "recent_posts has changed" );
// A post has been added, updated or even deleted
}
}
}