I want to make an axios instance available globally in my Vue 3 app.
Setup:
import { createApp } from 'vue'
import axios from 'axios'
const axiosInstance = axios.create({
withCredentials: true,
})
const app = createApp()
app.config.globalProperties.$axios = axiosInstance
app.mount(el)
Usage:
let response = await this.$axios.get('/api/leads')
I get this error:
TypeError: this.$axios.get is not a function
Seems like this.$axios is undefined. I cannot figure out why.
Notes:
I'm using the #vue/compat build of Vue to migrate from Vue 2 to Vue 3. I'm following the official migration guide.
When inspecting this.$axios - I get ƒ wrap() ......
The problem is caused by a known bug, where function properties (the result of axios.create() is actually a function) are bound to the component instance proxy, which inadvertently hides the function's own attached properties (i.e., $axios.get in this case). The PR that fixes the issue has not yet been merged.
A workaround is to convert the axiosInstance (a function) into an object with the spread operator:
const axiosInstance = axios.create({
withCredentials: true,
})
const app = createApp()
👇
app.config.globalProperties.$axios = { ...axiosInstance }
demo
Related
I used the beforeRouteEnter hook in vue-router to load data from two different endpoints using axios. I used promise.all() to load the data and then passed it to the component using next(). It seems to be working in development but when it is hosted on vercel the data isn't rendered on the component.
import axios from "axios"
import NProgress from "nprogress"
export default {
name: "DetailView",
beforeRouteEnter(to, from, next) {
NProgress.start()
const getDetails = axios.get(`api/grades/${ to.params.id }/`)
const getResults =
axios.get(`api/results/`, {
params: {
'grade-id': to.params.id,
}
})
Promise.all([getDetails, getResults])
.then(([details, results]) => {
next((vm) => {
vm.details = details.data
vm.results = results.data
})
})
.finally(NProgress.done())
},
}
I used a <script setup>...</script> for the setup function with the
import { ref } from "vue"
const details = ref({})
const grades = ref({})
I'm relatively new to javascript too and still trying to understand promises and async/await very well. Thank you
Finally found a solution to the problem. Components using <script setup> in vue are closed by default, he public instance of the component, which is retrieved via template refs or $parent chains, will not expose any of the bindings declared inside <script setup>. From the vue docs.
I had to explicitly expose the properties used in the beforeRouteEnter navigation guard using the defineExpose compiler macro
defineExpose(
{
details,
results
}
)
I have tried all solutions here and am getting the same error. I must be doing something wrong.
I want to use Axios globally and not have to import it in every component I need to use it. So I created its Instance, attached it to the Vue app and am still getting
Error in mounted hook: "TypeError: Cannot read property 'get' of undefined"
found in
---> <Home> at src/views/app/Home.vue
<AppLayout> at src/layouts/AppLayout.vue
<Index> at src/views/app/index.vue
<App> at src/App.vue
<Root>
Here is the instance that i'm creating called axios-instance.js
import axios from 'axios'
import Vue from "vue";
import {apiUrl} from "./constants/config";
const devInstance = createInstance(apiUrl);
// const productionInstance = createInstance("http://localhost:3000"); // will change later
function createInstance(baseURL){
return axios.create({
baseURL,
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer 9|b4DWuYCXyEK1H07KB1iiGXyRk2auEl5m1okDVe4B' //`Bearer ${localStorage.token}`
}
});
}
export default {
install () {
Vue.prototype.$http = devInstance
}
};
Then inside the main.js file, I am importing the instance and attaching it to Vue using Vue.use, see below.
import Vue from 'vue';
import http from './axios-instance';
//...
//setup axios
Vue.use(http)
//...
After that, I am trying to use it in an action but it's failing with the error message I showed you up there. Here is how am using it in action
//...
getDashboard({commit}) {
//get home info
this.$http.get('sacco/home')
.then(({status, data}) => {
console.log(status, data)
// commit('updateDashBoard', payload);
})
.catch((error) => {
console.log(error)
});
}
//...
I have a project where I use Vue 3 and Vuex. This is my first time using Vue 3. I can't seem to get how to access Vuex inside the Setup method of a Vue 3 project.
I have a feature object. That is being set by a Childcomponent using the featureSelected method. Firstly in my setup I create a store constant with useStore; from import { useStore } from "vuex";. Then inside the featureSelected function I call the dispatch function on this store object store.dispatch("setPlot", { geometry: newFeature });.
I keep on getting an error telling me that the dispatch function does not exist on the store object: Uncaught TypeError: store.dispatch is not a function.
setup() {
const store = useStore;
const feature = ref();
const featureSelected = (newFeature) => {
feature.value = newFeature;
store.dispatch("setPlot", { geometry: newFeature });
};
return { feature, featureSelected };
},
useStore is a composable function which should be called using () like :
const store = useStore();
The Error Image
when i send request via axios with url axios concatenate url of api
with the url of the quasar dev server how can i neglect this
concatenation and send the API url only there is any configuration for
baseUrl of axios with quasar ?
src/boot
import axios from 'axios'
export default async ({ Vue }) => {
axios.defaults.baseURL = 'http//:localhost:3000/'
Vue.prototype.$axios = axios
}
the componennt :
this.$axios({
url : 'backend/spots/all',
}).then(response=>{
this.allSlots = response.data
})
According Quasar documentation you can try it as below:
// src/boot/axios.js
const axiosInstance = axios.create({
baseURL: 'http//:localhost:3000'
})
export default async ({ Vue }) => {
Vue.prototype.$axios = axiosInstance
...
}
export { axiosInstance }
to use in some vue | js file:
import { axiosInstance } from 'src/boot/axios'
axiosInstance.get('/some-endpoint')
I am not sure, but can you try to change axios.defaults.baseURL = 'http//:localhost:3000/' to axios.defaults.baseURL = 'http://localhost:3000/' (change colon place) ?
For anyone reading this.
According to quasar axios boot file documentation you can try a more cleaner way...
import Vue from 'vue'
import axios from 'axios'
// we add it to Vue prototype
// so we can reference it in Vue files as this.$axios
// without the need to import axios or use vue-axios
Vue.prototype.$axios = axios
// can also create an axios instance specifically for the backend API
const api = axios.create({ baseURL: 'https://api.example.com' })
Vue.prototype.$api = api
export { axios, api }
I was having the same issue, in quasar.config.js under build I had
env: ctx.dev ? { // so on dev we'll have
API: JSON.stringify('https://my.staging.api/v1/')
} : { // and on build (production):
API: JSON.stringify('https://my.api/v1/')
},
removing JSON.stringify solved the issue
env: ctx.dev ? { // so on dev we'll have
API: 'https://my.staging.api/v1/'
} : { // and on build (production):
API: 'https://my.api/v1/'
},
I'm searching the way to call a mutation on a store from another file which is not a single file component.
This file is responsible to manage the axios configuration to be able to make some API calls. I managed some interceptors and i would like to call a mutation to change state of the notification store to display a notification in UI.
import axios from "axios";
import i18n from './i18n';
import Vue from 'vue';
// Define global param object for notification options
const options = {
type: "danger"
};
// Create global Axios instance for CTC Backends API calls
const instance = axios.create({
baseURL: process.env.VUE_APP_BACKEND_URL,
});
// Define interceptor for responses to handle certain API responses
instance.interceptors.response.use(res => {
console.log('axiosBackend::ResponseInterceptor()', res);
return res;
}, error => {
if (!error.response) {
Vue.$store.commit("SHOW_NOTIFICATION", {
text: i18n.t("serverError"),
type: 'error'
});
}
return Promise.reject(error.response);
});
export default instance;
If I understand your problem properly. You have to import the store instance and use it to call the mutation.
import store from '#/store'
...
store.commit("SHOW_NOTIFICATION", {
...
import {store} from './store';
store.commit("SHOW_NOTIFICATION", paylo )