working local pagination stopped working upon transfer to vuex - vue.js

I was practicing and learning about vuejs, specifically pagination.
I learn how to do it, and implemented it when I made the api calls in the component, then I moves the function to the actions in vuex, and mapped, them, now my pagination is not even showing up.
I wonder where I made the mistake ???
I have carefully paid attention to every single detail, and read about mutatioons, and actions, I do feel like I am doing everything right, I don't even have any mistakes showing up on the console. this is very wierd
my postModule
import axios from "axios";
export const postModule = {
state: () => ({
posts: [],
page: 1,
limit: 10,
totalPages: 0,
}),
mutations: {
setPosts(state, posts) {
state.posts = posts;
},
setPage(state, page) {
state.page = page;
},
setTotalPage(state, totalPages) {
state.setTotalPage = totalPages
},
},
actions: {
async fetchPosts( {state, commit}) {
try {
const response = await axios.get("https://jsonplaceholder.typicode.com/posts", {
params: {
_page: state.page,
_limit: state.limit,
},
});
commit('setTotalPage', Math.ceil(response.headers["x-total-count"] / state.limit));
commit('setPosts', [...state.posts, ...response.data]);
} catch (e) {
console.log(e);
}
},
async loadPosts({
state,
commit
}) {
try {
commit('setPage', state.page + 1)
setTimeout(async () => {
const response = await axios.get(
"https://jsonplaceholder.typicode.com/posts", {
params: {
_page: state.page,
_limit: state.limit,
},
});
commit('setTotalPage', Math.ceil(response.headers["x-total-count"] / state.limit));
commit('setPosts', [...state.posts, ...response.data]);
});
} catch (e) {
console.log(e);
}
},
},
namespaced: true,
}
<<<<<component >>>>
<template>
<div>
<h1>Page with the posts</h1>
<post-list :posts="posts" />
</div>
<div class="page__wrapper">
<div
v-for="pageNumber in totalPages"
:key="pageNumber"
class="page"
:class="{
'current-page': page === pageNumber,
}"
#click="changePage(pageNumber)"
>
{{ pageNumber }}
</div>
</div>
</template>
<script>
import PostList from "#/components/PostList";
// import axios from 'axios';
import { mapState, mapMutations, mapActions } from "vuex";
export default {
components: { PostList },
data() {
return {
// posts: [],
// page: 1,
// limit: 10,
// totalPages: 0,
};
},
methods: {
changePage(pageNumber) {
this.page = pageNumber;
this.fetchPosts();
},
...mapMutations({
setPage: "setPage",
}),
...mapActions({
// loadPosts: "post/loadPosts",
fetchPosts: "post/fetchPosts",
}),
},
watch: {
page() {
this.fetchPosts();
},
},
mounted() {
this.fetchPosts();
},
computed: {
...mapState({
posts: (state) => state.post.posts,
page: (state) => state.post.page,
limit: (state) => state.post.limit,
totalPages: (state) => state.post.totalPages,
}),
},
};
</script>
<style scoped>
.page__wrapper {
display: flex;
margin: 15px;
}
.page {
border: 1px solid black;
padding: 10px;
}
.current-page {
border: 2px solid red;
font-size: x-large;
}
</style>

Related

Problems with chart.js redrawing or not redrawing graphs

I am Japanese. Therefore, my sentences may be strange. Please keep that in mind.
I am writing code using vue.js, vuex, vue-chart.js and vue-chart.js to display the population of each prefecture of Japan when checked.I’m code is written to redraw the graph when the input element for each prefecture is checked.However, it does not redraw when checked.Also, it may redraw after half of the check.I believe this phenomenon can be confirmed from the following URL.
https://yumemi-coding.web.app/
※There are no errors.
Here's a question: what causes the graphs to redraw or not? Also, how can I code to remedy this?
What I have done to counteract the cause is as follows
I went to the official website and used the rendering process as a reference.
 URL:https://vue-chartjs.org/migration-guides/#new-reactivity-system
 => The way we did it was right.
We thought there was a problem with VueX and coded in a way that did not use it. => There was nothing wrong with vuex.
TopFroont.vue
<template>
<div class="Bar_area">
<Bar :options="chartOptions" :data="chartData" class="Bar_item" />
</div>
</template>
<script>
import { Bar } from "vue-chartjs"
import { Chart as ChartJS, registerables } from "chart.js"
ChartJS.register(...registerables)
export default {
name: "BarChart",
components: { Bar },
data() {
return {
chartOptions: {
responsive: true,
},
}
},
computed: {
chartData() {
return {
labels: this.$store.state.years,
datasets: this.$store.state.prefectures,
}
},
},
}
</script>
NaviBar.vue
<template>
<div class="navApp">
<ul>
<li v-for="(pref, index) in prefData" :key="index" class="pref_itemBox">
<label>
<input type="checkbox" #change="checkItem(pref)" />
<span class="pref_text">{{ pref.prefName }}</span>
</label>
</li>
</ul>
</div>
</template>
<script>
import resasInfo from "#/library/resas.js"
import axios from "axios"
export default {
data() {
return {
resasInfo: resasInfo,
url: resasInfo.url_prefectures,
api: resasInfo.api,
prefData: [],
prefectures: [],
}
},
async created() {
const request_Header = {
headers: { "X-API-KEY": this.api.key },
}
await axios.get(this.url, request_Header).then((res) => {
const value = res.data.result
this.prefData.push(...value)
})
},
methods: {
checkItem(pref) {
// チェックされてる都道府県のみを配列に入れる
const isExistencePref = this.prefectures.indexOf(pref)
isExistencePref === -1
? this.prefectures.push(pref)
: this.prefectures.splice(isExistencePref, 1)
this.$store.dispatch("getPrefectures", this.prefectures)
},
},
}
</script>
vuex => store/index.js
import axios from "axios"
import { createStore } from "vuex"
import createPersistedState from "vuex-persistedstate"
export default createStore({
state: {
prefectures: [],
years: [],
},
mutations: {
getPrefs(state, payload) {
state.prefectures = payload
},
getYears(state, payload) {
state.years = payload
},
},
actions: {
getPrefectures({ commit }, payload) {
// payload => 各都道府県のprefCode + prefName
const allPrefecture_Data = []
const result = payload.map(async (el) => {
const prefCode_data = el.prefCode
axios
.get(
`https://opendata.resas-portal.go.jp/api/v1/population/composition/perYear?prefCode=${prefCode_data}&cityCode=-`,
{
headers: {
"X-API-KEY": "5RDiLdZKag8c3NXpEMb1FcPQEIY3GVwgQwbLqFIx",
},
}
)
.then((res) => {
const value = res.data.result.data[0].data
const TotalPopulation_Year = []
const TotalPopulation_Data = []
// 都道府県の総人口データと年データを各配列に入れ込む
value.forEach((element) => {
TotalPopulation_Data.push(element.value)
TotalPopulation_Year.push(element.year)
})
// rgbaを自動生成する関数 => backgroundColor
const generateRGBA = () => {
const r = Math.floor(Math.random() * 256)
const g = Math.floor(Math.random() * 256)
const b = Math.floor(Math.random() * 256)
const a = 0.8
return `rgba(${r}, ${g}, ${b}, ${a})`
}
// chart.jsに入れ込むデータ
const prefData = {
label: el.prefName,
data: TotalPopulation_Data,
backgroundColor: generateRGBA(),
}
allPrefecture_Data.push(prefData)
commit("getPrefs", allPrefecture_Data)
commit("getYears", TotalPopulation_Year)
})
.catch((err) => {
console.log(err)
})
})
return result
},
},
plugins: [createPersistedState()],
getters: {},
modules: {},
})

How to change the content of webpage when I change the path of dynamic vue-router

I am using vue-router to write a dynamic router .and when I jump from one path to another, I find the path is indeed changed but the web page does not reload and I have no idea why.
the router definition is as follows:
const routes: Array<RouteRecordRaw> = [
{
path: '/lecture/:lecture_name',
name: 'Lecture',
component: LecturesBase,
}
]
and the dynamic web page vue components is like this:
LectureBase.vue
<template>
<div>
<a-layout>
<LectureNavigation />
<LectureTemplate
:page_name="page_name"
/>
<!-- <router-view>
</router-view> -->
<tui-juhe />
</a-layout>
</div>
</template>
<script>
import { ref } from 'vue';
import router from "#/router/index";
import { onBeforeRouteUpdate, useRoute } from "vue-router";
import LectureNavigation from "#/views/lecture/LectureNavigation.vue";
import LectureTemplate from "#/views/lecture/LectureTemplate.vue";
import TuiJuhe from "#/components/advertisement/TuiJuhe.vue";
export default {
name: "LectureBase",
setup() {
const route = useRoute();
},
components: {
LectureNavigation,
TuiJuhe,
LectureTemplate,
},
// props: {
// page_name: String, // 中文标题
// },
data() {
return {
$router: router,
page_name: ref(this.$route.params.lecture_name),
}
},
watch: {
'$route' (to, from) {
console.log('# to url: ' + to.path);
console.log('# to url: ' + this.$route.params.lecture_name);
this.page_name = this.$route.params.lecture_name;
console.log('# to url: ' + this.page_name);
this.$forceUpdate();
}
},
// methods: {
// refresh() {
// d
// }
// },
created() {
console.log("# url: " + this.$route.params.lecture_name);
}
};
</script>
<style>
</style>
LectureTemplate.vue
<template>
<a-layout class="variable_content" style="padding: 0 24px 24px">
<a-breadcrumb style="margin: 16px 0" :routes="router">
<a-breadcrumb-item>
<router-link to="/">
<home-outlined />
</router-link>
</a-breadcrumb-item>
<a-breadcrumb-item>
<router-link to="/lecture/lecture_home_page">
NLP 教程
</router-link>
</a-breadcrumb-item>
<!--a-breadcrumb-item> Home </a-breadcrumb-item-->
<a-breadcrumb-item>{{ this.title }}</a-breadcrumb-item>
</a-breadcrumb>
<a-layout-content :style="{
background: '#fff',
padding: '24px',
margin: 0,
width: '100%',
minHeight: '280px',
}">
<div>
<h1><b class="b_green">{{ this.title }}</b></h1>
<p class="description_text">
发布日期:{{ this.established_time }} 阅读量:{{ this.frontend_page_count }}
</p>
<div v-html="markdownToHtml"></div>
</div>
</a-layout-content>
</a-layout>
</template>
<script>
import { useMeta } from 'vue-meta';
import router from "../../router/index";
import { stat_instance } from "#/utils/request";
import blog_asset from "#/utils/blog_request";
import {
HomeOutlined,
} from "#ant-design/icons-vue";
export default {
name: 'LectureTemplate',
components: {
HomeOutlined,
},
// setup() {
// useMeta({ title: this.title})
// },
props: {
page_name: String, // 英文名,用于请求后端,展示 url
},
data() {
return {
router: router,
title: '',
established_time: '',
frontend_page_count: 0,
markdown: "### loading ...",
}
},
computed: {
markdownToHtml() {
var markdown_content = this.md(this.markdown);
return markdown_content;
}
},
created() {
console.log("## temp url: " + this.page_name);
stat_instance({
url: "/stat_api/frontend_page_statistics",
data: {
page_name: this.page_name,
}
})
.then((response) => {
this.frontend_page_count = response.data.frontend_page_count;
this.title = response.data.title;
this.established_time = response.data.established_time;
})
.catch(() => {
this.frontend_page_count = 0;
});
blog_asset({
url: "/lecture/" + this.page_name + "/README.md",
})
.then((response) => {
this.markdown = response.data;
})
.catch(() => {
this.markdown = "### Failed to request markdown file.";
});
}
}
</script>
<style lang="less" scoped>
h1 {
width: 100%;
// height: 80px;
font-size: 28px;
padding-top: 5px;
margin: 10px;
}
.b_green {
color: #00B441;
}
.description_text {
text-align: right;
font-size: 10px;
color: #777777;
}
</style>
So, what is wrong with my code, and the complete project code is at JioNLP_online.
You could git clone this repository and execute npm run serve to try this code and check the bug.
The program indeed captured the dynamic path of the vue-router but the web page does not changed at all.
Solution I found
I found this post about the same issue here.
Basically you need to add the :key attribute to the <vue-router> component where your page is rendered.
Example:
// this re-renders the page when the path changes
<router-view :key="$route.fullPath"></router-view>
My solution
The :key solution didn't work for me, because I didn't want the router to re-render. This would cause my smooth transition animation between the routes to break. So I tried solving it in a different way.
<script lang="ts" setup>
import { onMounted, watchEffect, ref } from "vue";
import { useRoute } from "vue-router";
const isLoading = ref<boolean>(true);
const route = useRoute();
const loadData = async (id) => {
isLoading.value = true;
// load dynamic data here and change ref values
isLoading.value = false; // after load
};
watchEffect(() => {
loadData(route.params.id);
});
onMounted(() => {
loadData(route.params.id);
});
</script>

Getting navigation duplicated error while the route is being replaced on Vue-Router

I have a problem with vue router as defined on the title above.
Let's say I have a router-view which is renders pages dynamically when the user selected a page from the page selector component. What I'm expecting is I have to get the url to be like this:
http://localhost:port/editor/{appSlug}/layout-editor/page/{pageSlug}
But instead, I got this:
http://localhost:port/editor/{appSlug}/layout-editor/page/{pageSlug}-randomString
And the console shows this error:
NavigationDuplicated {_name: "NavigationDuplicated", name: "NavigationDuplicated", message: "Navigating to current location ("/editor/penerimaa…/page/input-pendaftaran-edrpekvl") is not allowed", stack: "Error↵ at new NavigationDuplicated (webpack-int…/node_modules/vue/dist/vue.runtime.esm.js:3876:9)"}`
I already checked the router file and still can't find out what is wrong with my route. I also tried the solution from this question but still having this error.
Can somebody please help me with this?
Please take a look at my code:
router.js
import Vue from 'vue'
import Router from 'vue-router'
import store from './store/index'
import Home from './views/home/Index.vue'
Vue.use(Router)
let router = new Router({
mode: 'history',
linkActiveClass: 'active',
linkExactActiveClass: 'exact-active',
routes: [{
path: '/',
name: 'home',
component: Home,
meta: {
requiresAuth: true
}
},
{
path: '/login',
name: 'login',
// route level code-splitting
// this generates a separate chunk (login.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('./views/auth/Login.vue'),
meta: {
requiresGuest: true
}
},
{
path: '/register',
name: 'register',
component: () => import('./views/auth/Register.vue'),
meta: {
requiresGuest: true
}
},
{
path: '/forgot-password',
name: 'forgot-password',
component: () => import('./views/auth/extras/ForgotPassword.vue'),
meta: {
requiresGuest: true
}
},
{
path: '/database',
name: 'database',
component: () => import('./views/database/Index.vue'),
meta: {
requiresAuth: true
}
},
{
path: '/third-parties',
name: 'third-parties',
component: () => import('./views/third-parties/Index.vue'),
meta: {
requiresAuth: true
}
},
{
path: '/editor',
component: () => import('./components/ViewRenderer.vue'),
meta: {
requiresAuth: true,
requiresAdmin: true,
requiresEditor: true,
},
children: [{
props: true,
path: ':appSlug/layout-editor',
name: 'layout-editor',
component: () => import('./views/editor/Index.vue'),
children: [{
props: true,
path: 'page/:pageSlug',
name: 'layout-renderer',
component: () => import('./components/LayoutRenderer.vue'), // this is where the error occured.
}],
}]
},
]
})
// Route Middlewares
router.beforeEach((to, from, next) => {
const isLoggedIn = store.getters['auth/isLoggedIn']
// Role getters
const isAdmin = store.getters['auth/isAdmin']
const isEditor = store.getters['auth/isEditor']
// Redirect to the login page if the user is not logged in
// and the route meta record is requires auth
if (to.matched.some(record => record.meta.requiresAuth) && !isLoggedIn) {
next('/login')
}
// Redirect to the homepage page if the user is logged in
// and the route meta record is requires guest
if (to.matched.some(record => record.meta.requiresGuest) && isLoggedIn) {
next('/')
}
// Redirect to the preview page if the user is logged in
// but has no role assigned or the role is user
if (to.matched.some(
record => (
record.meta.requiresAuth &&
record.meta.requiresAdmin &&
record.meta.requiresEditor
)) && isLoggedIn && isAdmin !== true && isEditor !== true) {
next('/')
}
// Pass any access if not matches any of conditions above
next()
})
export default router
Editor/Index.vue
<template>
<div class="layout-editor container-fluid">
<ActivityBar></ActivityBar>
<Sidebar title="Layout Editor">
<PalleteControl></PalleteControl>
<Pallete :items="components" :list-style="pallete"></Pallete>
</Sidebar>
<Navbar class="editor-navbar">
<PageSelector></PageSelector>
<BaseButton id="create-page-button" text="Create new page"></BaseButton>
</Navbar>
<!-- Every selected page layout rendered here -->
<ViewRenderer></ViewRenderer>
<CommitBar></CommitBar>
</div>
</template>
<script>
import components from "#/data/components.json";
import data from "#/data/table.json";
import { mapGetters } from "vuex";
export default {
name: "LayoutEditor",
data() {
return {
components,
pallete: "grid"
};
},
computed: {
...mapGetters({
current: "apps/current" // Get current app
})
},
mounted() {
this.listenPalleteEvent();
this.listenPageSelectorEvent();
},
methods: {
listenPalleteEvent() {
EventBus.$on("switch-list-style", () => this.switchPallete());
},
switchPallete() {
if (this.pallete == "grid") return (this.pallete = "list");
return (this.pallete = "grid");
},
listenPageSelectorEvent() {
EventBus.$on("page-selected", component => {
this.$router.replace({
name: "layout-renderer",
params: { pageSlug: component.pageSlug, component }
});
});
}
}
};
</script>
<style lang="scss" scoped>
.layout-editor {
padding-left: 530px;
}
</style>
components/PageSelector.vue
<template>
<BaseDropdown
id="pages-dropdown-button"
id-obj="pageId"
name-obj="pageName"
:items="filtered"
:has-item-control="true"
text="Create new page or choose one from here"
event-keyword="page-selected"
>
<BaseInput
name="page-filter"
v-model="filter"
:borderless="true"
placeholder="Search by page name..."
></BaseInput>
<template #item-control>
<div class="item-control">
<BaseButton id="duplicate-page-button" text="Duplicate"></BaseButton>
<BaseButton id="delete-page-button" text="Delete"></BaseButton>
</div>
</template>
</BaseDropdown>
</template>
<script>
import { mapGetters } from "vuex";
export default {
data() {
return {
filter: ""
};
},
created() {
// Dispatch fetch page request on vuex store when the instance was created.
this.$store.dispatch("pages/load", this.currentApp);
},
computed: {
// Map getters from vuex store.
...mapGetters({
pages: "pages/pages",
currentApp: "apps/current"
}),
// Filter pages as long as user type in the dropdown input.
filtered() {
return this.pages.filter(page => {
return page.pageName.toLowerCase().includes(this.filter.toLowerCase());
});
}
}
};
</script>
<style lang="scss" scoped>
#import "../../sass/variables";
::v-deep .dropdown-item {
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
&:hover {
.item-control {
opacity: 1;
}
}
}
::v-deep .item-control {
display: flex;
align-items: center;
justify-content: flex-end;
opacity: 0;
.form-group {
margin-bottom: 0;
}
.form-group .btn {
border-radius: 30px;
height: auto;
}
.form-group:first-child .btn {
margin-right: 5px;
}
.form-group:last-child .btn {
background-color: $red;
border-color: $red;
color: white;
&:hover {
background-color: darken($color: $red, $amount: 3);
}
}
}
</style>
components/ViewRenderer.vue
<template>
<router-view />
</template>
components/LayoutRenderer.vue
<template>
<div class="layout-renderer">
<GridLayout
:layout.sync="components"
:col-num="12"
:row-height="30"
:is-draggable="true"
:is-resizable="true"
:is-mirrored="false"
:vertical-compact="true"
:margin="[10, 10]"
:use-css-transforms="false"
:responsive="true"
:auto-size="true"
>
<GridItem
v-for="component in components"
:key="component.i"
:x="component.x"
:y="component.y"
:w="component.w"
:h="component.h"
:i="component.i"
>
<ComponentRenderer :component="component" />
</GridItem>
</GridLayout>
</div>
</template>
<script>
import { mapState } from "vuex";
import VueGridLayout from "vue-grid-layout";
export default {
components: {
GridLayout: VueGridLayout.GridLayout,
GridItem: VueGridLayout.GridItem
},
data() {
return {
components: []
};
},
created() {
this.fetchComponents();
},
methods: {
/**
* Fetch component from the backend based on the pageId
* occured by the vue-router's route parameters.
*
* #return void
*/
fetchComponents() {
let pageId = this.$route.params.component.pageId;
this.$store.dispatch("components/fetchComponents", pageId).then(() => {
this.components = this.$store.getters["components/components"];
});
}
}
};
</script>
<style lang="scss" scoped>
.layout-renderer {
margin-bottom: 100px;
}
#media only screen and (max-width: 501px) {
.vue-grid-item {
height: fit-content !important;
transform: none !important;
position: relative !important;
margin-bottom: 10px;
}
}
#media (hover: none), (hover: on-demand) {
.vue-grid-item {
height: fit-content !important;
transform: none !important;
position: relative !important;
margin-bottom: 10px;
}
}
</style>
While joyBinary's answer solves the problem, it also swallows all other errors which might not be the desired behaviour.
This approach solves this issue:
const originalPush = Router.prototype.push;
Router.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => {
if (err.name !== 'NavigationDuplicated') throw err
});
}
For those using Typescript, here's Errik Sven Puudist's answer converted:
const originalPush = Router.prototype.push;
Router.prototype.push = async function (location: RawLocation) {
let route: Route;
try {
route = await originalPush.call<Router, [RawLocation], Promise<Route>>(this, location);
} catch (err) {
if (err.name !== 'NavigationDuplicated') {
throw err;
}
}
return route!;
}
Use this code in router.js file:
const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err);
}
This code can override catch's exceptions.

How to pass multiple mutations to update Vuex store?

If I mutate the state only once (by committing either of the two mutations shown below), there is no error and chart is updated correctly.
If I run both mutations:
commit('SET_COURSE_MATERIAL', data)
commit('SET_TOOLS_EQUIPMENT', data)
then I get Maximum call stack exceeded: RangeError.
If I comment out the code in the watch property of chart.vue, there are no errors and I can see the state with correct values in console.log
I am getting the error regarding maximum call stack only when I run "npm run dev". When I deploy it to Google Cloud, the site works as expected and I don't get any errors. I even re-checked this by editing some code and re-deploying it twice while also noticing the time in the build logs.
summary.vue
<v-card-text>
<chart
:chart-config.sync="this.$store.state.summary.courseMaterial"
/>
</v-card-text>
...
<v-card-text>
<chart
:chart-config.sync="this.$store.state.summary.toolsEquipment"
/>
</v-card-text>
chart.vue
<template>
<v-flex>
<no-ssr><vue-c3 :handler="handler"/></no-ssr>
</v-flex>
</template>
<script>
import Vue from 'vue'
export default {
name: 'chart',
props: ['chartConfig'],
data() {
return {
handler: new Vue()
}
},
watch: {
chartConfig: function(val) {
console.log('chart component > watch > chartConfig', val)
this.drawChart()
}
},
created() {
this.drawChart()
},
methods: {
drawChart() {
this.handler.$emit('init', this.chartConfig)
}
}
}
</script>
store/summary.js
import axios from 'axios'
import _ from 'underscore'
import Vue from 'vue'
import {
courseMaterialChartConfig,
toolsEquipmentChartConfig,
} from './helpers/summary.js'
axios.defaults.baseURL = process.env.BASE_URL
Object.filter = (obj, predicate) =>
Object.assign(
...Object.keys(obj)
.filter(key => predicate(obj[key]))
.map(key => ({ [key]: obj[key] }))
)
export const state = () => ({
courseMaterial: '',
toolsEquipment: '',
})
export const getters = {
courseMaterial(state) {
return state.courseMaterial
},
toolsEquipment(state) {
return state.toolsEquipment
}
}
export const actions = {
async fetchData({ state, commit, rootState, dispatch }, payload) {
axios.defaults.baseURL = process.env.BASE_URL
let { data: initialData } = await axios.post(
'summary/fetchInitialData',
payload
)
console.log('initialData', initialData)
let [counterData, pieChartData, vtvcData, guestFieldData] = initialData
//dispatch('setCourseMaterial', pieChartData.coureMaterialStatus)
//dispatch('setToolsEquipment', pieChartData.toolsEquipmentStatus)
},
setCourseMaterial({ commit }, data) {
commit('SET_COURSE_MATERIAL', courseMaterialChartConfig(data))
},
setToolsEquipment({ commit }, data) {
commit('SET_TOOLS_EQUIPMENT', toolsEquipmentChartConfig(data))
}
}
export const mutations = {
// mutations to set user in state
SET_COURSE_MATERIAL(state, courseMaterial) {
console.log('[STORE MUTATIONS] - SET_COURSEMATERIAL:', courseMaterial)
state.courseMaterial = courseMaterial
},
SET_TOOLS_EQUIPMENT(state, toolsEquipment) {
console.log('[STORE MUTATIONS] - SET_TOOLSEQUIPMENT:', toolsEquipment)
state.toolsEquipment = toolsEquipment
},
}
helpers/summary.js
export const courseMaterialChartConfig = data => {
return {
data: {
type: 'pie',
json: data,
names: {
received: 'Received',
notReceived: 'Not Received',
notReported: 'Not Reported'
}
},
title: {
text: 'Classes',
position: 'right'
},
legend: {
position: 'right'
},
size: {
height: 200
}
}
}
export const toolsEquipmentChartConfig = data => {
return {
data: {
type: 'pie',
json: data,
names: {
received: 'Received',
notReceived: 'Not Received',
notReported: 'Not Reported'
}
},
title: {
text: 'Job Role Units',
position: 'right'
},
legend: {
position: 'right'
},
size: {
height: 200
}
}
}
Deep copy the chart config.
methods: {
drawChart() {
this.handler.$emit('init', {...this.chartConfig})
}
}

Axios isn't filling store on mount

I'm having an issue regarding state management. I can achieve getting both filling my state and projecting my state onto the frontend. Except I'm having an issue with WHEN the state is getting filled. Whenever I compile my project and I go to the page in question, title: 'test' is shown instead of my api. But when I press f5 the state gets filled with my api call. Is there any reason why my state isn't being filled by the api straight away? I'm using promise, shouldn't rendering wait 'till my api request is "done"?
media/index.vue
<template>
<div>
<section class="hero is-info">
<div class="hero-body">
<div class="container">
<h1 class="title">Wordpress</h1>
<h2 class="subtitle">Media</h2>
</div>
</div>
</section>
<section>
<div class="container p-3">
<p class="title">Media</p>
<div class="posts-wrapper">
<template v-for="media in MediaList">
<nuxt-link class="card" :key="media.id" :to="'/wordpress/media/'+media.id">{{media.title.rendered}}</nuxt-link>
</template>
</div>
</div>
</section>
</div>
</template>
<script>
export default {
head () {
return {
title: 'Wordpress media'
}
},
fetch ({store}) {
store.dispatch('getMediaList')
},
computed: {
MediaList () {
return this.$store.state.getMediaList.mediaList
}
}
}
</script>
<style lang="scss">
.posts-wrapper {
display: flex;
flex-flow: row wrap;
justify-content: space-around;
a {
display: block;
margin: 1em;
padding: 1em;
flex: 1 1 200px;
text-transform: capitalize;
&:hover {
text-decoration: underline;
}
}
}
</style>
store/index.js
import Vuex from 'vuex'
import { getPosts } from './modules/wordpress/posts'
import { getPages } from './modules/wordpress/pages'
import { getMediaList } from './modules/wordpress/media'
const createStore = () => {
return new Vuex.Store({
modules: {
getPosts,
getPages,
getMediaList
}
})
}
export default createStore
store/media.js:
javascript
import API from '../../../api/request'
export const getMediaList = {
state: {
media: {},
mediaList: [{
title: {
rendered: 'test'
}
}]
},
mutations: {
setMediaList: (state, mediaList) => {
state.mediaList = mediaList
},
setCurrentMedia: (state, media) => {
state.media = media
}
},
actions: {
getMediaList ({commit}) {
return API.get(`/wp/media`)
.then((res) => {
commit('setMediaList', res.data)
})
.catch((err) => {
console.log(err)
})
},
getMedia ({commit, store}, id) {
return API.get(`/wp/media/${id}`)
.then((res) => {
commit('setCurrentMedia', res.data)
})
}
}
}
Dumb me, this did the trick:
Fetch:
async fetch ({store}) {
await store.dispatch('getMediaList')
}
Actions:
async getMediaList ({commit}) {
try {
const { data } = await API.get(`/wp/media`)
commit('setMediaList', data)
} catch (error) {
console.log(error)
}
}