Redo the api call everytime I change the data value on VueJs - vue.js

I'm trying to update a request of an axios.get
I have a method that adds 1 to the param data (the default value is 1), but even thought I'm updating the param value, the page won't change the content because it's not updating the get requisition
I know there something similar in react with componentDidUpdate method
Here's my code
Api request
async created() {
const {
data: {
data: { items, pagination },
},
} = await this.$axios.get(`/faq?page=${this.param}`)
},
Method:
methods: {
next() {
this.param = this.param + 1
},
},
So is it possible to redo the create() everytime i use the method next?

created() hook is called only once during a lifecycle, you can use watcher instead in order to listen to variable changes
watch: {
param: {
immediate: true,
handler(newVal, oldVal) {
if (newVal !== oldVal) {
await this.$axios.get(`/faq?page=${newVal}`)
}
}
}
}
For more info, please take a look at: https://v2.vuejs.org/v2/guide/computed.html#Computed-vs-Watched-Property

Related

How pass state vuex on created()

I have been using vuex for a project for a few days now. Now I need to pass the value of a state to the created method.
Below I show the code used.
Store file
state: {
friendstatus: null
},
mutations: {
SET_FRIEND_STATUS: (state,friend) => {
state.friendstatus = data;
},
actions: {
getFriendStatus: ({commit},data) => {
//axios request returns friendstatus
commit('STATE_FRIEND_STATUS',response.data.status)
}
Vue component
computed: {
...mapstate('friend',['friendstatus'])
},
created() {
//Here I need to pass friendstatus. Obviously if I call this.friendstatus it does not work.
this.$store.dispatch('friend/getFriendStatus);// I would like to call the state and not the action
}

Vue reactivity issues in component making asynchronous server requests

A small amount of context: I have a Vue view called Articles. When the component is mounted to the DOM, I fetch all posts from the database using the axios library (in conjunction with Laravel controllers and API routes). The articles view contains a data property called active, which points towards the post that is currently selected. Clicking on a different post in the sidebar updates active and subsequently the new post is shown.
Now, every post has many comments, and those comments in turn can be linked to subcomments if you will. However, the mounted lifecycle hook in Articles.vue gets invoked only once and when I try to place the server request in updated(), everything seemingly works but I'd eventually get a 429 status (too many requests). My guess is that for each comment that is retrieved, the code in updated() get's invoked again.
I guess my question is as follows: How can I make Post.vue reactive, since right now the mounted lifecycle hook will be invoked only once even when another post is selected.
Here's the code:
Articles.vue
export default {
name: "Articles",
components: {SidebarLink, PageContent, Sidebar, Post, Searchbar, Spinner},
data() {
return {
posts: [],
active: undefined,
loading: true
}
},
mounted() {
this.fetchPosts();
},
methods: {
async fetchPosts() {
const response = await this.$http.get('/api/posts');
this.posts = response.data;
this.active = this.posts[0];
setTimeout(() => {
this.loading = false;
}, 400);
},
showPost(post) {
this.active = post;
}
}
}
Post.vue
export default {
name: "Post",
components: {Tag, WennekesComment},
props: ['post'],
data() {
return {
expanded: true,
comments: []
}
},
mounted() {
this.fetchComments();
},
methods: {
async fetchComments() {
let response = await this.$http.get('/api/posts/' + this.post.id + '/comments');
this.comments = response.data;
}
}
}
WennekesComment.vue
export default {
name: "WennekesComment",
props: ['comment'],
data() {
return {
subComments: []
}
},
mounted() {
this.fetchSubcomments();
},
methods: {
fetchSubcomments() {
let response = this.$http.get('/api/comments/' + this.comment.id).then((result) => {
// console.log(result);
});
}
}
}
Template Logic
<wennekes-comment v-for="comment in comments" :key="comment.id" :comment="comment"></wennekes-comment>
<post v-if="!loading" :post="active" :key="active.id"/>
Thanks in advance, and my apologies if this question is somewhat unclear, I'm somewhat at a loss.
Regards,
Ryan
UPDATE
I think I got it to work. In Articles.vue, I have appended a key to the post component. I think this is Vue's way of knowing which specific instance of a component to update.
I think I got it to work. In Articles.vue, I have appended a key to the post component. I think this is Vue's way of knowing which specific instance of a component to update.

How to trigger watch AFTER I read array from db?

In my vue/cli 4/vuex opening page I need to fill select input with default value from
vuex store. To fill select input I need have selection items read from db and I have a problem that watch is triggered
BEFORE I read data from db in mount event.
I do as :
watch: {
defaultAdSavedFilters: {
handler: function (value) {
console.log('WATCH defaultAdSavedFilters value::')
console.log(value)
if (!this.isEmpty(value.title)) {
this.filter_title = value.title
}
if (!this.isEmpty(value.category_id)) {
this.categoriesLabels.map((nexCategoriesLabel) => { // this.categoriesLabels IS EMPTY
if (nexCategoriesLabel.code === value.category_id) {
this.selection_filter_category_id = {code: value.category_id, label: nexCategoriesLabel.label};
}
});
}
}
}, //
}, // watch: {
mounted() {
retrieveAppDictionaries('ads_list', ['ads_per_page', 'categoriesLabels']); // REQUEST TO DB
bus.$on('appDictionariesRetrieved', (response) => {
if (response.request_key === 'ads_list') { // this is triggered AFTER watch
this.ads_per_page = response.ads_per_page
this.categoriesLabels = response.categoriesLabels
// this.$forceUpdate() // IF UNCOMMENT THAT DOES NOT HELP
Vue.$forceUpdate() // THAT DOES NOT HELP
}
})
this.loadAds(true)
}, // mounted() {
I found this Can you force Vue.js to reload/re-render?
branch and tried some decisions, like
Vue.$forceUpdate()
but that does not work.
If there is a right way to trigger watch defaultAdSavedFilters AFTER I read array from db ?
Modified BLOCK :
I use Vuex actions/mutations when I need to read / keep /use /update data of the logged user, like
defaultAdSavedFilters, which is defined as :
computed: {
defaultAdSavedFilters: function () {
return this.$store.getters.defaultAdSavedFilters
},
Data ads_per_page(used for pagionaion), categoriesLabels(used for selection input items) has nothing to do with
logged user, that is why I do not use vuex for them, and I use retrieveAppDictionaries method to read them from the db
and bus to listen to them, which is defined as :
import {bus} from '#/main'
Sure I have data( block :
export default {
data() {
return {
...
ads_per_page: 20,
categoriesLabels: [],
...
}
},
"vue": "^2.6.10",
"vue-router": "^3.1.3",
"vuex": "^3.1.2"
Thanks!
Please add the data() method from you component. But I'm pretty sure it is NOT triggering because of the way you are assigning the result from the API call.
Try this:
mounted() {
retrieveAppDictionaries('ads_list', ['ads_per_page', 'categoriesLabels']); // REQUEST TO DB
bus.$on('appDictionariesRetrieved', (response) => {
if (response.request_key === 'ads_list') { // this is triggered AFTER watch
this.ads_per_page = [ ...response.ads_per_page ]
this.categoriesLabels = [ ...response.categoriesLabels ]
}
})
this.loadAds(true)
}
However, I don't understand what bus is doing for you and why you are NOT using Vuex actions/mutations

How to format fetched data in Vue.js and update the vue instance

I am trying to fetch a json from an api and then format it for later use in google-charts.
I fetch the json-file using vue-resource and it works normally, the problem happens when I try to format the received data (update other arrays in data() with the fetched data), the vue component is not updated (the function is in created() ).
When I use a v-on:click the formating is done correctly but when I call the function from created it doesn't work.
I tried Vue.set and the splice method, both didn't work.
Goal
Getting the formatData() method to run and update the idArray.
export default {
name: 'app',
components: {
FirstCharts
},
data() {
return {
apiData: undefined,
idArray: []
}
},
created() {
this.loadApi();
},
methods: {
loadApi: function () {
this.$http.get('https://api.myjson.com/######').then(this.successCallback, this.errorCallback);
},
successCallback: function (response) {
this.apiData = response.data;
},
errorCallback: function (response) {
this.apiData = response.data;
this.formatData();
this.$forceUpdate();
},
formatData: function () {
for (var i = 0; i < this.apiData.resourcePlan.length; i++) {
this.idArray.splice(i, 1, parseInt(this.apiData.resourcePlan[i].resourceID));
Vue.set(this.idArray, i, parseInt(this.apiData.resourcePlan[i].resourceID));
}
}
it looks like you are calling formatData in the error callback, not the success callback. see if moving it into success works.

Onsen + VueJS: Call back from child component (using onsNavigatorProps)

Per documentation here
If page A pushes page B, it can send a function as a prop or data that modifies page A’s context. This way, whenever we want to send anything to page A from page B, the latter just needs to call the function and pass some arguments:
// Page A
this.$emit('push-page', {
extends: pageB,
onsNavigatorProps: {
passDataBack(data) {
this.dataFromPageB = data;
}
}
});
I am following this idea. Doing something similar with this.$store.commit
I want to push AddItemPage and get the returned value copied to this.items
//Parent.vue
pushAddItemPage() {
this.$store.commit('navigator/push', {
extends: AddItemPage,
data() {
return {
toolbarInfo: {
backLabel: this.$t('Page'),
title: this.$t('Add Item')
}
}
},
onsNavigatorProps: {
passDataBack(data) {
this.items = data.splice() //***this*** is undefined here
}
}
})
},
//AddItemPage.vue
...
submitChanges()
{
this.$attrs.passDataBack(this, ['abc', 'xyz']) // passDataBack() is called, no issues.
},
...
Only problem is this is not available inside callback function.
So i can't do this.items = data.splice()
current context is available with arrow operator.
Correct version:
onsNavigatorProps: {
passDataBack: (data) => {
this.items = data.splice()
}
}