Using mixins with Vuejs - javascript

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.

Related

Is there a way to encapsulate Vuex store inside Vue plugin (its install function)?

I have a plugin and this plugin uses Vuex
// plugin.js
import Vuex from "vuex";
import store from "./store.js";
export default {
install(Vue, options) {
const storeInstance = new Vuex.Store(store);
Vue.prototype.$store = storeInstance;
}
};
And in that plugin I import a store object.
// store.js
export default {
actions: {
SOME_RANDOM_ACTION({ state, commit }) {
console.log("some random action");
}
}
};
Dispatching actions and using state is fine and works as expected.
But when I add this plugin to another Vue instance that uses vuex, store object re-initializes with new state.
// index.js
import Vue from "vue";
import Vuex from "vuex";
import App from "./App.vue";
import plugin from "./plugin.js";
Vue.use(Vuex);
Vue.use(plugin);
new Vue({
// WARN when i uncomment this next line of code Vuex gets re-initialized with new object
// store: new Vuex.Store({ state: { hello: "hix" } }),
components: {
App
}
}).$mount("#app");
When you uncomment store initialization, store that was defined in the plugin is now not available.
Currently, I have these solutions in mind:
Export my plugin store object to index.js main app, and use this store as a module.
Use some other state management.
Is there a way to use Vuex inside my plugin?
https://codesandbox.io/s/vibrant-sanne-67yej?file=/src/main.js:0-371
Vuex plugin uses store option to assign store instance to Vue.prototype.$store, similarly to your own plugin.
If the intention is to use multiple stores, their names shouldn't collide. The key is to name your store object inside plugin something other than $store
Vue.prototype.$myPluginStore = storeInstance;
But this still doesn't encapsulate $myPluginStore inside the plugin, as it is accessible within the app.
// App.vue
computed: {
appState() {
return this.$store.state;
},
pluginState() {
return this.$myPluginStore.state; // this is now accessible within the main app
}
}
It would be a reasonable solution to allow a store to be used as a module of existing store instead of creating a new store, but only when used within one app and not when used as a plugin for a package.
The main problem is that default store instance ($store) can make use of Vuex helpers - mapGetters, etc.
You can take advantage of the install method exposed by the plugin to get access to the store - which should be accessible from your other component.
One possible solution is to register your store in the index.js like:
import Vue from "vue";
import App from "./App.vue";
import store from "./store";
import plugin from "./plugin";
Vue.use(plugin);
new Vue({
store,
components: {
App
}
}).$mount("#app");
You can then expose $doStuff() and get access to $store in the plugin.js
export default {
install(Vue) {
Vue.prototype.$doStuff = function (payload) {
this.$store.dispatch("SOME_RANDOM_ACTION", payload);
};
}
};
The store instance is accessible from your plugin or all the other components.
You can see a working sample here

using vuejs mixins in js file

i have a system in which i have to set up some reusable functions to be used all over my application, now i have created a vue mixin in my main main.js file now when i call that function from vue components it works just fine but when i try to call the same function inside a js file i get an error of undefined here's my code
main.js
Vue.mixin({
methods: {
test: function () {
return 1;
},
}
});
Vue Components
//this works
async created() {
alert(this.test());
}
services.js
import { API } from 'aws-amplify';
import { Auth } from "aws-amplify";
import axios from 'axios'
export default {
somefunction(){
//this doesnot work
alert(this.test());
}
}
can someone tell me how can i use vue mixins in regular js files, i looked on the internet but couldn't find anything related to this
// mixin.js
export myMixin = { computed: { foo(): 'hi' } }
Simply create an object (and likely mark it as an export) besides adding it to vue.
It's just an object. It has special names like computed, data etc. in it, but it's just an object.
// usage.vue
import { myMixin } from './path/to/myMixin.js'
console.log( myMixin.computed.foo ) // hi
export default {
mixins: [ myMixin ],
computed: { bar(): { this.foo } // hi
}
In the above example, I'm not using a global mixin, because, to quote vue docs
Use global mixins sparsely and carefully, because it affects every single Vue instance created, including third party components.
Now, if you really need a global mixin, that's why it's for, but note that to use myMixin outside of vue export default, you'd need to access it via global scope, like window, or import it like above. For more info refer to queries like these: global functions in js.
My preference:
// in a file at /path/to/index.js
export { myMixin1 } from './myMixin1' // ...
// usage.vue
import { myMixin1, myMixin2 } from './path/to'
export default { mixins: [ ... ] }
or alternatively where needed, (because mixins can include other mixins ;) though I find it harder to use them in other JS then
export myMixin1 = { ... }
export myMixin2 = {
mixins: [ myMixin1 ]
// ...
}
// usage.vue
import { myMixin2 } from 'path/to/myMixins'
export default {
mixins: [ myMixin2 ] // contains both 1 and 2
}
Note you can also declare in Vue files (single file components), and then import from them just as they were Javascript.
Also, you (obviously) don't need to export them - they're already useful for separating concerns.
// example.vue
<script>
export myMixin = { ... }
// all mixins can interact with each other
// because in the end, they will be parts of the same object
myToggle = { ... }
mySuperComplicatedBit = { ... }
// so B can call this.A
export default {
mixins: [
myMixin,
myToggle,
mySuperComplicatedBit
],
...
}
</script>
<template> ...
// other.vue or other.js
import { myMixin } from 'path/to/example.vue'
Cheers and good luck
If your mixin is generic you could use a global mixin and access it via the main application. But I don‘t really see the point, then why have a mixin in the first place?
main.js
export default new Vue({
mixins: [YourMixin]
...
})
somecode.js
import vue from ‚./main.js‘
vue.method()
Edit: suggestion
To be honest, I‘d rather turn your implementation around and have a service expose a functionality, which is then integrated to the Vue components via a mixin.
You can call methods in mixins only in Vue components. The role of the mixin is to extend the vue component. I would extract the logic from your mixin in a separate service or utility js and then use it in the mixin and service.js

How to import a js class in main.js file of a vue.js project and use it in all the components instead of importing in each component?

I have written some JS classes that I would like to import in the app.js/main.js file of my vue.js project so that I can instantiate them in the components. Right now I am having to import the same JS class in all the components where I need the class individually.
I've tried the import in the main.js file but the components don't recognize it.
in the main.js file, I am importing like as follows
import Permissions from './Permissions'
However, when I want to instantiate the Permissions class in my component like
data() {
permissions: new Permission({
some object properties...
})
}
the component doesn't know what Permissions is.
How do I let the component know what Permissions class is?
To do it in the vue way, you can create your own plugin or mixin. See detailed instructions here
So, you can create a permissions plugin in permissions-plugin.js
import Permissions from './Permissions'
const PermissionsPlugin = {
install(Vue, options) {
// This adds the $getPermissions method to all instances
Vue.prototype.$getPermissions = function(properties) {
return new Permission({
some object properties...
})
}
}
};
Then you have to tell vue to use your plugin:
import Vue from 'vue'
import PermissionsPlugin from './permissions-plugin.js'
import App from './App.vue'
// The plugin is loaded here.
Vue.use(PermissionsPlugin)
new Vue({
el: '#app',
render: h => h(App)
});
And lastly now from any component you should be able to use your function like:
this.$getPermissions(properties)

declare mapState and mapMutations globally in SPA VueJS

I am creating a basic SPA, but it happens that the states I manage with Vuex and the mutations up there all right, but in each component that I want to use mapState and mapMutations I have to import them locally.
<script>
import {mapState,mapMutations } from 'vuex';
export default{
computed : mapState(['isLoggedIn']),
methods: {
...mapMutations(['logout'])
}
}
</script>
This is the correct way to do it? Or how can I declare them globally and avoid importing in each component so that it is as follows?
<script>
export default{
computed : mapState(['isLoggedIn']),
methods: {
...mapMutations(['logout'])
}
}
</script>
Quick solutions
The Vuex helpers like mapMutations etc. returns an object populated with functions which assumes that this.$store is a Vuex store.
Store service
If you need to use the store in vanilla JS and you don't want to expose the store module everywhere, you could define a service module.
import { mapActions } from 'vuex';
import $store from '#/store';
/**
* Simple mapping of the Vuex store UI module.
* #module services/ui
* #property {Function} pushMessage
*/
export default Object.assign({
$store,
}, mapActions('ui', ['pushMessage']));
Now, using it is as simple as importing the service module.
import ui from './services/ui';
// triggers the `pushAction` on the ui namespaced store module
ui.pushMessage({ content: 'whatever' });
Vue mixin
To have default computed and methods on a Vue component, you can create a simple mixin to import in specific components.
import { mapState, mapMutations } from 'vuex';
export default {
computed : mapState(['isLoggedIn']),
methods: mapMutations(['logout'])
}
Then, use the mixin in a component.
<script>
import mixin from './mixin';
export default {
mixins: [mixin],
data() {/* ... */},
// etc.
}
</script>
Global mixin
If you really want each component to have this default mixin without having to explicitly define it, use a global mixin.
import Vue from 'vue';
import { mapState, mapMutations } from 'vuex';
export const mixin = {
computed : mapState(['isLoggedIn']),
methods: mapMutations(['logout'])
};
Vue.mixin(mixin);
Personally, as a standard, I never map the state or mutations.
I only map getters and actions so my components don't need to know the state structure and that an action is async or not. I see getters and actions as the public API of a Vuex store (or any similar store, like Redux).
I also only map the relevant data. Components responsibility is to interact with the user of the app, displaying and handling events and nothing more. If all your components need the user object, maybe they're doing too much and that logic should probably be moved elsewhere, like in an action.
See more on Vue communication

how do I access `this.` in exported in vuejs

I have some files that return simple data, like mutation.js for vuex but generally they are just like this:
export default {
...
someFunction() {}
...
}
Right now, I would like to access this. so I can use the vue-i18n translation like this.$t('TRANS_TOKEN') but for some reason I am not able to use this. I am thinking about including vue in this file as: import vue from 'vue' and probably do vue.$t(..) if it works but I tried it and it doesn't
First a question. Why doing translations in mutations file? I'd keep translations in your components only.
You can however achieve what you want, by doing so
// i18n.js
const i18n = new VueI18n();
export default i18n;
// main.js
import VueI18n from 'vue-i18n';
import i18n from './i18n.js';
Vue.use(VueI18n);
new Vue({
i18n,
...
});
// Anywhere else, grab the i18n instance to do translations
import i18n from './i18n.js';
i18n.t('translate this');
Documentation on all the methods available on the VueI18n instance.

Categories

Resources