Vue 3's Provide / Inject using the Options API - javascript

I've been trying to follow the documentation for the API on the Vue 3 website which says to use app.provide('keyName',variable) inside your main.js file like so:
import App from './App.vue'
import { createApp } from 'vue'
import axios from 'axios'
const app = createApp(App)
app.provide('axios', axios)
app.use('Vue')
app.mount('#app')
Then inject and use it in your child component like so:
export default {
inject: ['axios'],
...
createUser (data) {
return this.axios.post('/users', data)
}
}
However doing so just gives me this error in my console:
Uncaught TypeError: Cannot read properties of undefined (reading 'post')
Is there anything I'm missing? I didn't see any about an import unless you're using the Composition API. Can provide / inject be called from within a .js file? I would expect so as long as its within a export default {} statement
Ive tried following the API to a "T" but it simply refuses to work for me. Also tried searching the web for solutions but everything I've found says what I'm doing should be working just fine.

It works, see the playground.
But is not absolutely necessary, since with the browser library version axios is globally defined and could be accessed also without inject
You could also save yourself some time with the vue-axios plugin.
Example
const { createApp } = Vue;
const myComponent = {
inject: ['axios'],
created() {
this.axios.get('/')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
},
template: '<div>My Component</div>'
}
const App = {
components: {
myComponent
}
}
const app = createApp(App)
app.provide('axios', axios)
app.mount('#app')
<div id="app">
<my-component></my-component>
</div>
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
<script src="https://unpkg.com/axios#1.3.1/dist/axios.min.js"></script>

Related

How to use vue-toastification

I just migrated my project created in vue 3 to nuxt 3. Previously I used the vue-toastification module but now I don't know how to import it correctly. My code using this module.
import { useToast, POSITION } from 'vue-toastification'
const toast = useToast()
export default {
methods: {
copy(text) {
toast.success('Copied!', {
timeout: 2000,
position: POSITION.BOTTOM_CENTER,
})
navigator.clipboard.writeText(text)
}
}
}
In Vue I had to do app.use(Toast) but Nuxt does not have an index.js file. Adding modules: ['vue-toastification/nuxt'] in nuxt.config.js does not work because I get an error.
Answers suggested by kissu and Ricardo de Paula worked for me while I was using development server (npm run dev).
After building and running the project I encountered error 500:
Named export 'useToast' not found. The requested module 'vue-toastification' is a CommonJS module, which may not support all module.exports as named exports. CommonJS modules can always be imported via the default export, for example using: import pkg from 'vue-toastification';
To fix this, I registered toast as plugin helper (I'm using Nuxt 3.1.1 with Nitro 2.1.1):
Inside vue-toastificaton.client.js:
import { defineNuxtPlugin } from '#app'
import * as vt from 'vue-toastification'
import '#/assets/css/toast.scss'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(vt.default)
return {
provide: {
toast: vt.useToast()
}
}
})
Then in my component script setup:
//throws an error after production build
//import { useToast } from 'vue-toastification'
//const toast = useToast()
//toast.success('Yay!!!')
//works after production build
const { $toast } = useNuxtApp()
$toast.success('Yay!!!')
If you want it to be available globally, you can install it as a Nuxt plugin as explained in the official docs or in this other answer.
vue-toastification is probably a client-side only plugin, hence you would probably want to use it as
/plugins/vue-toastificaton.client.js like this
import { defineNuxtPlugin } from '#app'
import Toast from "vue-toastification"
import "vue-toastification/dist/index.css" // if needed
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.use(Toast)
})
Then, you should be able to use it in your components with either Composition API or Options API (I think).
I was wanting to do the same thing. I read kissu's answer and did the following:
1 - I created a folder for the puglin - plugins
2 - Inside the plugins folder I created a file called vue-toastificaton.client.js
Inside vue-toastificaton.client.js:
import { defineNuxtPlugin } from '#app'
import Toast from 'vue-toastification'
import 'vue-toastification/dist/index.css' // if needed
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(Toast)
})
And I used it that way:
<script setup>
import { useToast } from 'vue-toastification'
const toast = useToast()
const onSubmit = () => {
// use the toast notification plugin to show a success message
toast.success('Hello world!')
}
</script>

How to use Oruga components (and progamatic components) in Vue 3 with the Options API?

I am finally starting to play around with Vue 3 and am migrating an app from Vue 2 + Buefy to Vue 3 + Oruga.
In the Oruga docs it looks like every example for importing a component or programatic component uses the composition API.
The Notification component for example imports the programatic component into the app/components/view's setup function which is using the composition API
import { defineComponent } from 'vue'
import { useProgrammatic } from '#oruga-ui/oruga-next'
import NotificationForm from './_notification-form.vue'
export default defineComponent({
setup() {
const { oruga } = useProgrammatic()
function toast() {
oruga.notification.open({
message: 'Something happened correctly!',
rootClass: 'toast-notification',
position: 'top'
})
}
The other examples show the Vue app importing either all of Oruga, or each component at a root level:
import { createApp } from 'vue'
import Oruga from '#oruga-ui/oruga-next'
import '#oruga-ui/oruga-next/dist/oruga.css'
createApp(...).use(Oruga);
------------------
import { createApp } from 'vue'
import { OAutocomplete, OSidebar } from '#oruga-ui/oruga-next'
import '#oruga-ui/oruga-next/dist/oruga.css'
createApp(...)
.component(OAutocomplete)
.component(OSidebar)
I however, would like to import components into my components/views which are using the options API (which I prefer), how would I do that?
I tried to import things as I would in in Vue2, but I get warnings like: 'Failed to resolve component: o-button'
import { OButton } from '#oruga-ui/oruga-next';
export default {
components: {
OButton
}
}
Or in the case of the programmatic notification I get 'Uncaught TypeError: Cannot read properties of undefined (reading 'open')':
import { useProgrammatic } from '#oruga-ui/oruga-next';
const { oruga } = useProgrammatic()
export default {
methods: {
onAlert() {
oruga.notification.open({
message: 'Something happened correctly!',
rootClass: 'toast-notification',
position: 'top'
})
},
},
}
Vue composables should be called inside the setup function or setup script only, so calling useProgrammatic under the script tag is wrong, what you should do instead is something like this:
import { useProgrammatic } from '#oruga-ui/oruga-next';
export default {
setup() {
const { oruga } = useProgrammatic()
return {
oruga
}
},
methods: {
onAlert() {
this.oruga.notification.open({
message: 'Something happened correctly!',
rootClass: 'toast-notification',
position: 'top'
})
},
},
}
and about calling the components, I tested what you did and it works fine, I think you need to re-install the package because maybe something went wrong
Please check this sample for more details: stackblitz

Access to main Vue instance in App.vue script

In Vue2, I'm trying to set up an axios interceptor in my App.vue file to trap any responses that come back 401 from my API so I can redirect the user to the Vue route /sign-in. My code works, but I rely on storing the Vue instance created in main.js in window.appvue.
In main.js:
window.appvue = new Vue({
router,
render: (h) => h(App),
}).$mount("#app");
In App.vue:
<script>
import...
export default { ... }
export const $axios = axios.create();
$axios.interceptors.response.use(
(response) => {
return response;
},
(error) => {
if (error.response.status === 401) {
window.appvue.$router.push("/sign-in");
} else {
return Promise.reject(error);
}
}
);
<script>
I have tried importing $axios from App.vue in main.js and moving the $axios.interceptors.response.use(...) code to that file, but then the interceptor never runs when I have a page where an $axios.get() returns 401.
Is there a way to accomplish this without storing the main Vue instance in window as a global? Or should I just go with what's working and call it a day?
P.S.
I was not aware of the existence of $root, when I asked this question, and I have not tried a version where the code in App.vue uses $root instead of relying on the window.appvue global, but when it comes to accessing the main/root instance of Vue from main.js, $root is definitely preferable to a global.
I managed to avoid using the global by isolating the axios wrapper into its own module/file. Then my .vue files that need axios can import from that instead of from axios directly
In {root}/src/axios.js:
import axios from "axios";
import router from "#/router";
const $axios = axios.create();
$axios.interceptors.response.use(
[stuff that uses router]
);
export default $axios;
Then in my files that need to call to the API:
import $axios from "#/axios.js";
and use $axios instead of axios to make the API call.
inside your main.js try something like this
import router from './router'
import axios from 'axios'
Vue.prototype.axios.interceptors.reponse.use(
res => {
// res stuff here
},
err => {
// error stuff here
if (err.response.status === 401) {
router.push("/sign-in");
} else {
return Promise.reject(err);
}
}
)

Unable to initialise LiveLike chat in Vue 3, Failed to resolve component

I'm running into the following error when trying to initialise the LiveLike Chat.
[Vue warn]: Failed to resolve component: livelike-chat
Stripped back view:
<template>
<livelike-chat></livelike-chat>
</template>
<script>
import LiveLike from "#livelike/engagementsdk";
import { onMounted } from "vue";
export default {
setup() {
onMounted(() => {
let clientId = 'somelongclientidsuppliedbylivelike';
LiveLike.init({ clientId });
});
}
};
</script>
The livelike chat is supposed to initialise to a custom element, <livelike-chat>, the trouble is Vue sees that and tries to find the component livelike-chat. How do I "tell" Vue to ignore that element, its not a component but a tag reserved for LiveLike?
You could use an isCustomElement config for this:
// main.js
const app = createApp({})
app.config.isCustomElement = tag => tag === 'livelike-chat'

How to correctly globally register and use Vue Rangedate Picker component?

I am trying to use VueRangedatePicker and I can't seem to figure out how to use this on the template of some other vue component. I am using Webpack.
I have registered the component/plugin on my main.js file like this:
import Vue from 'vue'
import App from './App'
import router from './router'
import { store } from './store/store'
import firebase from './firebase-config'
import vuefire from 'vuefire'
//////////////// HERE
import VueRangedatePicker from 'vue-rangedate-picker' // importing the plugin here
Vue.use(VueRangedatePicker) // using it
Vue.component('VueRangedatePicker', { }) // creating the component globally (if I don't add this line the app complains the component is not registered
////////////////
Vue.config.productionTip = false
let app;
Vue.use(vuefire)
firebase.auth().onAuthStateChanged(function(user){
if (!app) {
/* eslint-disable no-new */
app = new Vue({
el: '#app',
template: '<App/>',
components: { App, VueRangedatePicker },
router,
store,
VueRangedatePicker
})
}
})
Then on my component component_A.vue I am again importing the VueRangedatePicker plugin in the following manner:
<template>
<div>
<vue-rangedate-picker #selected="onDateSelected" i18n="EN" />
</div>
</template>
<script>
import firebase,{ itemRef } from '../firebase-config';
import VueRangedatePicker from 'vue-rangedate-picker'
export default {
firebase() {
return {
items: itemsRef,
}
},
name: 'component_A',
data () {
return {
}
},
created() {
console.log(VueRangedatePicker);
},
methods: {
onDateSelected: function (daterange) {
this.selectedDate = daterange
},
}
</script>
I know the plugin/component is registered because when I log the Vue Rangedate Picker on the console I can see the object
However I am getting the an error message like this
I have read the complete readme.md file on the project's github but I am still puzzled. What is Vue_Daterange_picker? Is it a plugin? Is it a component? Is it a plugin that allows me to build a component? I am quite confused. Can you clarify this for me a little better? How can I make this work?
This is because you have registered the component with an empty name.
In main.js :
Vue.component('DatePicker', VueRangedatePicker)
Then in your component use the component as :
<date-picker></date-picker>

Categories

Resources