I am trying to get a dynamic title for useMeta with composition API but it does not work.
<script setup>
import { computed } from 'vue'
import { POST } from '#/constants/blog'
import { useQuery, useResult } from "#vue/apollo-composable";
import { useRoute } from 'vue-router'
import { useMeta } from "vue-meta";
const route = useRoute();
const variables = computed(() => ({
slug: route.params.slug,
}));
const { result, loading, error } = useQuery(
POST, variables
);
const post = useResult(result, null, data => data.post.data );
const metaTitle = computed(() => ({
title: post.attributes.title,
}));
useMeta(metaTitle);
</script>
here is the response
{
"data": {
"post": {
"data": {
"id": 4,
"attributes": {
"title": "This is the post title"
}
}
}
}
}
Please help me understand what is wrong here!
Maybe It's too late to answer this question.
This module is for vue2. After many searches, I found version 3 of this module, But It's at the alpha stage, now.
I found an alternative solution that doesn't need any dependency.
Create a new file somewhere in your project directory(utils.js) and put the below code in it:
const changeMetaTags = (meta) => {
document.title = `${meta.title} - YOUR PROJECT NAME`;
// document.querySelector('meta[name="og:title"]').setAttribute("content", meta['og:title']);
// document.querySelector('meta[name="description"]').setAttribute("content", meta.description);
// document.querySelector('meta[name="og:description"]').setAttribute("content", meta['og:description']);
// document.querySelector('meta[name="keywords"]').setAttribute("content", meta.keywords);
}
export { changeMetaTags }
Caution: You have to have the above code on your index.html file.
and for your use case just import it and use:
<script setup>
import { computed } from 'vue'
import { POST } from '#/constants/blog'
import { useQuery, useResult } from "#vue/apollo-composable";
import { useRoute } from 'vue-router'
import { useMeta } from "vue-meta";
import { changeMetaTags } from "#/infrastructures/seo/utils"; // <----- this
const route = useRoute();
const variables = computed(() => ({
slug: route.params.slug,
}));
const { result, loading, error } = useQuery(
POST, variables
);
const post = useResult(result, null, data => data.post.data );
const metaTitle = computed(() => ({
title: post.attributes.title,
}));
changeMetaTags(metaTitle.value); // <---- this
</script>
I use it in the router file (router/index.js) as well
const router = createRouter({
routes: [
{
path: "/",
component: () => import("#/layouts/MainLayout.vue"),
children: [
{
path: "",
name: "Home",
meta: { // <-------- add this
title: "Home",
description:
"your description",
"og:title": `YOUR PROJECT NAME home page`,
"og:description":
"og description",
keywords:
`your, keywords`,
},
component: () => import("#/views/HomeView.vue"),
},
...
]
})
router.beforeEach((to, from) => {
changeMetaTags(to.meta); // <----- and this
...
})
Related
This is my first time using useRouter and i really dont know how it works.
I want to take props.indexUrl and added dynamiacally into the url below, i have done several ways but always getting error.
import { useRouter } from "next/router";
const Component = () => {
const router = useRouter();
const {
query: { indexUrl },
} = router;
const props = {
indexUrl,
};
return props.indexUrl;
};
export const urls = [
{
url:
"click.myyellowlocal.com/k.php?ai=19202&url=http%3a%2f%2f" +
Component,
},
{
url: "cse.google.vu/url?q=https%3A%2F%2",
},
{
url: "sazhs.co.kr/member/login.html?noMemberOrder=&returnUrl=http%3a%2f%2",
},
];
I have try like this before
import { useRouter } from "next/router";
const router = useRouter();
const {
query: { indexUrl },
} = router;
const props = {
indexUrl,
};
export const urls = [
{
url:
"click.myyellowlocal.com/k.php?ai=19202&url=http%3a%2f%2f" +
props.indexUrl,
},
{
url: "cse.google.vu/url?q=https%3A%2F%2",
},
{
url: "sazhs.co.kr/member/login.html?noMemberOrder=&returnUrl=http%3a%2f%2",
},
];
and give an error Cannot read properties of null (reading 'useContext')
so i make like this
const Component = () => {
const router = useRouter();
const {
query: { indexUrl },
} = router;
const props = {
indexUrl,
};
};
but i dont know how to get props.indexUrl to url like in the top code.
more detail, the router indexUrl is from other file
function sendProps() {
Router.push({
// pathname: "/processUrl",
pathname: "/urlList",
query: { indexUrl },
});
}
how to get the value of props.indexUrl and add it into the list of url dynamiacally ??
React Testing Using Mock service worker is returning undefined and then taking values from the actual API. As you can see from the image down below the test is getting passed by getting values from the actual API and the name ARLO WANG is getting pulled out. Where as the name I have kept in the mockResponse is "first last" in the handler.js file.
FollowersList.js
import React, { useEffect, useState } from 'react'
import "./FollowersList.css"
import axios from "axios"
import { Link } from 'react-router-dom';
import { v4 } from 'uuid';
export default function FollowersList() {
const [followers, setFollowers] = useState([]);
useEffect(() => {
fetchFollowers()
}, []);
const fetchFollowers = async () => {
const {data} = await axios.get("https://randomuser.me/api/?results=5")
setFollowers(data.results)
}
// console.log(followers)
return (
<div className="followerslist-container">
<div>
{followers.map((follower, index) => (
<div className="follower-item" key={v4()} data-testid={`follower-item-${index}`}>
<div className="followers-details">
<div className="follower-item-name">
<h4>{follower.name.first}</h4> <h4>{follower.name.last}</h4>
</div>
<p>{follower.login.username}</p>
</div>
</div>
))}
</div>
<div className="todo-footer">
<Link to="/">Go Back</Link>
</div>
</div>
)
}
FollowersList.test.js
import { render, screen } from "#testing-library/react";
import { BrowserRouter } from "react-router-dom";
import FollowersList from "../FollowersList";
const MockFollowersList = () => {
return (
<BrowserRouter>
<FollowersList />
</BrowserRouter>
);
};
describe("FollowersList Component", () => {
test("renders first follower", async () => {
render(<MockFollowersList />);
screen.debug()
expect(await screen.findByTestId("follower-item-0")).toBeInTheDocument();
});
});
src/mock/handler.js
import { rest } from 'msw';
const mockResponse = {
data: {
results: [
{
name: {
first: "first",
last: "last",
},
login: {
username: "x",
},
},
],
},
};
export const handlers = [
rest.get('https://randomuser.me/api/', (req, res, ctx) => {
return res(ctx.json({mockResponse}))
}
})
]
VSCODE terminal
Something is going wrong in the return line in handlers array in the handler file. It's not sending back the mockResponse correctly.
Found the mistake. The response structure returned by the actual API and the msw is different. Just had to remove the 'data' object in the mockResponse and keep the it just as an array of 'results'.
import { rest } from 'msw';
const mockResponse = {
results: [
{
name: {
first: "first",
last: "last",
},
login: {
username: "x",
},
},
],
};
export const handlers = [
rest.get('https://randomuser.me/api/', (req, res, ctx) => {
return res(ctx.json(mockResponse))
}
})
]
I'm fairly new to React testing library and am using a function within a useEffect to decode a user token from keycloak when they sign up, to determine what type of user they are and render different Menu's based on that. This new Jwt function I created though, is causing a lot of my previously working tests within other files to fail as it throws an error like below:
I'm sure how to deal with this error on the testing side, should I be mocking this decoder function within the test file?
This is my main file:
import React, {useEffect, useState, useMemo, useCallback} from "react";
import {withTranslation} from "react-i18next";
import "./index.scss";
import {historyObject} from "historyObject";
import {Heading} from "#xriba/ui";
import { keycloak } from "utils/keycloak";
export const Menu = (props) => {
const {t} = props;
const [userHasCommunities, setUserHasCommunities] = useState(false);
useEffect(() => {
function parseJwt (token) {
var base64Url = token.split('.')[1];
var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
var jsonPayload = decodeURIComponent(window.atob(base64).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
if (JSON.parse(jsonPayload).communities?.length > 0){
setUserHasCommunities(true)
}
return JSON.parse(jsonPayload);
};
parseJwt(keycloak.token);
}, [userHasCommunities])
const buildItem = useCallback((item) => {
const isCurrent = historyObject.location.pathname.includes(item.path);
return <li key={item.path} className={isCurrent ? "selected" : ""} onClick={() => historyObject.push(item.path)}>
<Heading level={"4"}>{t(item.title)}</Heading>
</li>
}, [t])
const renderMenu = useMemo(() => {
let menuItems = []
if (userHasCommunities){
menuItems = [
{
path: "/portfolio",
title: "pages.portfolio.menu_entry"
},
{
path: "/transactions",
title: "pages.transactions.menu_entry"
},
{
path: "/community",
title: "pages.community.menu_entry"
},
{
path: "/reports",
title: "pages.reports.menu_entry"
}
]
} else {
menuItems = [
{
path: "/portfolio",
title: "pages.portfolio.menu_entry"
},
{
path: "/transactions",
title: "pages.transactions.menu_entry"
},
{
path: "/reports",
title: "pages.reports.menu_entry"
}
]
}
return menuItems.map(i => buildItem(i))
}, [userHasCommunities, buildItem])
return <div className={"menu"}>
<ul>
{renderMenu}
</ul>
</div>
}
export default withTranslation()(Menu)
And my current test file:
import React from "react";
import {shallow} from "enzyme";
import {Menu} from "features/layouts/logged-in/menu/index";
import {historyObject} from "historyObject";
import { keycloak } from "utils/keycloak";
jest.mock("utils/keycloak");
jest.mock("historyObject")
describe("Menu test", () => {
const props = {
t: jest.fn(),
};
beforeEach(() => {
jest.resetAllMocks();
jest.spyOn(React, "useEffect").mockImplementationOnce(x => x()).mockImplementationOnce(x => x()).mockImplementationOnce(x => x()).mockImplementationOnce(x => x());
});
it('should render Menu', () => {
const wrapper = shallow(<Menu {...props} />);
expect(wrapper).toBeDefined();
wrapper.find('li').at(0).prop('onClick')();
expect(historyObject.push).toHaveBeenCalled()
});
it('should render Menu with an object as current', () => {
historyObject.location.pathname = "/portfolio"
const wrapper = shallow(<Menu {...props} />);
expect(wrapper).toBeDefined();
expect(wrapper.find('.selected')).toHaveLength(1);
});
});
Thanks in advance for any advice!
I'm using Strapi as a Headless CMS and building my frontend with Gatsby + Graphql. I have a "blocks renderer" component that is rendering any of the dynamic zones in strapi.
import React from "react"
import { graphql } from "gatsby"
import BlockHero from "./block-hero"
import BlockParagraph from "./block-paragraph"
import BlockSplitFeature from "./block-split-feature"
const componentsMap = {
// STRAPI__COMPONENT_LAYOUT_ELEMENTS_MULTIPLE_CALLOUT: blockMultipleCallout,
STRAPI__COMPONENT_LAYOUT_ELEMENTS_SIMPLE_PARAGRAPH: BlockParagraph,
STRAPI__COMPONENT_LAYOUT_ELEMENTS_SPLIT_FEATURE: BlockSplitFeature,
STRAPI__COMPONENT_MEDIA_ELEMENT_HERO: BlockHero,
// STRAPI__COMPONENT_META_DATA_DEFAULT_SEO: blockSeo
}
const Block = ({ block }) => {
const Component = componentsMap[block.__typename]
if(!Component) {
return null
}
return <Component data={block} />
}
const BlocksRenderer = ({ blocks }) => {
return (
<div>
{blocks.map((block, index) => (
<Block key={`${index}${block.__typename}`} block={block} />
))}
</div>
)
}
export const query = graphql`
fragment Blocks on STRAPI__COMPONENT_LAYOUT_ELEMENTS_CTASTRAPI__COMPONENT_LAYOUT_ELEMENTS_MULTIPLE_CALLOUTSTRAPI__COMPONENT_LAYOUT_ELEMENTS_SIMPLE_PARAGRAPHSTRAPI__COMPONENT_LAYOUT_ELEMENTS_SPLIT_FEATURESTRAPI__COMPONENT_MEDIA_ELEMENT_HEROUnion {
__typename
... on STRAPI__COMPONENT_LAYOUT_ELEMENTS_MULTIPLE_CALLOUT {
id
MultipleCalloutItem {
id
Heading
Description
}
}
... on STRAPI__COMPONENT_LAYOUT_ELEMENTS_SIMPLE_PARAGRAPH {
id
Text
}
... on STRAPI__COMPONENT_LAYOUT_ELEMENTS_SPLIT_FEATURE {
id
Heading
Description
mediaAlignment
Media {
id
mime
localFile {
childImageSharp {
gatsbyImageData
}
}
alternativeText
}
}
... on STRAPI__COMPONENT_MEDIA_ELEMENT_HERO {
id
Heading
Description
Media {
id
mime
alternativeText
localFile {
url
}
alternativeText
}
}
}
`
export default BlocksRenderer
Then I have my page layout file to generate a page layout (side note, the "Layout" element is just for the navigation & footer. This will be rewritten once I have this page layout file issue fixed)>
import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Layout from "../components/layout"
import Seo from "../components/seo"
import BlocksRenderer from "../components/blocks-renderer"
const PageLayout = () => {
const { allStrapiPage } = useStaticQuery(graphql`
query {
allStrapiPage {
edges {
node {
id
Name
Slug
Blocks {
...Blocks
}
}
}
}
}
`)
const { Blocks } = allStrapiPage
return (
<Layout>
<div>{allStrapiPage.id}</div>
<h1>{allStrapiPage.Name}</h1>
<BlocksRenderer blocks={allStrapiPage.Blocks} />
</Layout>
)
}
export default PageLayout
I'm dynamically creating pages with a gatsby-node.js file. When I try to access one of the dynamically created slugs, I get an error in the blocks-renderer file that says can't access property "map", blocks is undefined. Anyone have any ideas?
EDIT: Added the additional files mentioned.
gatsby-config.js file below:
/**
* Configure your Gatsby site with this file.
*
* See: https://www.gatsbyjs.com/docs/gatsby-config/
*/
require("dotenv").config({
path: `.env.${process.env.NODE_ENV}`,
})
module.exports = {
/* Your site config here */
plugins: [
"gatsby-plugin-gatsby-cloud",
"gatsby-plugin-postcss",
"gatsby-plugin-sass",
"gatsby-plugin-image",
"gatsby-plugin-sharp",
"gatsby-transformer-sharp",
"gatsby-transformer-remark",
{
resolve: "gatsby-source-strapi",
options: {
apiURL: process.env.STRAPI_API_URL || "http://localhost:1337",
accessToken: process.env.STRAPI_TOKEN,
collectionTypes: [
"drink",
"category",
{
singularName: "page",
queryParams: {
populate: {
Blocks: {
populate: "*",
MultipleCalloutItem: {
populate: "*",
},
},
PageMeta: {
populate: "*",
},
ParentPage: {
populate: "*",
},
},
},
},
],
singleTypes: [
{
singularName: "global",
queryParams: {
populate: {
DefaultSeo: {
populate: "*",
},
Favicon: {
populate: "*",
},
},
},
},
{
singularName: "homepage",
queryParams: {
populate: {
Blocks: {
populate: "*",
},
},
},
},
],
queryLimit: 1000,
}
},
],
}
home.js (which works as intended).
import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Layout from "../components/layout"
import Seo from "../components/seo"
import BlocksRenderer from "../components/blocks-renderer"
const HomePage = () => {
const { strapiHomepage } = useStaticQuery(graphql`
query {
strapiHomepage {
Blocks {
...Blocks
}
}
}
`)
const { Blocks } = strapiHomepage
// const seo = {
// metaTitle: title,
// metaDescription: title
// }
return (
<Layout>
<BlocksRenderer blocks={Blocks} />
</Layout>
)
}
export default HomePage
This is the gatsby-node.js file I'm using to generate the pages with the page-layout.js file. Note that I can generate the pages and content, minus the Blocks query.
const path = require('path')
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
const result = await graphql(
`
query {
allStrapiPage {
edges {
node {
Slug
Name
ParentPage {
Slug
}
}
}
}
}
`
)
if (result.errors) {
reporter.panicOnBuild(`Error while running GraphQL Query`)
return
}
const pageTemplate = path.resolve(`./src/layouts/page-layout.js`)
result.data.allStrapiPage.edges.forEach(({ node }) => {
const path = node.Slug
createPage({
path,
component: pageTemplate,
context: {
pagePath: path
},
})
})
}
The problem is here:
<BlocksRenderer blocks={allStrapiPage.Blocks} />
You can't access directly to Blocks because you node is an array inside edges property. From what I see, the loop is done in BlocksRenderer hence you need to provide it an array of blocks. Without knowing exactly your data structure and what returns it's difficult to guess but try something like:
<BlocksRenderer blocks={allStrapiPage.edges.node[0].Blocks} />
I have a Home.js file that is using a different property
(allStrapiHomepage) and BlockRenderer is working as expected
If your Home.js query is using a page query instead of a static query they cane be triggered and hydrated in different runtimes and build times, so one can fail if the other doesn't. This leads me to think that maybe the query is ok, but the logic isn't. You can easily check it by adding a simple condition like:
<BlocksRenderer blocks={allStrapiPage?.Blocks} />
Or:
{allStrapiPage.Blocks && <BlocksRenderer blocks={allStrapiPage.Blocks} />}
Thanks to #Ferran I was pointed in the right direction and solved this issue.
Two changes needed to be made for this to work properly. First, I needed to be passing pageContext from the gatsby-node.js file. Here I'm passing the page slug to the template
const { resolve } = require('path')
const path = require('path')
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
const result = await graphql(
`
query {
allStrapiPage {
edges {
node {
Slug
Name
ParentPage {
Slug
}
}
}
}
}
`
)
if (result.errors) {
reporter.panicOnBuild(`Error while running GraphQL Query`)
return
}
const pageTemplate = path.resolve('./src/layouts/page-layout.js')
result.data.allStrapiPage.edges.forEach(edge => {
const path = `${edge.node.Slug}`
const parentPath = `${edge.node.ParentPage.Slug}`
createPage({
path,
component: pageTemplate,
context: {
Slug: edge.node.Slug
},
})
resolve()
})
}
Then in the page-layout.js file, I needed to get the pageContext from gatsby-node.js, map all of my page nodes, in the graphql query, and pass the page Slug from gatsby-node.js as a variable in the graphql query.
import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Layout from "../components/layout"
import Seo from "../components/seo"
import BlocksRenderer from "../components/blocks-renderer"
const PageLayout = ({ data, pageContext }) => {
const { Slug } = pageContext
console.log(Slug)
return (
<Layout>
{
data.allStrapiPage.nodes.map(node => {
return (
<div key={node.id}>
<h1>{node.Name}</h1>
{node.Blocks &&
<BlocksRenderer blocks={node.Blocks} />
}
</div>
)
})
}
</Layout>
)
}
export const query = graphql`
query GetPage($Slug: String) {
allStrapiPage(filter: { Slug: {in: [$Slug]} }) {
nodes {
id
Name
Blocks {
...Blocks
}
}
}
}
`
export default PageLayout
Now I can dynamically create pages with Strapi and the "blocks" I made using dynamic zones.
I have setup my routes.js file to import my state from my store. This is working as when I console.log(state) it outputs my store to console successfully:
I then define my route as below:
routes.js
import { state } from './store/store';
// import { mapState, mapGetters } from "vuex";
console.log(state)
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/dashboard',
name: 'dashboard',
component: Dashboard,
},
{
path: '/project/:id',
name: 'project',
component: Project,
props: true,
meta: {
requiresAuth: true,
},
children: [
{
path: 'module/:module',
name: 'module',
component: Tasks,
props: true,
children: [
{
path: 'task/:url',
name: 'task',
component: () => import(`./components/ProductServiceAnalysis/${$state.taskURL}.vue`),
props: true,
I am getting the error:
app.js:59653 [vue-router] Failed to resolve async component default: ReferenceError: state is not defined in relation to the second last line where I try to access the state.taskURL variable.
Why is this erroring? And how can I access my taskURL variable in my store from my Router?
If I am approaching this incorrectly then please offer suggestions.
This is my store.js:
import Vue from 'vue';
import Vuex from 'vuex';
import axios from 'axios'
Vue.use(Vuex);
axios.defaults.baseURL = 'http://buildmybusiness.test/api'
Vue.config.devtools = true;
export const state = {
token: localStorage.getItem('access_token') || null,
requiredTask: 'This is my current task',
currentModule: '1',
currentModuleName: 'Product & Service Analysis',
currentTask: '1',
modules:[],
tasks:[],
taskName:[],
actions:[],
userId: localStorage.getItem('loggedin_user') || null,
userName: localStorage.getItem('loggedin_username') || null,
projects:[],
currentProjectId: '',
currentProjectName: '',
taskURL: 'define-product-service'
}
export const store = new Vuex.Store({
state,
mutations: {
SET_MODULES: (state, payload) => {
state.modules = payload;
},
SET_TASKS: (state, tasks) => {
state.tasks = tasks;
},
SET_MODULE_TITLE: (state, moduleTitle) => {
state.currentModuleName = moduleTitle
},
SET_ACTIONS: (state, payload) => {
state.actions = payload;
},
RETRIEVE_TOKEN: (state, token) => {
state.token = token;
},
DESTROY_TOKEN: (state) => {
state.token = null;
},
SET_USERID: (state, userid) => {
state.userId = userid;
},
DESTROY_USERID: (state) => {
state.userId = null;
},
SET_USERNAME: (state, username) => {
state.userName = username;
},
DESTROY_USERNAME: (state) => {
state.userName = '';
},
SET_PROJECTS: (state, projects) => {
state.projects = projects;
},
DESTROY_PROJECTS: (state) => {
state.projects = [];
},
SET_PROJECT_ID: (state, projectId) => {
state.currentProjectId = projectId;
},
SET_PROJECT_NAME: (state, projectName) => {
state.currentProjectName = projectName;
},
SET_ACTION_URL: (state, taskURL) => {
state.taskURL = taskURL;
},
},
getters: {
loggedIn(state){
return state.token !== null;
},
SelectedTaskURL(state) {
return state.taskURL;
}
},
actions: {
setActionsURL(context, taskURL){
context.commit("SET_ACTION_URL", taskURL);
},
setProject(context, projectDetails){
const projectId = projectDetails.projectId;
const projectName = projectDetails.projectName;
context.commit("SET_PROJECT_ID", projectId);
context.commit("SET_PROJECT_NAME", projectName);
},
fetchProjects(context) {
axios.defaults.headers.common['Authorization'] = 'Bearer ' + context.state.token;
return axios.get('/project').then(response => {
const projectNames = response.data.map(project => project);
context.commit("SET_PROJECTS", projectNames);
});
},
getUserDetails(context) {
axios.defaults.headers.common['Authorization'] = 'Bearer ' + context.state.token;
return axios.get('/user').then(response => {
const userid = response.data.id
localStorage.setItem('loggedin_user', userid)
context.commit("SET_USERID", userid);
const username = response.data.name
localStorage.setItem('loggedin_username', username)
context.commit("SET_USERNAME", username);
});
},
register(context, data) {
return new Promise ((resolve, reject) => {
axios.post('/register', {
name: data.name,
email: data.email,
password: data.password,
})
.then(response => {
resolve(response)
})
.catch(error => {
reject(error);
})
})
},
destroyToken(context){
axios.defaults.headers.common['Authorization'] = 'Bearer ' + context.state.token
if (context.getters.loggedIn){
return new Promise ((resolve, reject) => {
axios.post('/logout')
.then(response => {
localStorage.removeItem('access_token')
context.commit("DESTROY_TOKEN")
context.commit("DESTROY_USERID")
context.commit("DESTROY_USERNAME")
context.commit("DESTROY_PROJECTS")
resolve(response)
})
.catch(error => {
localStorage.removeItem('access_token')
context.commit("DESTROY_TOKEN")
context.commit("DESTROY_USERID")
context.commit("DESTROY_USERNAME")
context.commit("DESTROY_PROJECTS")
reject(error);
})
})
}
},
loadModules(context) {
axios.defaults.headers.common['Authorization'] = 'Bearer ' + context.state.token
return axios.get('/modules').then(response => {
context.commit("SET_MODULES", response.data);
});
},
getTasks(context, moduleDetails){
var moduleTitle = moduleDetails.moduleName;
var moduleTitle = (moduleTitle === undefined) ? moduleTitle = 'Product & Service Analysis' : moduleTitle;
//console.log(moduleTitle);
var moduleId = moduleDetails.moduleId;
var moduleId = (moduleId === undefined) ? moduleId = 1 : moduleId;
return axios.get(`project/${context.state.currentProjectId}/module/${moduleId}`)
.then(response => {
context.commit("SET_TASKS", response.data);
context.commit("SET_MODULE_TITLE", moduleTitle);
});
},
loadTasks(context, tasks){
},
loadActions(context){
},
retrieveToken(context, credentials){
return new Promise ((resolve, reject) => {
axios.post('/login', {
username: credentials.username,
password: credentials.password,
})
.then(response => {
const token = response.data.access_token
localStorage.setItem('access_token', token)
context.commit("RETRIEVE_TOKEN", token)
resolve(response)
})
.catch(error => {
console.log(error);
reject(error);
})
})
},
}
});
my app.js
// main.js
require('./bootstrap');
import Vue from 'vue';
import App from './App.vue';
import VueRouter from 'vue-router';
import VueAxios from 'vue-axios';
import axios from 'axios';
import routes from './routes';
import BootstrapVue from 'bootstrap-vue'
import { store } from './store/store';
import Vuex from 'vuex'
Vue.config.productionTip = false;
Vue.use(VueRouter);
Vue.use(VueAxios, axios);
Vue.use(BootstrapVue);
Vue.use(Vuex);
const router = new VueRouter({
store,
routes,
mode: 'history'
})
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!store.getters.loggedIn) {
next({
name: 'login',
})
} else {
next()
}
} else if (to.matched.some(record => record.meta.requiresVisitor)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (store.getters.loggedIn) {
next({
name: 'dashboard',
})
} else {
next()
}
} else {
next() // make sure to always call next()!
}
})
new Vue({
store: store,
router,
render: h => h(App)
}).$mount('#app');
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap-vue/dist/bootstrap-vue.css';
If reference to #shazyriver:
I have done as you suggested. I have put a console.log(./components/ProductServiceAnalysis/${state.taskURL}.vue); before const routes = [ ... which correctly accesses the taskURL property and prints it to console. However, it still fails with a 'state undefined' when it tries to access the same property from within the route itself - even though it works when accessed outside the const routes = [:
See console log for detail
First of all, your configuration and all your imports are correct.
It's very interesting issue...I have researched it and can conclude that there is a kind of bug in transpilation process of webpack+babel. Let me explain:
If you check your bundle you can see that there is strange untranspiled concat expression in your dynamic import line, something like this: ("./".concat(state.taskURL,".vue")) - but state should be wrapped with webpack helpers but it wasn't...Looks like module resolving was skipped for import statement string interpolation.
The simplest solution is just assign imported module to some variable and use that variable in the import statement(I recommend to use fully configured store instead of state):
import { store } from './store/store';
let storeVar = store;
//...
//...below
component: () => import(`./components/ProductServiceAnalysis/${storeVar.state.taskURL}.vue`),
In this case module will be processed correctly by webpack.
P.S. I had created clean project with just webpack and tried to play with dynamic imports and they was resolved successfully...So I suppose that issue in another transpilation layer, maybe babel.
P.P.S. If my explanation is not enough clear please feel free to ask in comments.
You just need to import it like:
import store from './store/store.js'
Then you can use it like:
store.commit('increaseCounter')