Access VueRouter outside Vue components - vuejs2

Is it possible to access the VueRouter outside of Vue components.
I've tried importing Vue in a JavaScript file. In this file I can access Vue.http but not Vue.router or Vue.$router. The last 2 return undefined.
main.js
import Vue from 'vue'
import VueResource from 'vue-resource'
import VueRouter from 'vue-router'
import routes from './config/routes'
import store from './store'
import * as rootUrl from './config/rootUrl'
//Routing support
Vue.use(VueRouter);
//Backend support
Vue.use(VueResource);
const router = new VueRouter({
mode: 'history',
routes: routes
})
new Vue({
store,
router,
}).$mount('#app')
Vue.http.get(rootUrl.url, {Accept: "application/json"}).then(response => {
let data = response.body
store.commit('SET_APP_DATA', { data: {
'title': data.title,
'peopleUrl': data.people,
'eventsUrl': data.events
}})
store.commit('SET_READY')
})

I've used it only from components but you could try following in case you're using common boilerplate where routes are defined under router/index.js then you just import it like:
import Router from '../router';
After it is possible to use it in code e.g.
Router.push('/mypage')
Not sure if it works but give it a try.

I resolved this by exporting my router instead of my routes in routes.js (now router.js)
export default new VueRouter({
mode: 'history',
routes: routes
})
Any file can then access the router with
import router from 'config/router'

You've defined your router with this statement
const router = new VueRouter({
mode: 'history',
routes: routes
})
So all you need to do to access it outside Vue is use
router.push(...)
Or whatever else you want to do.
If you want to use it in some other file, you may need to expose it on the window.

Add the router to your Vue constructor in the same file that you create and initialize your vue instance.
Vue.$router = router
Then use it as you first tried.
Vue.$router.push(...)
If using Typescript, you can augment the VueContructor to enable type checking and autocompletion.
mytypes.d.ts
import {VueRouter} from "vue-router/types/router";
declare module 'vue/types/vue' {
interface VueConstructor {
$router: VueRouter
}
}

Related

VueJS not reference NestJS ServeRoot Base path

I am using the NestJS ServeStaticModule to resolve my admin and client front-ends to two different paths, /client and /admin.
When we try to load this page Vue is attempting to load the JS, CSS and other local assets without the /{prefix} in-front resulting in a 404.
Is there a way to work around this, do I need to define at a Vue level what the route is going to be prior to building?
My solution was to add the pass path to my VueRouter when in production. For example if you are trying to replicate this is how it would look:
import Vue from 'vue';
import Router from 'vue-router';
Vue.use(Router);
const router = new Router({
mode: 'history',
base: (process.env.NODE_ENV === 'production' ? '/admin' : undefined ),
routes: [...]
});
export default router;

How to use Axios in main.js

I am learning Vue.js.
I have this code which runs fine :
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
const app = createApp(App).use(store).use(router)
app.mount('#app')
Now I would like to add some import, for example 'axios'. This code does not run :
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'
const app = createApp(App).use(store).use(router).use(axios)
app.mount('#app')
The error is:
Uncaught RangeError: Maximum call stack size exceeded
at merge (utils.js?c532:276)
at assignValue (utils.js?c532:282)
at forEach (utils.js?c532:253)
at merge (utils.js?c532:291)
at assignValue (utils.js?c532:282)
at forEach (utils.js?c532:253)
at merge (utils.js?c532:291)
at assignValue (utils.js?c532:282)
at forEach (utils.js?c532:253)
at merge (utils.js?c532:291)
So how to add some other "use" in the main.js file ? It is certainly very basic but I am a beginner.
You're using vue 3 and axios is not a plugin (we cannot register it like app.use()) it's a javascript module that could be add to the app instance like :
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'
const app = createApp(App).use(store).use(router)
app.config.globalProperties.axios=axios
app.mount('#app')
and in child component reference it like :
this.axios
Note: the code below is valid for Vue 2.x. Since version 3, some stuff has changed regarding initialization (createApp function is now required).
What I usually do in my code is the following:
import Vue from 'vue';
import axios from 'axios';
// Add it to Vue prototype (use any variable you like, preferrably prefixed with a $).
Vue.prototype.$http = axios;
// Instantiate the main vue app.
let app = new Vue({
//
});
This means that the $http object is now available in all your components using this.$http. Since it is assigned as a prototype variable, it is considered a singleton (it is re-used everywhere), so you can add any options you need to the axios variable before assigning it to Vue.prototype.$http.
Additionally:
Vue.use() is made specifically for enabling Vue plugins. That means the given parameter must use the exact syntax as described here https://v2.vuejs.org/v2/guide/plugins.html . Since axios is not a Vue plugin but just a regular JavaScript library, you cannot use it with this function.
If you want to make it especially nice (or convoluted), you can use the following syntax:
Vue.use({
install(v) {
v.prototype.$http = axios;
// Do other stuff like adding mixins etc.
}
})
This may clear up your code if you move this code to another file, so it could end up like this:
import myCustomAxiosLoader from './bootstrap/axios';
Vue.use(myCustomAxiosLoader);

Vuex module not accessible from rootState

I needed to get route's query parameters inside Vuex in order to preload filter settings and update the state of the application. To make this possible I installed vuex-router-sync.
Next step was to synchronize the Vuex and VueRouter.
Router:
Vue.use(VueRouter);
export default new VueRouter({ mode: 'history' });
Store:
Vue.use(Vuex);
export default new Vuex.Store({
modules: { filters: FiltersModule },
plugins: [ FiltersPlugin ]
});
App's bootstrap:
const unsync = sync(store, router);
new Vue({
el: '#restaurant-admin-app',
components: {
'App': AppComponent,
'filters': FilterComponent,
'orders-table': OrdersTableComponent
},
store,
router
});
My FilterPlugin that should trigger the URL parsing:
export default store => {
store.dispatch('filters/parseURLFilterSettings');
}
And now, the funny part, here's the URL parsing action:
parseURLFilterSettings: ({ state, commit, rootState }) {
console.log('RootState:', rootState);
console.log('Route module (incorrect):', rootState.route);
console.log('Filters module (correct):', rootState.filters);
console.log('Object\'s keys:', Object.keys(rootState));
}
What am I doing wrong? I thought it might be something with syncing, but at the end the console.log shows clearly that the route Object is there (and it's not empty), but somehow when I access it, it's undefined. Thank you in advance.
The problem was very well explained here. What it basically says is that the object's value is evaluated when you open it's body in the console.
The problem was I didn't have the route module loaded yet, because I was trying to dispatch an action from a vuex plugin which seems to load before the vuex-router-sync's syncing was done.
The problem was solved when I moved application's bootstrap logic from vuex plugins into the AppRootComponent's mount lifecycle event.
You should import the router-sync. After that your store and routes wil behave properly. I usually do this in the main.js file.
import router from './router'
import store from './store'
import { sync } from 'vuex-router-sync'
sync(store, router)

Url query params

I am using Vue 2.4.4. I have been searching for gettin URL query params, and most places following are suggested:
this.$route.query.test
$route is undefined do you need to do something special to get this working?
I found a solution thanks to tanathos:
var router = new VueRouter({
mode: 'history',
routes: []
});
var index = new Vue({
el: '#index',
router,
mounted: function () {
alert(this.$route.query.test);
In your main.js (or anyway, the entry point of your application) you'll need first to import the VueRouter:
import Vue from "vue";
import VueRouter from 'vue-router';
and use it to extend Vue:
Vue.use(VueRouter);
At this point you'll need to crete the real instance of the router, configuring it according to your application's needs:
const router = new VueRouter({
/* your configuration options */
});
The you inject this instance in the Vue root instance:
new Vue({
router,
/* etc... */
});
At this point the $router and $route object should be available from any Vue component.

Difference between Vue.use and constructor import with VueRouter

What is the difference between these two options when importing VueRouter?
import router from './router'
const app = new Vue({
el: '#app',
router,
});
vs
Vue.use(VueRouter);
I understand that Vue.use installs a plugin, is it necessary when passing it into my Vue instance constructor?
Your first example is passing a router definition object to the Vue instance. Your second example is registering the VueRouter plugin.
The VueRouter plugin needs to be registered to Vue via Vue.use(VueRouter) prior to passing the router object.
If you are confused why your first example works, even though you haven't registered VueRouter, I'd expect that Vue.use(VueRouter) is being called in the router.js file being imported.