I need to call router.replace before injecting the router into the Vue instance. But can't figure out why history property is undefined in that situation:
VueRouter.prototype.replace = function replace (location) {
this.history.replace(location) // TypeError: Cannot read property 'replace' of undefined
}
Here is the online example (check the console) and the code snippet:
// 0. If using a module system, call Vue.use(VueRouter)
// 1. Define route components.
// These can be imported from other files
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
// 2. Define some routes
// Each route should map to a component. The "component" can
// either be an actual component constructor created via
// Vue.extend(), or just a component options object.
// We'll talk about nested routes later.
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
// 3. Create the router instance and pass the `routes` option
// You can pass in additional options here, but let's
// keep it simple for now.
const router = new VueRouter({
routes
})
try {
router.replace('/bar');
} catch(e) {
console.log(e); // TypeError: Cannot read property 'replace' of undefined
}
// 4. Create and mount the root instance.
// Make sure to inject the router with the router option to make the
// whole app router-aware.
const app = new Vue({
router
}).$mount('#app')
// Now the app has started!
You should do it after injecting the router into a Vue instance. I think this is intended, but would like some input from @fnlctrl and/or @yyx990803
That this.history requires the vue instance the router is injected to be created (to call router.init() which sets up this.history), which doesn't exist yet when you call router.replace() before injecting. Unfortunately there's no way around that.
However, if you only need router.replace functionality, you can directly call the native browser apis that are called by vue-router under the hood:
For history mode, it's simply window.history.replaceState('/').
For hash mode, it's window.location.replace('#/')
@HashemQolami Did it solve your problem?
@fnlctrl hmm.. that makes sense. I guess you meant the window.history.replaceState().
I was under the assumption that this points to the created VueRouter instance, still can't find out how it points to the Vue instance. Any hints are appreciated.
I guess you meant the window.history.replaceState().
Yeah.. fixed it.
still can't find out how it points to the Vue instance
I was wrong about it, and you probably missed my updated comment above 馃槀 .
@fnlctrl
That
this.historyrequires the vue instance the router is injected to be created (to callrouter.init()which sets upthis.history) [...]
Does setting up the this.history require the presence of the vue component instance? Or that is a design decision?
I am asking as it seems that the HTML5History just needs the router.options to be instantiated. Actually it is the this.$options.router.options.base where this is the vue component instance. Or the base property varies? (belonging to each vue component?)
Does setting up the
this.historyrequire the presence of the vue component instance? Or that is a design decision?
It's nessessary by the fundamentals of the implemented transitioning process.
When you do router.replace() you trigger a route transition, which relies upon the router-view component to initialize the right components - which can't happen before your app has started.
Also, things like the in-component beforeRouteLeave hook are executed by History, and won't have access to the vm as this because, again, the component can't be initialized by router-view without the application being started.
etc. pp.
I'm looking into this, looks like basic functionalities like replace/push can really be performed before vue instance initialization, with some changes to the source.
Not sure the options that _could be_ available exceed what window.history offers, but happy to be proven wrong :)
@LinusBorg I didn't mean you're wrong, sorry if I made you think that... Your explanation was perfect, and I'm just thinking that it may be an improvement to allow users to do basic replace/push before initializing root vue instance. And I just got a proof-of-concept working that passed all tests, will submit a PR shortly. ;)
I didn't take it that way, don't worry ;) I hope you're successful
fixed via 83418bce4b66b0320047a0f7cbd50a3a2d2b4d1f