Vue JS. Layered calls not synchronised: Web Page -> VUEX-> API call - vue.js

I have refactored my VUE JS code to have a dedicated API layer (Calls out to AWS Graphql services), it is called by the VUEX layer. It now has the following levels:
Web Page -> Vuex -> API
I want to retrieve data (this.getActivities) before referencing it (Point 7). I have cut down the code for simplicity:
async created() {
console.log("Point 1")
await this.getActivities();
},
mounted() {
console.log("Point 7")
// reference the data set by this.getActivities()
},
methods: {
async getActivities() {
// from DB
console.log("Point 2")
this.$store.dispatch('getAllActivities') // vuex call
},
VUEX DATA STORE
actions: {
async getAllActivities ({ commit }) {
console.log("point 3")
const activities = await queries.getActivities()
console.log("point 6")
commit('setActivities', activities)
},
API
async getActivities () {
await API.graphql({
query: listActivities
}).then((response) => {
console.log("Point 4")
})
console.log("Point 5")
return activitiesList
},
Prints the following:
Point 1
Point 2
point 3
Point 7
Point 8
Point 4
Point 5
point 6
I presume I have misused the await/sync processes?
Thanks

Assuming that you need the list of activities in more than 1 component/route (otherwise why would you store this list in Vuex instead of the component itself ?!) you would normally do something like this:
<template>
<div>
<ActivityItem v-for="act in ACTIVITY_LIST" :key="act.id" :activity="act" />
</div>
</template>
<script>
import ActivityItem from './components/ActivityItem';
import { mapGetters, mapActions } from 'vuex';
import { ACTIVITY_LIST, FETCH_ACTIVITIES } from './store/constants';
export default
{
components:
{
ActivityItem,
},
computed:
{
...mapGetters([ACTIVITY_LIST]),
},
created()
{
this[FECH_ACTIVITIES]();
},
methods:
{
...mapActions([FETCH_ACTIVITIES])
}
}
</script>
// store/constants.js
export const ACTIVITY_LIST = 'ACTIVITY_LIST';
export const FETCH_ACTIVITIES = 'FETCH_ACTIVITIES';
export const SET_ACTIVITIES = 'SET_ACTIVITIES';
// store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import { ACTIVITY_LIST, FETCH_ACTIVITIES, SET_ACTIVITIES } from './store/constants';
import myAPI from './api';
Vue.use(Vuex);
export default new Vuex.Store(
{
strict: process.env.NODE_ENV !== 'production',
state()
{
return {
activities: []
};
},
getters:
{
[ACTIVITY_LIST](state)
{
return state.activities;
}
},
mutations:
{
[SET_ACTIVITIES](state, value)
{
state.activities = value || [];
}
},
actions:
{
[FETCH_ACTIVITIES]({ commit })
{
return myAPI.getActivities().then(response =>
{
commit(SET_ACTIVITIES, response.data.activitiesList);
return response.data.activitiesList; // optional
});
}
}
});

Related

Axios - get data from api in vuex actions?

How to correctly transfer or rewrite the function in actions that will receive the first photo from each album in?
my photos models:
import { api } from "#/apis/config";
const endPoint = 'photos'
const state = {
photos: []
}
const getters = {}
const mutations = {
SET_PHOTOS(state, data) {
state.photos = data
}
}
const actions = {
loadMore(id) {
api.get(`photos?albumId=${id}`).then(response => {
return response.data[0].thumbnailUrl;
});
}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
};
And my album component:
...
<script>
import {mapActions} from "vuex";
export default {
name: "GridAlbums",
props: ['album'],
data() {
return {
loading: true,
errored: false,
photo: null
}
},
mounted() {
this.photo = this.loadMore(this.album.id)
},
methods: {
...mapActions("photos", ["loadMore"])
}
}
</script>
...
Here is my configuration file for api, where VUE_APP_HOST is https://jsonplaceholder.typicode.com/
import axios from 'axios'
export const api = axios.create({
baseURL: process.env.VUE_APP_HOST,
})
api.interceptors.response.use(
response => {
return response
},
error => {
return Promise.reject(error)
}
)
If you get the data this way, then everything turns out as it should:
Try adding async / await in vuex actions, because actions must be asynchronous and store and mutations synchronous.
Also use try / catch instead Promise that way you keep your code cleaner

mapActions not returning action from module

I am trying to add the Actions I created in my Vuex module to the Methods of my component.
My component "HomePage.vue" looks like this
import { PlusIcon } from "vue-feather-icons";
import TaskItem from "../TaskItem";
import moment from "moment";
import { mapGetters, mapActions } from "vuex";
export default {
name: "home-page",
components: {
PlusIcon,
TaskItem,
},
methods: {
...mapActions(['fetchTasks'])
},
computed: mapGetters(['allTasks']),
created() {
setInterval(() => {
document.getElementById("time").innerHTML = moment().format("h:mm:ss a");
}, 1000);
},
};
My Vuex module "tasks.js" looks like this
import fs from 'fs'
const state = {
tasks: []
}
const getters = {
allTasks: (state) => state.tasks
}
const actions = {
fetchTasks({commit}) {
let rawdata = fs.readFileSync('../backend/tasks.json')
console.log(JSON.parse(rawdata))
commit('setTasks', JSON.parse(rawdata))
}
}
const mutations = {
setTasks: (state, passedTasks) => (state.tasks.push(passedTasks))
}
export default {
state,
getters,
actions,
mutations,
}
When attempting to use this.fetchTasks() in created(), nothing happens.
When console logging this.fetchTasks() it returns as undefined
Considering your tasks is a module of your vuex store, you should call your mapActions, mapGetters this way :
methods: {
...mapActions('tasks', ['fetchTasks'])
},
computed: {
...mapGetters('tasks', ['allTasks'])
},

How can I get response ajax by vuex store in the vue component?

My component vue like this :
<template>
...
</template>
<script>
import {mapActions, mapGetters} from 'vuex'
export default {
...
methods: {
add(event) {
this.addProduct(this.filters)
console.log(this.getStatusAddProduct)
if(this.getStatusAddProduct) {
...
}
},
...mapActions(['addProduct'])
},
computed: {
...mapGetters(['getStatusAddProduct'])
}
}
</script>
This code : this.addProduct(this.filters), it will call addProduct method n the modules vuex
My modules vuex like this :
import { set } from 'vue'
import product from '../../api/product'
import * as types from '../mutation-types'
// initial state
const state = {
statusAddProduct: null
}
// getters
const getters = {
getStatusAddProduct: state => state.statusAddProduct
}
// actions
const actions = {
addProduct ({ dispatch, commit, state }, payload)
{
product.add(payload,
data => {
commit(types.ADD_PRODUCT_SUCCESS)
},
errors => {
commit(types.ADD_PRODUCT_FAILURE)
}
}
}
}
// mutations
const mutations = {
[types.ADD_PRODUCT_SUCCESS] (state){
state.statusAddProduct = true
},
[types.ADD_PRODUCT_FAILURE] (state){
state.statusAddProduct = false
}
}
export default {
state,
getters,
actions,
mutations
}
This code : product.add(payload, in the modules vuex, it will call api
The api like this :
import Vue from 'vue'
export default {
add (filter, cb, ecb = null ) {
axios.post('/member/product/store', filter)
.then(response => cb(response))
.catch(error => ecb(error))
}
}
My problem here is if add method in vue component run, the result of console.log(this.getStatusAddProduct) is null. Should if product success added, the result of console.log(this.getStatusAddProduct) is true
I think this happens because at the time of run console.log(this.getStatusAddProduct), the process of add product in vuex modules not yet finished. So the result is null
How can I make console.log(this.getStatusAddProduct) run when the process in the vuex module has been completed?
You have to pass the property down all the way from the .add() method.
You do that by returning it in the intermediary methods and, lastly, using .then().
The api:
add (filter, cb, ecb = null ) {
return axios.post('/member/product/store', filter) // added return
.then(response => cb(response))
.catch(error => ecb(error))
}
And, the action:
addProduct ({ dispatch, commit, state }, payload) // added return
{
return product.add(payload,
data => {
commit(types.ADD_PRODUCT_SUCCESS)
},
errors => {
commit(types.ADD_PRODUCT_FAILURE)
}
}
}
Finally:
methods: {
add(event) {
this.addProduct(this.filters).then(() => { // added then
console.log(this.getStatusAddProduct) // moved inside then
if(this.getStatusAddProduct) {
...
}
})
},

How to add the total + 1 in the text span each time a notification using vue.js 2?

My vue component is like this :
<template>
...
<span v-if="total > 0" class="badge" id="total">{{ total }}</span>
...
</template>
<script>
import { mapGetters } from 'vuex'
export default {
mounted() {
this.initialMount()
},
computed: {
...mapGetters(['total'])
},
methods: {
initialMount() {
Echo.private('App.User.' + window.Laravel.authUser.id).notification((notification) => {
const a = $('#total').text()
const b= parseInt(a) + 1
$('#total').text(b)
})
},
}
}
</script>
My modules is like this :
import { set } from 'vue'
import notification from '../../api/notification'
import * as types from '../mutation-types'
const state = {
total: 0,
}
const getters = {
total: state => state.total
}
const actions = {
getNotificationList ({ commit,state })
{
notification.getList(
data => {
const notifications = data
commit(types.GET_NOTIFICATION,{ notifications });
},
errors => {
console.log(errors)
}
)
}
}
const mutations = {
[types.GET_NOTIFICATION] (state, { notifications }) {
state.total = notifications.length
}
}
export default {
state,
getters,
actions,
mutations
}
===================================================================
I want every notification, the notification number incremented by 1
My above code works, but it still using jquery
I want change it using vue.js
How can I do it?
You have to commit action into the sucess callback of Echo, but first you have to define mutation:
const mutations = {
[types.GET_NOTIFICATION] (state, { notifications }) {
state.total = notifications.length
},
inc (state) {
state.total++
}
}
And then, you can commit action
methods: {
initialMount() {
Echo.private('App.User.' + window.Laravel.authUser.id).notification((notification) => {
// Make sure you have imported store
store.commit('inc')
})
},
}

AngularJS services in Vue.js

I'm new to Vue.js and looking for the equivalent of a service in AngularJS, specifically for storing data once and getting it throughout the app.
I'll be mainly storing the results of network requests and other promised data so I don't need to fetch again on very state.
I'm using Vue.JS 2.0 with Webpack.
Thanks!
I think what u are seeking for is vuex, which can share data from each component.
Here is a basic demo which from my code.
store/lottery.module.js
import lotteryType from './lottery.type'
const lotteryModule = {
state: {participantList: []},
getters: {},
mutations: {
[lotteryType.PARTICIPANT_CREATE] (state, payload) {
state.participantList = payload;
}
},
actions: {
[lotteryType.PARTICIPANT_CREATE] ({commit}, payload) {
commit(lotteryType.PARTICIPANT_CREATE, payload);
}
}
};
export default lotteryModule;
store/lottery.type.js
const PARTICIPANT_CREATE = 'PARTICIPANT_CREATE';
export default {PARTICIPANT_CREATE};
store/index.js
Vue.use(Vuex);
const store = new Vuex.Store();
store.registerModule('lottery', lotteryModule);
export default store;
component/lottery.vue
<template>
<div id="preparation-container">
Total Participants: {{participantList.length}}
</div>
</template>
<script>
import router from '../router';
import lotteryType from '../store/lottery.type';
export default {
data () {
return {
}
},
methods: {
},
computed: {
participantList() {
return this.$store.state.lottery.participantList;
}
},
created() {
this.$store.dispatch(lotteryType.PARTICIPANT_CREATE, [{name:'Jack'}, {name:'Hugh'}]);
},
mounted() {
},
destroyed() {
}
}
</script>
You don't need Vue-specific services in Vue2 as it is based on a modern version of JavaScript that uses Modules instead.
So if you want to reuse some services in different locations in your code, you could define and export it as follows:
export default {
someFunction() {
// ...
},
someOtherFunction() {
// ...
}
};
And then import from your Vue code:
import service from 'filenameofyourresources';
export default {
name: 'something',
component: [],
data: () => ({}),
created() {
service.someFunction();
},
};
Note that this is ES6 code that needs to be transpiled to ES5 before you can actually use it todays browsers.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export