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
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>
<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.
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/
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>
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>