store is not defined vue.js - javascript

I have created login page. router intercepting the request and validates the user is authenticated or not . store is maintaining the user is logged in or not.
while debugging i am getting in auth.js
"store is not defined"
I also tried relative path instead of # in imports.
router code snippet
import auth from '#/services/auth';
...
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!auth.loggedIn()) {
next({
path: '/login',
});
} else {
next();
}
} else {
next();
}
});
auth.js is like service which will interact with store and maintain state .
import Vue from 'vue';
import axios from 'axios';
import VueAxios from 'vue-axios';
import store from '#/store/UserStore';
Vue.use(VueAxios, axios);
export default {
login(credentials) {
return new Promise((resolve, reject) => {
Vue.axios.post('/api/authenticate', credentials).then((response) => {
localStorage.setItem('token', response.body.token);
store.commit('LOGIN_USER');
resolve();
}).catch((error) => {
store.commit('LOGOUT_USER');
reject(error);
});
});
},
isUserLoggedIn() {
return store.isUserLoggedIn();
},
};
here is my store to
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
strict: process.env.NODE_ENV !== 'production',
state: {
isLogged: !localStorage.getItem('token'),
user: {},
},
actions: {
},
mutations: {
/* eslint-disable no-param-reassign */
LOGIN_USER(state) {
state.isLogged = true;
},
/* eslint-disable no-param-reassign */
LOGOUT_USER(state) {
state.isLogged = false;
},
},
getters: {
isUserLoggedIn: state => state.isLogged,
},
modules: {
},
});

change export type in UserStore like this:
line
export default new Vuex.Store({
replace with
export const store = new Vuex.Store({

Related

Vuex is not able to find namespace of module

I have a Vue2 sample app and want to add a Vuex store with a todos module. Inside the store folder I changed the index.js file to
import Vue from "vue";
import Vuex from "vuex";
import * as todos from "./modules/todos/index.js";
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
todos
},
});
Inside
/store/modules/todos
I created the following files
index.js
import * as state from "./state.js";
import * as getters from "./getters.js";
export const module = {
namespaced: true,
state,
getters,
};
state.js
export const state = {
todos: []
}
getters.js
export const getters = {
todos(state) {
return state.todos;
}
};
Inside my component I want to access the getter:
<script>
import { mapGetters } from "vuex";
export default {
computed: {
...mapGetters("todos", ["todos"]), // namespace.getter
},
};
</script>
Unfortunately I get this error when loading the component
[vuex] module namespace not found in mapGetters(): todos/
Does someone know what's wrong or missing here? Thanks for help
I think your import/export statements are the culprit.
Try this:
/store.js
import Vue from "vue";
import Vuex from "vuex";
import todos from "./modules/todos";
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
todos
},
});
/store/modules/todos/index.js
import state from "./state";
import getters from "./getters";
const todos = {
namespaced: true,
state,
getters,
};
export default todos;
The other files seem fine.
Work for me
Base API URL
project/src/api/common.js
import axios from 'axios'
export const HTTP = axios.create({
baseURL: 'http://api-url',
})
Base element project/src/api/element.js
import {HTTP} from './common'
function createHTTP(url) {
return {
async post(config) {
return HTTP.post(`${url}`, config).then(response => {
console.log(response)
return response.data
})
},
async get(element) {
return HTTP.get(`${url}${element.id}/`)
},
async patch(element) {
console.log(element)
return HTTP.patch(`${url}${element.id}/`, element).then(response => {
console.log(response)
return response.data
})
},
async delete(id) {
HTTP.delete(`${url}${id}/`)
return id
},
async list(queryParams = '') {
return HTTP.get(`${url}${queryParams}`).then(response => {
return response.data.results
})
}
}
}
export const Todos = createHTTP(`/todos/`)
Your store project/src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import todos from "#/store/modulse/todos";
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
todos,
}
})
Your mutations types project/src/store/mutation-types.js
export const SET_TODOS ='SET_TODOS'
export const PATCH_TODO ='PATCH_TODO'
export const DELETE_TODO ='DELETE_TODO'
export const CREATE_TODO ='CREATE_TODO'
Your module project/src/store/modulse/todos.js
import {
Todos,
} from '#/api/elements'
import {
SET_TODOS, PATCH_TODO, DELETE_TODO, CREATE_TODO
} from '../mutation-types'
// Getters
export default {
state: {
todos: []
},
getters: {
getTodos(state) {
return state.todos
},
},
// Mutations
mutations: {
[SET_TODOS](state, todos) {
state.todos = todos
},
[PATCH_TODO](state, todos) {
let id = todos.id
state.todos.filter(todos => {
return todos.id === id
})[0] = todos
},
[CREATE_TODO](state, todo) {
state.todos = [todo, ...state.todos]
},
[DELETE_TODO](state, {id}) {
state.todos = state.todos.filter(todo =>{
return todo.id !==id
})
},
},
// Actions
actions: {
async setTodos({commit}, queryParams) {
await Todos.list(queryParams)
.then(todos => {
commit(SET_TODOS, todos)
}).catch((error) => {
console.log(error)
})
},
async patchTodo({commit}, todoData) {
await Todos.patch(todoData)
.then(todo => {
commit(PATCH_TODO, todo)
}).catch((error) => {
console.log(error)
})
},
async deleteTodo({commit}, todo_id) {
await Todos.delete(todo_id)
.then(resp => {
commit(DELETE_TODO, todo_id)
}).catch((error) => {
console.log(error)
})
},
async createTodo({commit}, todoData) {
await Todos.create(todoData)
.then(todo => {
commit(CREATE_TODO, todo)
}).catch((error) => {
console.log(error)
})
},
}
In your project/src/main.js
import Vue from 'vue'
import store from './store'
import App from './App.vue'
import Axios from 'axios'
Vue.prototype.$http = Axios;
new Vue({
store,
render: h => h(App),
}).$mount('#app')
In your project/src/App.vue
import {mapActions, mapGetters} from "vuex";
export default {
name: 'App',
components: {},
data() {
return {}
},
methods: {
...mapActions(['setTodos','patchTodo','createTodo','deleteTodo']),
},
computed: {
...mapGetters(['getTodos']),
},
async mounted() {
await this.setTodos()
},
}

Check if user is logged in Laravel sanctum with Vuejs SPA

I am trying to solve this but I can't, I have a website built with Laravel and Vuejs:
This is my app.js
import 'bootstrap';
import './axios';
import Vue from 'vue';
import VueRouter from 'vue-router';
import store from './store';
import router from './router';
store.dispatch('checkAuth');
const app = new Vue({
el: '#app',
store ,
router
});
this is my router.js:
import VueRouter from 'vue-router';
import Login from './components/Login';
import Register from './components/Register';
import Main from './components/Main';
const checkLogin = (to, from, next) =>{
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!store.getters.isAuthenticated) {
next({name: 'login' })
} else {
next()
}
} else if (to.matched.some(record => record.meta.requiresVisitor)) {
if (store.getters.isAuthenticated) {
next({name: 'home' })
} else {
next()
}
} else {
next()
}
}
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/',
beforeEnter: checkLogin,
component: Main,
meta: { requiresAuth: true },
children : [
{
path: "",
name: "home",
component: PostsList
},
....
]
},
{
path: '/login',
beforeEnter: checkLogin,
component: Login,
name:'login',
meta: { requiresVisitor: true }
},
{
path: '/register',
beforeEnter: checkLogin,
component: Register,
name: 'register',
meta: { requiresVisitor: true }
}
]
});
and this is my store:
import Vue from 'vue';
const state = {
user: null,
isAuthenticated: false
};
const getters = {
isAuthenticated(state){
return state.isAuthenticated;
},
currentUser(state){
return state.user;
}
};
async login({commit, dispatch}, credentials) {
await axios.get('/sanctum/csrf-cookie');
const {data} = await axios.post("/login", credentials);
commit('setAuth', data);
},
async checkAuth({commit}) {
const {data} = await axios.get('/api/user');
commit('setAuth', data);
}
}
const mutations = {
setAuth(state, payload) {
state.user = payload.user;
state.isAuthenticated = Boolean(payload.user);
}
};
Then the problem arrives when I refresh the page, it calls the action:
store.dispatch('checkAuth');
then it should wait until the action is done because I did this in the action:
const {data} = await axios.get('/api/user');
But no, it doesn't wait because vue-router is executed and as the user state is not set yet , store.getters.isAuthenticated is false then it redirects to /login, then when I check the vue tools in the browser and see that the state was set correctly even the request to api/user returns the user correctly, Because before that I logged in a user, I need that vue-router waits until the vuex state is set. what can I do? Thank you.
I was able to solve this problem, but I don't know if this is the best way to do it:
in my app.js
Instead of this:
store.dispatch('checkAuth');
const app = new Vue({
el: '#app',
store ,
router
});
I did this:
const VueInstance = ()=>{
new Vue({
el: '#app',
store ,
router
});
}
store.dispatch('checkAuth').then(()=>{
VueInstance();
}).catch(()=>{
VueInstance();
});
Now it is working because the vuex action checkAuth returns a promise, so I needed to wait until it is completed, but, in case the action returns an error, because in the first load the user is not logged in, I must add a catch, because th Vue should be created whether the user is logged in or not. If someone have a better solution let me know. Thank you.

How to hide and deny access to some routes in VueJS with Store state?

After authorization, I write the user type to the state, based on this type, I want to show / hide some routes.
src/store/index.js:
import Vue from "vue";
import Vuex from "vuex";
import getters from "./getters";
import user from "./modules/user";
Vue.use(Vuex);
const store = new Vuex.Store({
modules: { user },
getters
});
export default store;
src/store/getters.js:
const getters = {
token: state => state.user.token,
name: state => state.user.name,
type: state => state.user.type
};
export default getters;
src/router/index.js:
import Vue from "vue";
import Router from "vue-router";
import Layout from "#/layout";
Vue.use(Router);
export const constantRoutes = [
{
path: "/login",
component: () => import("#/views/Login"),
hidden: true
},
{
path: "/",
component: Layout,
redirect: "/dashboard",
children: [
{
path: "dashboard",
name: "Dashboard",
component: () => import("#/views/Dashboard"),
meta: { title: "routes.dashboard", icon: "el-icon-odometer" }
}
]
},
{
path: "/providers",
component: Layout,
redirect: "/providers/list",
name: "Providers",
meta: { title: "routes.providers", icon: "el-icon-suitcase-1" },
children: [
{
path: 'list',
name: "List",
component: () => import("#/views/providers/ProvidersList"),
meta: { title: "routes.providersList", icon: "el-icon-document" }
}
]
}
];
const createRouter = () =>
new Router({
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
});
const router = createRouter();
export function resetRouter() {
const newRouter = createRouter();
router.matcher = newRouter.matcher;
}
export default router;
Authorization control in a separate file src/permission.js:
import router from "./router";
import store from "./store";
import { Message } from "element-ui";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
import { getToken } from "#/utils/auth";
import getPageTitle from "#/utils/get-page-title";
NProgress.configure({ showSpinner: false });
const whiteList = ["/login"];
router.beforeEach(async (to, from, next) => {
NProgress.start();
document.title = getPageTitle(to.meta.title);
const hasToken = getToken();
if (hasToken) {
if (to.path === "/login") {
next({ path: "/" });
NProgress.done();
} else {
const hasGetUserInfo = store.getters.name;
if (hasGetUserInfo) {
next();
} else {
try {
await store.dispatch("user/getInfo");
next();
} catch (error) {
await store.dispatch("user/resetToken");
Message.error(error || "Has Error");
next(`/login?redirect=${to.path}`);
NProgress.done();
}
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) {
next();
} else {
next(`/login?redirect=${to.path}`);
NProgress.done();
}
}
});
router.afterEach(() => {
NProgress.done();
});
As you can see all the code is a collection of copy-paste solutions found somewhere and now I'm completely stuck. How can I hide and deny access to certain routes for users with different state.user.type?
Converting my comment to answer.
Perhaps it will be easier (for you) to use an existing (and tested) solution - something like Vue-ACL or even more advanced.

How to mock vue router in a Vuex store test with Jest?

I have a vuex store like this:
// store.js
import Vuex from 'vuex'
import router from '../router' // this is a vuejs router
export const actions = {
async load({ dispatch, commit }) {
if (router.currentRoute.name === 'one-route') {
dispatch('oneModule/oneAction', null, { root: true })
}
}
}
export default new Vuex.Store({
state,
actions,
...
})
I would like to test it with Jest.
// store.test.js
import { createLocalVue } from '#vue/test-utils'
import Vuex from 'vuex'
import VueRouter from 'vue-router'
import { actions } from './store'
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(VueRouter)
describe('store tests', () => {
let store, router, oneAction
beforeEach(() => {
oneAction = jest.fn()
const modules = {
oneModule: {
namespaced: true,
actions: { oneAction }
}
}
store = new Vuex.Store({ actions, modules })
router = new VueRouter({ routes: [{ name: 'one-route' }] })
}
test('call module action if one-route is selected', async () => {
router.push({ name: 'one-route' })
await store.dispatch('load')
expect(oneAction).toHaveBeenCalled()
})
}
This makes the following error:
Expected mock function to have been called, but it was not called.
What is the correct way to mock the router to make this test pass?
Thank you

Vue.js vuex state not working correctly

I'm using Vuex in my project with vue.js 2.0. My app.js looks like this:
import VueRouter from 'vue-router';
import Login from './components/Login.vue';
import Home from './components/Home.vue';
import VModal from 'vue-js-modal';
import Vuex from 'vuex';
import store from './store';
window.Vue = require('vue');
Vue.use(VueRouter);
Vue.use(VModal);
Vue.use(Vuex);
window.Bus = new Vue();
const routes = [
{ path: '/', component: Login, name: 'login' },
{ path: '/home', component: Home, name: 'home', beforeEnter: requireAuth },
];
const router = new VueRouter({
routes // short for `routes: routes`
});
const app = new Vue({
router,
store
}).$mount('#app');
function requireAuth() {
return this.$store.state.isLoggedIn;
}
My store looks like this:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const LOGIN = "LOGIN";
const LOGIN_SUCCESS = "LOGIN_SUCCESS";
const LOGOUT = "LOGOUT";
const store = () => {
return new Vuex.Store({
state: {
isLoggedIn: !!localStorage.getItem("token"),
user: null
},
mutations: {
[LOGIN] (state) {
state.pending = true;
},
[LOGIN_SUCCESS] (state) {
state.isLoggedIn = true;
state.pending = false;
},
[LOGOUT](state) {
state.isLoggedIn = false;
}
},
actions: {
login({state, commit, rootState}) {
commit(LOGIN_SUCCESS);
},
setUser({state, commit, rootState}, user) {
//todo
}
}
});
}
export default store;
However when I try to access a value from the state in my requireAuth function:
return this.$store.state.isLoggedIn;
or
return this.store.state.isLoggedIn;
I get the error:
Cannot read property '$store' of undefined
What could be wrong here?
--EDIT--
When I console.log(store); I see:
store() {
var _mutations;
return new __WEBPACK_IMPORTED_MODULE_1_vuex__["a" /* default */].Store({
state: {
isLoggedIn: !!localStorage.getItem("token"),
You have the function declared in the global scope like this:
function requireAuth() {
return this.$store.state.isLoggedIn;
}
So when you call this function this is bound by default to global object. But since ES6 this will be undefined instead of the global object. So you get the error cannot read $store of undefined
Since you are importing the store in app.js you can directly use:
function requireAuth() {
return store.state.isLoggedIn;
}
EDIT
export the created store instance itself, not a function that returns a store instance as follows:
store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const LOGIN = "LOGIN";
const LOGIN_SUCCESS = "LOGIN_SUCCESS";
const LOGOUT = "LOGOUT";
const store = new Vuex.Store({
state: {
isLoggedIn: !!localStorage.getItem("token"),
user: null
},
mutations: {
[LOGIN] (state) {
state.pending = true;
},
[LOGIN_SUCCESS] (state) {
state.isLoggedIn = true;
state.pending = false;
},
[LOGOUT](state) {
state.isLoggedIn = false;
}
},
actions: {
login({state, commit, rootState}) {
commit(LOGIN_SUCCESS);
},
setUser({state, commit, rootState}, user) {
//todo
}
}
});
export default store;
The requireAuth function should be:
function requireAuth() {
return store.state.isLoggedIn;
}
requireAuth is just a function defined in your app.js and this.$store is how you would refer to the store inside a Vue method. Instead, you can just refer to it in the function as store.

Categories

Resources