Get $store data in ~/plugins/axios - vue.js

I'm new with VueJs, I'm finding best way to get $store data in ~/plugins/axios in VueJS in order to use it for APIs. But some errors occur. Hope your helps
~/plugins/axios.js
import axios from 'axios'
import store from '~/store'
var api = axios.create({
baseURL: 'http://localhost:8000/api/v1/',
headers: {'Authorization': 'JWT ' + store.state.token}
})
export default api
Errors:
Issues: Can't tranmit store in to axios.create, so store is not defined
My ~/Store.JS:
const AuthenticationStore = () => {
return new Vuex.Store({
state: {
token: null
},
mutations: {
SET_TOKEN: function (state, token) {
state.token = token
instance.defaults.headers = { Authorization: 'Bearer ' + token }
}
},
actions: {
....
}
})
}
const createStore = () => {
return AuthenticationStore
}
export { AuthenticationStore }
export default createStore
Error:
Cannot read property 'token' of undefined in 'headers': {'Authorization': 'JWT ' + store.state.token}

You could do this in your mutation:
{
SET_TOKEN: function (state, token) {
state.token = token;
Vue.axios.defaults.headers.common['Authorization'] =
(token ? ('JWT ' + token) : '');
}
Every time you set a token in a mutation you update your default token, so you won't have to set it in each request you do. Could do this in an action as well.
That's assuming you have your axios available globally via this.axios. There's a VueAxios library just for that. Make sure you do this in your entry js file (main.js probably):
import axios from 'axios';
import VueAxios from 'vue-axios';
Vue.use(VueAxios, axios);
That way you'll never have to import your store or axios when you need to make a request. Your typical request would look like this:
this.axios.get('URL', {data}, {options});

import axios from 'axios'
import store from '../store'
var api = axios.create({
baseURL: 'http://localhost:8000/api/v1/',
headers: {'Authorization': 'JWT ' + store.state.token}
})
export default api
You need to import your store.
If you are using Nuxt.js the default store will be in classic mode. It will export a function that create a vuex store.
import Vuex from 'vuex'
import mutations from './mutations'
const createStore = () => {
return new Vuex.Store({
state: {
counter: 0
},
mutations
})
}
export default createStore
So you can fix the new error by switching to modules mode https://nuxtjs.org/guide/vuex-store#modules-mode.
Or edit your store/index.js to the following strucutre
import Vuex from 'vuex'
import mutations from './mutations'
cosnt store = new Vuex.Store({
state: {
counter: 0
},
mutations
})
const createStore = () => {
return store
}
export { store }
export default createStore
and change the import statement in ~plugins/axios.js to import { store } from '../store'

Related

[vuex]unknown action type: getPackagingList

i'm using vuex with namespace, i created à store for vuex, when i call the action i have error [vuex] unknown action type: getPackagingList , i checked typo of all things, but without result:
store(index.js):
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state';
import * as getters from './getters';
import * as mutations from './mutations';
import * as actions from './actions';
import packaging from './modules/item/packaging'
Vue.use(Vuex);
export default new Vuex.Store({
namespaced: true,
state,
getters,
actions,
mutations,
modules: {
packaging,
}
})
index.js(of packahing):
import state from './state';
import * as getters from './getters';
import * as mutations from './mutations';
import * as actions from './actions';
export default {
namespaced: true,
state,
getters,
actions,
mutations
};
actions.js:
import axios from 'axios'
import Vue from 'vue'
export const getPackagingList = ({ commit }) => {
axios.get("product/packaging/index", {
headers: {
"Content-Type": "application/json",
// withCredentials: true //sent with cookie
Authorization: "Bearer " + Vue.$cookies.get("jwt"),
},
})
.then(res => {
commit("SET_PACKAGING", res.data);
})
};
mutations.js
export const SET_PACKAGING = (state, packagingList) => {
state.packagingList= packagingList;
};
state.js
export default {
packagingList:[],
packagingId : null,
}
call action on mycomponent.vue:
mounted() {
this.getPackagingList();
}
methods: {
...mapActions(['getPackagingList']),
}
Try this
mounted() {
this.getPackagingList();
}
methods: {
...mapActions('packaging', ['getPackagingList']),
}

vue-axios: Cannot read property 'post' of undefined

I try to send login data using axios and I get this error:
[Vue warn]: Error in v-on handler: "TypeError: Cannot read property
'post' of undefined"
TypeError: Cannot read property 'post' of undefined
I used this.$http.post from documentation.
main.js
import Vue from "vue";
import App from "./App.vue";
import axios from "axios";
import VueAxios from "vue-axios";
import router from "./router/router";
import store from "./store/index";
import vuetify from "./plugins/vuetify";
Vue.config.productionTip = false;
Vue.use(VueAxios, axios);
new Vue({
router,
store,
vuetify,
render: h => h(App)
}).$mount("#app");
store/index.js
import Vue from "vue";
import Vuex from "vuex";
import account from "./account.module";
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
account
}
});
stroe/account/module.js
import jwt_decode from "jwt-decode";
import accountService from "../services/account.service";
const token = localStorage.getItem("token");
const user = token ? jwt_decode(token) : null;
const state = token
? { loggedIn: true, user }
: { loggedIn: false, user };
const getters = {
}
const actions = {
login({ commit }, user) {
return accountService.login(user).then(
data => {
if (data.status == "success") {
const user = jwt_decode(data.token);
commit("loginSuccess", user);
} else {
commit("loginFailure");
}
return data;
});
}
}
const mutations = {
loginSuccess(state, user) {
state.loggedIn = true;
state.user = user;
},
loginFailure(state) {
state.loggedIn = false;
state.user = null;
},
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
services/account.service.js
const apiUrl = "***";
export default {
login(user) {
return this.$http.post(apiUrl + "login", {
login: user.login,
password: user.password
}).then(response => {
if (response.data.status == "success") {
localStorage.setItem("token", response.data.token);
}
return response.data;
});
}
}
VueAxios only creates a wrapper around the passed in axios, so this.$http.post() is the same as axios.post().
Thus, you could use axios directly in your services file:
import axios from 'axios'; 👈
const apiUrl = "***";
export default {
login(user) {
👇
return axios.post(apiUrl + "login", {
login: user.login,
password: user.password
}).then(/*...*/);
}
}

Have to import axios in any *.vue file of vue/cli 4.0.5 app

In my #vue/cli 4.0.5 app in any *.vue file I have to import axios, if I need to use it on this page, like:
<script>
import {bus} from '../../../src/main'
import appMixin from '#/appMixin'
import axios from 'axios'
...
But I expected axios to be accessible in *.vue file of my app.
In src/main.js I have defined :
import router from './router'
import store from './store'
import axios from 'axios'
...
Vue.use(axios)
moment.tz.setDefault(settingsTimeZone)
export const bus = new Vue()
axios.defaults.crossDomain = true
Vue.config.productionTip = false
Vue.prototype.$http = axios
I have this question as priorly I worked in laravel 5 / vuejs 2.6 app I have axios was accessible in all *.vue files of my app
without any definition...
Why so and if I have to write
import axios from 'axios'
in any file where I need axios ?
UPDATED BLOCK :
In my src/main.js I tried and failed as :
...
import axios from 'axios'
export const bus = new Vue()
axios.defaults.crossDomain = true
// axios.withCredentials = true
// window.axios.defaults.baseURL = window.App.baseurl;
Vue.config.productionTip = false
Vue.prototype.$http = axios
const token = localStorage.getItem('token')
if (token) {
Vue.prototype.$http.defaults.headers.common['Authorization'] = token
}
// home url in .env file
let apiUrl = process.env.VUE_APP_API_URL
alert( '++apiUrl::'+apiUrl ) // CHECK IT VALID URL
new Vue({
router,
store,
bus,
render: h => h(App)
}).$mount('#app')
Vue.use({
install (Vue) {
Vue.prototype.$api = axios.create({
baseURL: apiUrl // !!!
})
}
})
router.afterEach((to, from) => {
bus.$emit('page_changed', from, to)
})
But next in my component I commented line with axios import:
<script>
import {bus} from '../../main'
// import axios from 'axios'
import Vue from 'vue'
...
export default {
data: function () {
return {
...
}
}, // data: function () {
mounted() {
this.loadTasksData()
}, // mounted() {
methods: {
loadTasksData() {
let apiUrl = process.env.VUE_APP_API_URL
let config = {
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
}
}
axios({url: apiUrl + '/tasks_paged/' + this.current_page, data: {}, method: 'get', config: config})
.then(response => { // Error here!
I got error :
vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in mounted hook: "ReferenceError: axios is not defined"
...
What is wrong? Did I put your construction in valid place?
Also could you please give more explanations (or provide a link) about this construction? It is about my expiarence ...
Thanks!
Try this:
Vue.use({
install (Vue) {
Vue.prototype.$api = axios.create({
baseURL: 'PUT A BASE URL IF YOU WANT'
})
}
})

Use Vuex classic mode in Nuxt application

I'm rewriting Vue application to Nuxt architecture because we want SSR. However I don't want to rewrite Vuex store file which is:
import Vue from "vue";
import Vuex from "vuex";
import vuexI18n from "vuex-i18n/dist/vuex-i18n.umd.js";
import toEnglish from "../translations/toEnglish";
import toSpanish from "./../translations/toSpanish";
import toGerman from "./../translations/toGerman";
import toRussian from "./../translations/toRussian";
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
currentLanguage: ''
},
mutations: {
changeLang: (state, response) => {
if(response) {
state.currentLanguage = response;
Vue.i18n.set(response);
console.log(response);
}
}
}
});
Vue.use(vuexI18n.plugin, store);
Vue.i18n.add("en", toEnglish);
Vue.i18n.add("es", toSpanish);
Vue.i18n.add("de", toGerman);
Vue.i18n.add("ru", toRussian);
export default store;
I know that Nuxt has some other approach to that but I really want to stick with above code. Unfortuenally I can't call mutation from my component by:
this.$store.commit('changeLang', lang)
it print error in console:
[vuex] unknown mutation type: changeLang
I also tried like this
this.$store.commit('store/changeLang', lang)
but error is same. How to fix it? Do I need to rewrite this vuex file in order to make it work?
I followed #Aldarund tips and changed above code to:
import Vue from "vue";
import Vuex from "vuex";
import vuexI18n from "vuex-i18n/dist/vuex-i18n.umd.js";
import toEnglish from "../translations/toEnglish";
import toSpanish from "./../translations/toSpanish";
import toGerman from "./../translations/toGerman";
import toRussian from "./../translations/toRussian";
const store = () => {
return new Vuex.Store({
state: () => ({
currentLanguage: ''
}),
mutations: {
changeLang: (state, response) => {
if (response) {
state.currentLanguage = response;
Vue.i18n.set(response);
console.log(response);
}
}
}
})
};
Vue.use(vuexI18n.plugin, store);
Vue.i18n.add("en", toEnglish);
Vue.i18n.add("es", toSpanish);
Vue.i18n.add("de", toGerman);
Vue.i18n.add("ru", toRussian);
export default store;
now error is
Uncaught TypeError: store.registerModule is not a function
It's probably because of Vue.use(vuexI18n.plugin, store);.
You need to use classic mode.
Classic (deprecated): store/index.js returns a method to create a
store instance
So it should look like this, no vuex use, on import of Vue. And it must be a function that crestr store, not plain vuex object
import Vuex from 'vuex'
const createStore = () => {
return new Vuex.Store({
state: () => ({
counter: 0
}),
mutations: {
increment (state) {
state.counter++
}
}
})
}
export default createStore
Docs https://nuxtjs.org/guide/vuex-store/#classic-mode
As for plugin e.g. vyexi18 you need to move that code into plugin file and get created store object from context https://nuxtjs.org/guide/plugins/
export default ({ store }) => {
Your vuex18initcode
}

Set axios authorization header depends on store changes

I am new to Vue (I am a react person) and I am having this problem.
axios.js
import store from '../../store/index';
import axios from 'axios'
const API_URL = process.env.API_URL;
const token = store.getters.auth.token;
export default axios.create({
baseURL: API_URL,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
})
store/index.js
import auth from './modules/auth'
Vue.use(Vuex);
const debug = process.env.NODE_ENV !== 'production'
export default new Vuex.Store({
state: {},
getters : {},
mutations: {},
actions:{},
modules: {
auth
},
strict: debug,
})
modules/auth
import { AUTH_SUCCESS, AUTH_GUEST } from '../actions/auth'
import axios from '../../util/axios/axios'
import Vue from "vue";
const state = {
token: localStorage.token || '',
};
const getters = {
token: state => state.token
};
const actions = {
[AUTH_GUEST]: async ({commit}) => {
await axios.post('auth/register',)
.then(response => {
commit(AUTH_SUCCESS, response);
})
.catch(error => {
console.log(error);
});
},
};
const mutations = {
[AUTH_SUCCESS]: (state, resp) => {
state.token = resp.data.token;
},
}
export default {
state,
getters,
actions,
mutations,
}
when trying to get the store from store/index it returns undefined.
probably the axios has been called before the store has been initialized.
but how can I deal with it?
the flow of the app is.
user register->get token->update store with this token->add to the axios header.
so for now on, all calls to the api will have the token provided.
First of all, you should be careful with Vue's reactivity caveats which affect Vuex aswell. In your case, you're adding a new property inside an object in a mutation.
Back to the main issue, your axios.js file is being executed before the Store instance is built, that's why you cannot access to it and you get undefined.
What I'd do is:
axios.js
import axios from 'axios';
const API_URL = process.env.API_URL;
export default (store) => axios.create({
baseURL: API_URL,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${store.getters.auth.token}`
}
});
and then in your main file, where you have the main Vue instantiation I'd just run the function there, exporting the return of that function.