Vue.js / Mixins - Is there a way to get the global mixin-object outside of the vue component? - vue.js

I am new with Vue.js
I am using Vue.js 2.4.4.
I have created the global mixin in my app.js file:
...
import router from './router'
...(some imports and plugins definitions)
Vue.use(VeeValidate);
Vue.component(VuePassword);
...
Vue.mixin({
data: function(){
return {
get auth(){
return Auth;
}
}
}
});
const app = new Vue({
el: '#root',
template: `<app></app>`,
components: { App },
router
});
This mixin imports some Auth object with validation methods e.t.c which needed to be in every component.
All of my components can check this mixin and it's working fine.
But I need to check the auth state after every route request, and I want to use my currently existing mixin, so I am trying to make something like this in my router.js file:
import Vue from 'vue'
import VueRouter from 'vue-router'
...
Vue.use(VueRouter);
const router = new VueRouter({
routes:[
...
]
});
router.beforeEach((to, from, next) => {
if(to.meta.requiresAuth) {
if(...call to mixin method) {
next();
} else {
next('/');
}
} else {
next();
}
});
export default router
Question:
Is there a way to get the global mixin object and change it's inner values or can you please give some small advise or example what is the right solution to this kind of tasks?
Or should I use the plugins instead of mixins?

I would rather create a seperate file for auth and not make it a mixin. Then using Vue.use() which will set auth on the vue object.
A sample of what the files might look like:
auth.js
export default function(Vue) {
Vue.auth = {
// do your auth logic
}
}
Then in your main js file
main.js
import Auth from './auth.js'
Vue.use(Auth);
Then you should be able to use Vue.auth
Another option would be keep using the mixin and pass the value to a store (like vuex) or create your own if your project is small...

Related

Use vue router (v4) in a plain .js file with Quasar framework (v2)

I'm trying to access the router from a plain .js file in a Quasar project but I'm not being able to. I have search how to do it in vue and people seem to import the Router object from /src/router/index, like this: import { Router } from 'src/router/index'.
But Quasar doesn't expose the Router object, but a function called route that accepts another function as an argument that returns the Router object.
export default route(function (/* { store, ssrContext } */) {
const createHistory = process.env.SERVER
? createMemoryHistory
: process.env.VUE_ROUTER_MODE === 'history'
? createWebHistory
: createWebHashHistory;
const Router = createRouter({
scrollBehavior: () => ({ left: 0, top: 0 }),
routes,
// Leave this as is and make changes in quasar.conf.js instead!
// quasar.conf.js -> build -> vueRouterMode
// quasar.conf.js -> build -> publicPath
history: createHistory(process.env.MODE === 'ssr' ? void 0 : process.env.VUE_ROUTER_BASE),
});
return Router;
});
How can I use the Router object outside a SFC with Quasar?
Ideally, you shouldn't need the router outside Vue components, outside boot files, outside src/router/index.js, outside src/store/index.js, and except the places where you define a function that gets called in Vue files(e.g. composables/helpers). Here are all the ways to access the router, both inside and outside SFCs:
Inside .vue files:
Composition API(inside setup() or ): const router = useRouter()
Options API: this.$router
Inside the <template> section: #whatever="$router.push('...')"
Inside boot files:
// src/boot/whatever.js
export default boot(({ router }) => {
router.beforeEach(...)
})
Inside src/router/index.js(using boot files are better):
const router = createRouter(...)
router.beforeEach(...)
Inside a function/composable which you use in .vue files:
// /src/composables/whatever.js
export function useWhatever() {
const router = useRouter()
// ...
function changeRoute () {
router.push('...')
}
return {
changeRoute,
// ...
}
}
// Inside setup() or <script setup>
const { changeRoute } = useWhatever()
changeRoute()
As a last resort / lazy way: (Won't work with SSR)
// src/router/index.js
// Remove export default function route(...), and use it like this:
const router = createRouter(...)
export default router;
// src/whatever.js
import router from 'src/router';
router.push('...');

Vue build didnt include my function to output .js file

Works fine in dev mode, but after build process vue not includes setupToken function (from #/api.js) to app.js output file.
// App.vue
//...
import { setupToken } from '#/api
export default {
mounted () {
this.setupToken() // TypeError: this.setupToken is not a function
}
}
// #/api.js
import { mande } from 'mande'
export const postsAPI = mande(`${process.env.VUE_APP_ROOT_URL}/api/v1/posts`)
export const setupToken = ({ token }) => {
postsAPI.options.headers.Authorization = 'Bearer ' + token
}
I guess the problem with webpack config (im using default one), but not sure how to fix it.
setupToken does not exist on the object you're exporting from App.vue.
You are importing setupToken from #/api so you have to call it directly, i.e. setupToken() and not as an instance method, i.e. this.setupToken()
WebPack sees you are not using the method you're importing from #/api (because you are calling it as an instance method) so it tree-shakes it out.
BTW, try using TypeScript, it would have let you know of that error.
Import api.js in main.js
import Vue from 'vue'
import App from './App.vue'
import api from './api'
Vue.config.productionTip = false
new Vue({
api,
render: function (h) {
return h(App)
},
}).$mount('#app')
Modify api.js:
import Vue from 'vue'
Vue.mixin({
methods: {
setupToken({ token }) {
postsAPI.options.headers.Authorization = 'Bearer ' + token
}
}
}

How I can access $data variable of a Mixin.js file from Store.js using Vue.Js?

I have a Mixin file like this:
export default {
data: function() {
return {
analysisTime: "nothing",
phantomPrefix: "One more",
}
},
methods: {
isGeneric: function() {
return this.phantomPrefix
},
}
}
Whenever I call Mixin.js its methods are accessible but the $data variable is returning undefined.
For example, Whenever I called isGeneric function it's returning undefined instead of 'one more' because it's returns this.phantomPrefix.
Ps: If I access the same method of Mixin.js file from another component let's say Example.Vue it's working fine for me.
I have imported the Mixin file in store.js like:
import Mixin from "./mixins/Mixin";
and calling method like this: Mixin.methods.isGeneric()
Store.js file contains:
import Vue from "vue";
import Vuex from "vuex";
import tmpMixin from "./mixins/tmpMixin";
Vue.use(Vuex);
let vue_plugins = [];
export default new Vuex.Store({
plugins: vue_plugins,
state:{},
action:{
get_snippet_data_using_tomograph: function(data) {
let output = tmpMixin.methods.isGeneric()
}
}
});
Vue mixins are made for Vue components, it's not compatible with a Vuex module.
A mixins expect a Vue component instance, which is not provided by Vuex when you import it like this.
If you need to have a reusable code between a Vuex store and Vue components, you still can create a simple js file that exports a functions. But it won't be reactive or have a current state because it's not a Vue component.

Use Vue Router In Script

I have a script that will redirect a user to the login screen when they get a response code of 401 - which means their session has expired within the API.
import axios from 'axios';
axios.interceptors.response.use(function (response) {
return response;
}, function(error) {
if(error.response.status === 401) {
localStorage.clear();
window.location = '/';
return Promise.reject(error);
}
return Promise.reject(error)
})
I wish to use vue router instead of window.location to redirect to the login page.
I have tried adding these lines of code to the script:
import Vue from 'vue';
Vue.$router.push({ name: 'login' })
I get an error.
How would one go about using vue router in this instance?
Make sure you already installed vue router. If not yet, this is how to install
npm install vue-router // npm
or vue router cdn
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
When used with a module system, you must explicitly install the router via Vue.use(). Do this one
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
then redirect to other page like this
this.$router.push({ name: 'nome-of-location'})
You can try this:
this.$router.push({ name: 'nome-of-location'})
This problem is is applicable to other frameworks like React and Angular and should be solved similarly there.
Router instance is unavailable outside component hierarchy, it cannot be accessed when Axios interceptor is defined in module scope.
It's also unwise to modify global Axios instance because it can be used by third-party libraries and cause unexpected side effects for them, this also makes clean-up more complicated in tests.
Local Axios instance can be defined in Vue application, also allows to define specific options like base URL:
Object.defineProperty(Vue.prototype, 'axios', {
get() {
return this.$root._axiosInstance;
}
});
Vue.mixin({
created() {
if (this.$root === this) {
let axiosInstance = axios.create({/*...*/});
axiosInstance.interceptors.response.use(
response => response,
error => {
...
this.$router.push(...);
...
}
);
this._axiosInstance = axiosInstance;
}
}
});
And is accessed as this.axios inside components.

importing store to a vuejs nuxt project

I'm trying to write a simple plugin for my Vue.js(Nuxt) project. I came across this post Adding Mutations to Vuex store as part of Vue Plugin but still unable to get it working.
Here is my application structure.
~ is root
~/plugins/HTTP/index.js
~/plugins/HTTP/_store/ => index.js, actions.js, getters.js, mutations.js
~/plugins/HTTP/_api/ => index.js
**Global Store**
~/store/index.js
~/store/modules/
~/store/modules/testing => index.js, actions.js, getters.js, mutations.js
in my ~/plugins/HTTP/index.js, I have the following code
import Vue from 'vue';
import store from '~/store';
const HTTP = {
install(vue, { store }){ // Now you plugin depend on store
if(!store){
throw new Error('Please provide vuex plugin.')
}
// register your own vuex module
store.registerModule({store})
}
}
export default HTTP;
Vue.use(HTTP)
In my ~/store/index.js I have the following code:
import Vuex from 'vuex'
import testingModule from './modules/testing'
const state = () => {
return new Vuex.Store({
modules:{
testing: testingModule
}
})
}
export default state
When I try to run it, it gives me the following message:
Cannot destructure property `store` of 'undefined' or 'null'.
What did I do wrong here?
You aren't passing any properties so the error is correct. You need pass in an options object when you tell it to use. It can be empty, but it needs an object.
import Vue from 'vue';
import store from '~/store';
const HTTP = {
install(vue, { store }){ // Now you plugin depend on store
if(!store){
throw new Error('Please provide vuex plugin.')
}
// register your own vuex module
store.registerModule({store})
}
}
export default HTTP;
Vue.use(HTTP, {}) // <---------- Empty object to avoid allow destructuring.