Home > Software design >  Use class inside Vue 3 component globally imported through provide function
Use class inside Vue 3 component globally imported through provide function

Time:06-21

I'm building an application on Vue 3 where I've build an api class for my api calls:

import axios from 'axios'

export default class {

    /**
     * Send GET Request
     * @param  {string} url
     * @return {Promise}
     */
    get(url) {
        return new Promise((resolve, reject) => {
            axios.get(url, {}).then(response => {
                if (response.status === 200) {
                    return resolve(response);
                }
            }).catch((error) => {
                return reject(error);
            })
        });
    }

    /**
     * Send POST Request
     * @param  {string} url
     * @param  {object} payload Data object to send
     * @return {Promise}
     */
    post(url, payload) {
        return new Promise((resolve, reject) => {
            axios.post(url, payload, {}).then(response => {
                if (response.status === 200) {
                    return resolve(response);
                }
            }).catch((error) => {
                return reject(error);
            })
        });
    }

    /**
     * Send FIND Request
     * @param  {string} url
     * @return {Promise}
     */
    find(url) {
        return new Promise((resolve, reject) => {
            axios.get(url, {}).then(response => {
                if (response.status === 200) {
                    return resolve(response);
                }
            }).catch((error) => {
                return reject(error);
            })
        });
    }

}

I want to utilize this class functions inside my Vue components, for this I imported the _api.js file and inserted .provide('$api', apis) into createApp function in app.js file:

import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/inertia-vue3';
import api from './Models/_api'

const apis = new api();

createInertiaApp({
    resolve: (name) => require(`./Pages/${name}.vue`),
    setup({ el, app, props, plugin }) {
        return createApp({ render: () => h(app, props) })
            .use(plugin)
            .mixin({ methods: { route } })
            .provide('$api', apis)
            .mount(el);
    },
});

And in my component I'm using as:

<template>
   //HTML Files
</template>
export default {
    data(){
        return{
            tableData:[],
        }
    },
    methods:{
        fetchData(){

            this.$api.post('/api/user-data', {}).then(response=>{
                if(response.status === 200)
                {
                    this.tableData = response.data.data
                }
            });
        }
    },
    created(){
        this.fetchData();
    },
}
</script>

while using this.$api I'm getting error:

TypeError: Cannot read properties of undefined (reading 'post')

Screenshot:

error screenshot

when I tried console.log(this.$api) it returned undefined

Below solution working in Vue 2

In Vue 2 it was working perfectly fine:

I only have to initiate the class in app.js and add it to prototype and it works good.

Vue 2 Code app.js:

import { App, plugin } from '@inertiajs/inertia-vue'
import Vue from 'vue'
import api from './Models/_api'

const apis = new api();
Vue.prototype.$api = apis;

const el = document.getElementById('app')

new Vue({
    store: store,
    render: h => h(App, {
        props: {
            initialPage: JSON.parse(el.dataset.page),
            resolveComponent: name => import(`NitsPages/${name}`).then(module => module.default),
        },
    }),
}).$mount(el)

CodePudding user response:

This is be related to Vue3 reserving _ and $ prefixes.

Properties that start with _ or $ will not be proxied on the component instance because they may conflict with Vue's internal properties and API methods. You will have to access them as this.$data._property.

So try the following:

this.$data.$api.post(...)

Personally, I think using those two common conventions and reserving them for internal use was not ideal. But it is what it is. You can read more about it here. https://github.com/vuejs/vue/issues/5879

CodePudding user response:

You can add your API Class as a global Property to your Vue 3 Instance.

This is stated in the Vue 3 Application Documentation.

e.g.:

main.js

import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/inertia-vue3';
import api from './Models/_api'

const apis = new api();

createInertiaApp({
    resolve: (name) => require(`./Pages/${name}.vue`),
    setup({ el, app, props, plugin }) {
        const app = createApp({ render: () => h(app, props) });
        app.config.globalPoperties.api = apis;
        return 
            .use(plugin)
            .mixin({ methods: { route } })
            .provide('$api', apis)
            .mount(el);
    },
});

Which will then be callable anywhere inside your Vue Components with this.API

  • Related