Vuejs : use imported plugin mixin localy - javascript

Is it possible to use a mixin imported from a VueJS plugin in one component?
I've created a plugin and when I import it I can access the mixin's functions from all my components.
Is there a way to make it available in only one component ? or all the plugin add global-level functionality to Vue by definition?

IMHO you should use create 2 things:
the plugin that imports the essentials globally
the mixin that needs to be imported in the components you want
example:
//main.js
import {MyPlugin} from 'my-library'
vue.use(MyPlugin)
in the component
//component.vue
import {MyMixin} from 'my-library'
export default {
mixins: [myMixin],
}

You can register a mixin either globally, either locally. If you don't register a mixin globally, it will be only available in components where it is locally registered. So, with local registration, you can make a mixin available in only specific components.
Registering globally: you just need to declare it in the main.js file
Nb: you don't need to register the mixin in components
Vue 2:
// main.js
import myMixin from './mixins/myMixin'
Vue.mixin(myMixin) // makes the plugin globally available
new Vue({
// ...
}).$mount('#app')
Vue 3:
// main.js
import myMixin from './mixins/myMixin'
const app = createApp(App)
app.mixin(myMixin) // makes the plugin globally available
app.mount('#app')
Registering locally: you do NOT declare it in the main.js file, and you register the mixin in the relevant components
// componentWithMixin.vue
import myMixins from "../mixins/myMixin"
export default {
// ...
mixins: [myMixins] // importing the mixin - without this line, the mixin can't be available
}

Related

Vue - make helper for root component and all child component

Please is there a way to create a helper function on a root component in vue and also make the function accessible in all child components?
You can create helper functions and use it as a plugin. In case of you are using nuxt.js, you can create helpers.js in plugins and register it in nuxt.config.js file.
import Vue from 'vue'
import helpers from './helpers'
const plugin = {
install () {
Vue.prototype.$helpers = helpers
}
}
Vue.use(plugin)
In helpers.js, you can define all helper functions.
export default {
cloneObj(val) {
return JSON.parse(JSON.stringify(val));
}
};
Then you can use it in any child components like this:
this.$helpers.cloneObj()
You need to store it in a separate file because it's frustrating to pass it as a prop from one component to another and that's the main idea of why state management like Vuex is a better solution because it provides a centralized state manage which you can access from any component

Add global variable in Vue.js 3

Anybody know how to do add a global variable in Vue 3 ?
in Vue 2 we use this in the main.js file:
Vue.prototype.$myGlobalVariable = globalVariable
The most direct replacement is app.config.globalProperties. See:
https://vuejs.org/api/application.html#app-config-globalproperties
So:
Vue.prototype.$myGlobalVariable = globalVariable
becomes:
const app = createApp(RootComponent)
app.config.globalProperties.$myGlobalVariable = globalVariable
This is scoped to a particular application rather than being global as it was with Vue.prototype. This is by design, all 'global' configuration options are now scoped to an application.
The relevant RFC is here:
https://github.com/vuejs/rfcs/blob/master/active-rfcs/0009-global-api-change.md
Properties added to globalProperties will be available via the component instance for all components within the application. So if you're using the Options API you'll be able to access them using this.$myGlobalVariable, just like you could with Vue.prototype. They'll also be available in the template without the this., e.g. {{ $myGlobalVariable }}.
If you're using the Composition API then you'll still be able to use these properties within the template, but you won't have access to the component instance within setup, so these properties won't be accessible there.
While hacks involving getCurrentInstance() can be used to access globalProperties within setup, those hacks involve using undocumented APIs and are not the recommended approach.
Instead, application-level provide/inject (also discussed in that RFC) can be used as an alternative to Vue.prototype:
const app = createApp(RootComponent)
app.provide('myGlobalVariable', globalVariable)
In the descendant component this can then be accessed using inject. e.g. With <script setup>:
<script setup>
import { inject } from 'vue'
const myGlobalVariable = inject('myGlobalVariable')
</script>
Or with an explicit setup function:
import { inject } from 'vue'
export default {
setup() {
const myGlobalVariable = inject('myGlobalVariable')
// Expose it to the template, if required
return {
myGlobalVariable
}
}
}
Or with the Options API:
export default {
inject: ['myGlobalVariable']
}
Docs: https://vuejs.org/api/application.html#app-provide
The idea here is that the component can explicitly declare the property rather than inheriting it by magic. That avoids problems like name collisions, so there's no need to use a $ prefix. It can also help to make it clearer where exactly a property is coming from.
It is common for the inject function to be wrapped in a composable. For example, the useRoute composable exposed by Vue Router is just a wrapper around inject.
In addition to globalProperties and provide/inject, there are various other techniques that might be used to solve the same problems as Vue.prototype. For example, ES modules, stores, or even global mixins. These aren't necessarily direct answers to the specific question posted here, but I've gone into more detail describing the various approaches at:
https://skirtles-code.github.io/vue-examples/patterns/global-properties.html
Which approach you prefer will depend on your circumstances.
How to add a global variable using Vue 3 and vue-cli (or Vite)
Note: You can drop the dollar sign from your $globalVariable and just use globalVariable, just like in the documentation.
Initially your main.js file looks something like this (adding router for common use case):
import { createApp } from 'vue'
import { App } from './App.vue'
import { router } from './router'
createApp(App).use(router).mount('#app')
To use add the global variable using Vue 3 and the vue-cli or Vite:
import { createApp } from 'vue'
import { App } from './App.vue'
import { router } from './router'
// 1. Assign app to a variable
let app = createApp(App)
// 2. Assign the global variable before mounting
app.config.globalProperties.globalVar = 'globalVar'
// 3. Use router and mount app
app.use(router).mount('#app')
Then to access the variables in components like this:
<script>
export default {
data() {
return {
myVar: this.globalVar
}
}
}
</script>
like in the template like this:
<template>
<h1>{{ globalVar }}</h1>
</template>
And that's it. Happy coding!
About Global Variables and Composition API
According to the very bottom of samayo's answer on this post, global variables are only available on the Options API.
Quoting the bottom of his answer:
Note: This is only for the Options API. Evan You (Vue creator) says: "config.globalProperties are meant as an escape hatch for replicating the behavior of Vue.prototype. In setup functions, simply import what you need or explicitly use provide/inject to expose properties to app.
I recommend to use provide/inject approach as follows :
in main.js :
import {createApp} from 'vue'
let app=createApp({
provide:{
globalVariable:123
}
}).$mount('#app')
in some child or grand-child component do :
export default{
name:'some-compo',
inject:['globalVariable'],
//then access this.globalVariable as property in you component
...
}
for composition api and script setup :
import { inject } from 'vue'
let globalVar=inject('globalVariable')
If possible you should use imports or provide/inject. Another way to define global variables/functions and use them would be using globalProperties (although this seems to be considered more of an anti-pattern). But if a library you use uses globalProperties then you can use it like this. This also works with global functions.
const app = Vue.createApp({})
app.config.globalProperties.$http = () => {} // global function
app.config.globalProperties.$globalVariable = 'Jimmy' // global variable
1. Using options API
mounted() {
console.log(this.$globalVariable)
}
2. Using setup method
<script setup>
import { getCurrentInstance } from 'vue'
const app = getCurrentInstance()
const progressBar = app.appContext.config.globalProperties.$globalVariable
console.log(this.$globalVariable)
</script>
For those of you who are confused about how to access globalProperties in the setup() method, you can use getCurrentInstance() as in the following documentation.
https://v3.vuejs.org/api/composition-api.html#getcurrentinstance
In my case I had to create a global var and get the data from a script.
Used provide and inject:
In main.js:
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App);
app.provide('message',document.querySelector('script[name="nameSCRIPT"]').innerHTML.split('=').slice(1).join('=').slice(1,-1));
app.mount('#app')
In index.html:
<script name="nameSCRIPT">nameSCRIPT="HELLO"</script>
In child component:
inject:['message'],
mounted(){
console.log(this.message)
},

Nuxtjs plugin registration

I am curious as to the methodology Nuxt.js uses to register a plugin. I have been reading the documentation for Nuxt.js and I am slightly confused as to the registration methodology.
I do not want to register plugins such as vue-flag-icon globally.
My understanding is when we register the plugin we use the plugin folder as such:
import Vue from 'vue'
import FlagIcon from 'vue-flag-icon'
Vue.use(FlagIcon)
I can now use the flag component anywhere in my app - I dont want this!!!
I want to be able to load plugins into the components that need them ONLY.
I have tried loading them as a component like:
components:{
'flag': ()=> import('path to plugin') // #/plugins/vue-flag-icon
}
This does not work.
I changed my plugins script to:
import Vue from 'vue'
import FlagIcon from 'vue-flag-icon'
export default () => {
Vue.use(FlagIcon)
}
And then tried to register the plugin within the components like so:
import flag from '#/plugins/vue-flag-icon';
created(){
flag()
}
My questions really are:
How can I register a plugin within the component without importing the vue instance? (I think is called a bus)
Is it bad practice to import the plugins directly into components?
Is registering all the plugins within nuxt.config.js creating a larger download file for users to download (example: registering vue-twix is not necessary on pages that do not have textareas) or will nuxt/webpack handle the removal of unnecessary plugins on a page by page or component by component basis (so I don't have to even worry about this)?. If this is the case than I dig nuxt.
Thanks
If you want to use FlagIcon only on certain components, you have to import it and use it on every component you want to use.
<template>
<flag iso="ca" />
</template>
<script>
import FlagIcon from 'vue-flag-icon'
export default () => {
components: {
FlagIcon
}
</script>
This should work.
For other components, remember to import any style sheets the component might require:
<style lang="scss" scoped>
#import 'path/to/plugin/style.css';
</style>

How to use VeeValidate or any third party package locally inside vue component

Ok here is the situation, I am working on a SPA with Vue.js. I am using VeeValidate in one of my component say in Component1.vue like this,
import Vue from 'vue';
import VeeValidate from 'vee-validate';
Vue.use(VeeValidate);
export default {
//...
}
In another component say in Component2.vue I am using vuetable-2 which I registered like this,
import Vuetable from 'vuetable-2/src/components/Vuetable';
export default {
components: {
Vuetable
},
//...
}
The problem is that both VeeValidate and Vuetable internally depends on a computed property with same name. And as I am registering VeeValidate globally like Vue.use(VeeValidate);, if I navigate from Component1 to Component2, Vuetable gives an error saying,
The computed property "fields" is already defined as a prop
because VeeValidate already registered itself globally when I landed on Component1.
If I navigate to Component2 from any other component which does not have any dependency with VeeValidate then it works just fine.
So here is my question,
How do I register VeeValidate or any other package inside Component1.vue locally so that it does not influence other components? much like registering other components inside components: {} object.
Vee validate allows you to change the field and error bag names through the configuration. It's in the docs here.
const config = {
errorBagName: 'errors', // change if property conflicts
fieldsBagName: 'fields',
}
Also maybe if interest, the advanced configuration section explains how to inject instances into components instead of globally.

Using mixins with Vuejs

I'm currently learning how to develop an app with Vuejs. I have a main.js file with the code for setting up Vue.js. I created a new directory /mixins with a new file api.js. I want to use that as mixin so that every component can use a function to access my api. But I don't know how to do it.
This is my /mixins/api.js file:
export default{
callapi() {
alert('code to call an api');
},
};
This is my main.js file:
import Vue from 'vue';
import VueRouter from 'vue-router';
import VueResource from 'vue-resource';
import { configRouter } from './routeconfig';
import CallAPI from './mixins/api.js';
// Register to vue
Vue.use(VueResource);
Vue.use(VueRouter);
// Create Router
const router = new VueRouter({
history: true,
saveScrollPosition: true,
});
// Configure router
configRouter(router);
// Go!
const App = Vue.extend(
require('./components/app.vue')
);
router.start(App, '#app');
How can I include my mixin the right way now, so that every component has access to the callapi() function?
If you want to use a mixin on a specific component, rather than all components, you can do it like this:
mixin.js
export default {
methods: {
myMethod() { .. }
}
}
component.vue
import mixin from 'mixin';
export default {
mixins: [ mixin ]
}
Another thing you might consider is using a component extension design pattern i.e. creating a base component and then inheriting from that in sub components. It's a little more involved but keeps code DRY if you have many components sharing many options and perhaps inheriting the template too.
I've written about it on my blog if you're interested.
You can apply mixin globally using Vue.mixin
api.js
------
export default {
methods: {
callapi() {};
}
}
main.js
-------
import CallAPI from './mixins/api.js';
Vue.mixin(CallAPI)
As the documentation states you should use it carefully:
Use global mixins sparsely and carefully, because it affects every single Vue instance created, including third party components.

Categories

Resources