Passing route params in vue router v-link - vue.js

I have this anchor in Parent.vue:
<a v-link="{ path: '/somepath/somesubpath', query: { messageId: 999}}"> Here </a>
or also this
<a v-link="{ path: '/somepath/somesubpath', params: { messageId: 999}}"> Here </a>
My Child.vue is like this:
<template>
{{messageId}}
// other html..
</template>
<script>
export default {
props: ['messageId']
}
</script>
In Child.vue I can not see the value of {{messageId}} being rendered. This means that the value is not getting passed.
I am using vue router 0.7.5 and the docs here do not specify how to specify params in v-link (without named routes).
So whats the proper way to pass in params using vue router with v-link?

Route params are available in the this.$route.params property. They do not need to be passed as a component property.
In your case you can access the messageId param in your template like so:
{{ $route.params.messageId }}
However, you also need to make sure that the template for your Child.vue component has a single root element and not just text. Otherwise, the component will not render.
So, you'd at least need something like this:
<template>
<div>
{{ $route.params.messageId }}
</div>
</template>
Here's a simple example:
Vue.component('child', {
template: `
<div>
message id: {{ $route.params.messageID }}
</div>
`
});
const Home = {
template: '<div>Home</div>'
};
const Message = {
template: `
<div>
<span>Message View</span>
<child></child>
</div>
`
};
const router = new VueRouter({
routes: [
{ path: '/', component: Home, name: 'home' },
{ path: '/message', component: Message, name: 'message' }
]
})
new Vue({
router,
el: '#app'
})
<script src="https://npmcdn.com/vue/dist/vue.js"></script>
<script src="https://npmcdn.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<router-link :to="{ name: 'home' }">home</router-link>
<router-link :to="{ name: 'message', params: { messageID: 123 } }">message view</router-link>
<router-view></router-view>
</div>

Related

NavBar in Vue using v-for and router

I have this default vue navbar which I want to make it more dynamic by using v-for.
Before changes, this is the code:
<template>
<div>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
</template>
After changes, this is the code:
<template>
<div>
<div v-for="navbar in navbars" :key="navbar.id">
<router-link :to="navbar.router">{{ navbar.names }}</router-link>
</div>
</div>
</template>
<script>
export default {
name: "Header",
navbars: [
{ names: "Home", router: "/" },
{ names: "About", router: "/About" }
]
};
</script>
But after converted it, the navbar doesn't show up. Anything I miss out?
You need to define navbars as a data of the component using data
<template>
<div>
<div v-for="navbar in navbars" :key="navbar.id">
<router-link :to="navbar.router">{{ navbar.names }}</router-link>
</div>
</div>
</template>
<script>
export default {
name: "Header",
data: function () {
return {
navbars: [
{ names: "Home", router: "/" },
{ names: "About", router: "/About" }
]
}
}
};
</script>

how to use router-link custom navigation instead of `to` prop

<router-link to="/" tag="a" :title="title">
<span class="icon icon-home i-large" />
<span class="class-2">Name</span>
</router-link>
This is what I have...
As you can see , I am using to prop. But I don't want to use it. Whenever someone clicks on this, i want to execute a function and use programatic navigation.
How is this possible? the structure and htmls that I have shouldn't change and it still should work as expected.
Something like this you mean?
<a #click="functionThatExecutesMyCode">
<span class="icon icon-home i-large" />
<span class="class-2">Name</span>
</a>
functionThatExecutesMyCode() {
this.$router.push({ to: 'newRoute'})
}
Else you should use the navigation guards: https://router.vuejs.org/guide/advanced/navigation-guards.html
I don't think it's possible to change :to props to add a function, because it is predefined as only accept a string in its docs. https://router.vuejs.org/api/#to
However, I suggest another way to implement what you want, you can add the logic in beforeEach hook. For example
router.beforeEach( (to, from, next) => {
// implement your logic here, for example if no internet, go to error page
if (!navigator.onLine && to.name !== "NetworkError") {
next({ name: "NetworkError" });
return false;
}
next();
}
For more info, look at their docs: https://router.vuejs.org/api/#router-beforeeach
It depends on what you exactly want.
There are easier solutions, like:
const Root = {
template: '<div>Root</div>'
}
const Route1 = {
template: '<div>Route1</div>'
}
const routes = [{
path: '/',
name: 'root',
component: Root
},
{
path: '/1',
name: 'route1',
component: Route1
}
]
const router = new VueRouter({
routes // short for `routes: routes`
})
new Vue({
el: "#app",
router,
data: {
selected: 'root',
options: ['root', 'route1']
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<select v-model="selected">
<option v-for="(option, i) in options">
{{ option }}
</option>
</select>
<router-view></router-view>
<router-link :to="{ name: selected }">{{ selected }}</router-link>
</div>
In this solution I used a named route, and the "name" can be changed by the select input.
The next solution is to incorporate a function:
const Root = {
template: '<div>Root</div>'
}
const Route1 = {
template: '<div>Route1</div>'
}
const routes = [{
path: '/',
name: 'root',
component: Root
},
{
path: '/1',
name: 'route1',
component: Route1
}
]
const router = new VueRouter({
routes // short for `routes: routes`
})
new Vue({
el: "#app",
router,
data: {
selected: 'root',
options: ['root', 'route1']
},
methods: {
changeRouteName() {
return this.selected
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<select v-model="selected">
<option v-for="(option, i) in options">
{{ option }}
</option>
</select>
<router-view></router-view>
<router-link :to="{ name: changeRouteName() }">{{ selected }}</router-link>
</div>
By adding a method to resolve the name of the component, it's possible to build ANY logic on the to of the <router-link. You could also use path instead of name of course - I just like named components.
It does not remove the click event from the to prop, but you can do your logic before returning the name it's "waiting" for.

Vue router dynamic link and children reload page - not load correctly component

I add to my routes file path with children:
path: '/warehouse/:id',
name: 'ShowWarehouse',
component: ShowWarehouse,
children: [{
path: 'edit',
name: 'EditWarehouse',
component: EditWarehouse
}
]
Now in component ShowWarehouse I have:
<div v-if="!changeEdit">
<div v-if="warehouseData">
<div>Name: {{ warehouseData.warehouse.name }}</div>
<div>
<router-link
:to="{ name: 'EditWarehouse', params: {id: warehouseData.warehouse.id }}"
>Edit</router-link>
</div>
</div>
</div>
<router-view v-else></router-view>
When the user click edit button I need load component EditWarehouse, but component ShowWarehouse must be disappear, and if user back (without /edit) disappear componet EditWarehouse and load component ShowWarehouse. I write method in watch:
watch: {
$route() {
if (this.$route.path == '/warehouse/' + id_get_from_API + '/edit') {
this.changeEdit = true;
} else {
this.changeEdit = false;
}
}
},
The problem is when the user is at mydomain.com/warehouse/23/edit and click reload page (F5), then Vue loads component ShowWarehouse instead of loading EditWarehouse.
I using mode: 'history'.
Problem:
From the Vue.JS website: "Vue does provide a more generic way to observe and react to data changes on a Vue instance: watch properties." When you refresh the page the watch() method will not be executed because it is a new Vue instance and no data has changed on the Vue instance yet. You should probably use a different pattern to determine which component to show. (https://v2.vuejs.org/v2/guide/computed.html#Computed-vs-Watched-Property)
Solution:
I suggest making the EditWarehouse a sibling route to ShowWarehouse, and make EditWarehouse its own component (you already have this). Your router-link in the ShowWarehouse component can stay the same.
Code Snippet:
const ShowWarehouse = {
template: `<div><h1>ShowWarehouse</h1> <div v-if="warehouseData">
<div>Name: {{ warehouseData.warehouse.name }}</div>
<div>ID: {{ $route.params.id }}</div>
<div>
<router-link :to="{ name: 'EditWarehouse'}">Edit</router-link>
</div>
</div></div>`,
computed: {
warehouseData: function() {
let data;
let id = this.$route.params.id;
if (id) {
data = {
warehouse: {
name: 'Some Warehouse Name',
id: id
}
}
}
return data;
}
}
};
const EditWarehouse = {
template: "<h1>EditWarehouse [{{ $route.params.id }}]</h1>"
}
const router = new VueRouter({
routes: [{
path: '/warehouse/:id',
name: 'ShowWarehouse',
component: ShowWarehouse
},
{
path: '/warehouse/:id/edit',
name: 'EditWarehouse',
component: EditWarehouse
}
]
});
new Vue({
el: '#app',
router
});
<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">
<p>
<router-link :to="{ name: 'ShowWarehouse', params: { id: 123 }}">Go to Warehouse 123</router-link>
</p>
<router-view/>
</div>
Here is a jsfiddle with the same code:
https://jsfiddle.net/austinwasinger/oruswb3a/39/

how to programmatically return to Vue cli's pre-made Home.vue

I'm using Vue CLI 3 and it makes a few routes. One is Home.vue. In my program I am trying to programmaticaly go to different pages. I added the routes I need in router.js but kept the already created routes for Home.vue and About.vue. It works fine until I get to 'Home' and get a warning: [vue-router] Route with name 'Home' does not exist.'
Here is the code:
<template>
<div class='secondItem'>
<h4 v-for="item in menuItems"
#click="bindMe(item)" v-bind:class="{'active':(item === current)}">{{item}}</h4>
</div>
</template>
<script>
export default {
name: 'Header',
data() {
return {
current: '',
menuItems: ['Home', 'About', 'Portfolio', 'Contact'],
}
},
methods: {
bindMe(item) {
this.current = item;
this.$router.push({
path: item
})
}
}
}
<script>
Are you using named routes? In that case you need to use name instead of path:
this.$router.push({
name: item
})
Also, your example can be simplified quite a lot. Try this:
<template>
<div class="secondItem">
<router-link :to="{ name: item }" tag="h4" active-class="active" v-for="item in menuItems" v-bind:key="item">{{item}}</router-link>
</div>
</template>
<script>
export default {
name: 'Header',
data() {
return {
menuItems: ['Home', 'About', 'Portfolio', 'Contact']
}
}
}
<script>

Add event listener to <router-link> component using "v-on:" directive - VueJS

I'm attempting to add a custom handler InlineButtonClickHandler to a <router-link> component's click event, so that I can emit a custom appSidebarInlineButtonClick event.
But, my code isn't working. What am I doing wrong?
<template>
<router-link :to="to" #click="InlineButtonClickHandler">
{{ name }}
</router-link>
</template>
<script type="text/babel">
export default {
props: {
to: { type: Object, required: true },
name: { type: String, required: true }
},
methods: {
InlineButtonClickHandler(event) {
this.$emit('appSidebarInlineButtonClick');
}
}
}
</script>
You need to add the .native modifier:
<router-link
:to="to"
#click.native="InlineButtonClickHandler"
>
{{name}}
</router-link>
This will listen to the native click event of the root element of the router-link component.
<router-link:to="to">
<span #click="InlineButtonClickHandler">{{name}}</span>
</router-link>
Maybe you can try this.
With vue 3 and vue router 4 the #event and tag prop are removed according to this and instead of that you could use v-slot:
const Home = {
template: '<div>Home</div>'
}
const About = {
template: '<div>About</div>'
}
let routes = [{
path: '/',
component: Home
}, {
path: '/about',
component: About
}, ]
const router = VueRouter.createRouter({
history: VueRouter.createWebHashHistory(),
routes,
})
const app = Vue.createApp({
methods: {
test() {
console.log("test")
}
}
})
app.use(router)
app.mount('#app')
<script src="https://unpkg.com/vue#3"></script>
<script src="https://unpkg.com/vue-router#4"></script>
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/" v-slot="{navigate}">
<span #click="test" role="link">Go to Home</span>
</router-link>
<br/>
<router-link to="/about">Go to About</router-link>
</p>
<router-view></router-view>
</div>