While the solution works, there are two problems:
- The Hello component mutates its own
agility property. This shouldn't happen (Vue generates a warning in the console), instead an event should be emitted so that the property is changed upstream. That way, the value is always stored in only one place, modifying the value in that one place will modify it everywhere else.
- If the url's hash changes, due to the user manually entering the new url or clicking a link, the value in the input will not be updated
To solve the first problem, we will not use v-model on the agility property, as we don't want to mutate it. We need to listen to the input's event directly:
<input min=0 max=100 :value="agility" type="range" @input="updateAgility">
{
...,
methods: {
updateAgility(event /*: InputEvent */) {
this.$router.push({...this.$route, hash: "#" + event.target.value});
}
}
}
This will directly change the url when the input changes value. The second issue is how to update the prop agility when the url changes.
Doing it in created is not enough, as the component is not recreated if the page stays the same but the hash changes.
So we go back to the original solution, directly setting the prop from the router:
{
path: "*",
component: Hello,
props: route => route.hash.length > 1 ?
{ agility: Number(route.hash.slice(1))} :
{}
}
Now whether you update the value from the URL or the input, the URL & input value are always in sync. And the warning about mutating a prop is gone.
// https://github.com/vuejs/vue-router/blob/dev/examples/route-props/Hello.vue
var Hello = Vue.component('Hello', {
template: `
<div>
<h2 class="hello">Hello {{agility}}, Current route's hash: {{ $route.hash}}</h2>
<input min=0 max=100 :value="agility" @input=updateAgility type="range">
<br>
<router-link to="#1">Hash 1 link</router-link> <router-link to="#15">Hash 15 link</router-link>
</div>
`,
props: {
agility: {
type: Number,
default: 25
}
},
methods: {
updateAgility(event/*: InputEvent */) {
this.$router.push({...this.$route, hash: "#" + event.target.value});
}
}
});
const router = new VueRouter({
// mode: 'history',
routes: [
{ path: '*', component: Hello, props: route => route.hash.length > 1 ? { agility: Number(route.hash.slice(1))} : {}},
]
})
new Vue({
router,
template: `
<div id="app">
<router-view></router-view>
</div>
`
}).$mount('#app')
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app"></div>
Just for info: it's also possible to listen to url changes in the component itself, by creating a watcher on '$route.hash', but it's not the recommended way.