I have two path with same component like this:
/:loc("-host") - should match /usa-host
/:loc/:sublocation("-host") - should match /usa/washington-host
how to achieve this using single named route in vue.js
You can use alias of path
const router = new VueRouter({
routes: [
{ path: '/a', component: A, alias: '/b' }
]
})
Check in doc
const Home = { template: '<div>Home</div>' }
const Project = {
template: '<div>Project {{id}}</div>',
mounted(){
console.log(this.$route);
},
data: function () {
return {
id:this.$route.params.id||'',
}
}
}
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/',
component: Home
},
{
path: '/projects/:id?',
component: Project,
alias: '/project/:id'
}
]
})
new Vue({
router,
el: '#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">
<router-link to="/">Home</router-link> |
<router-link to="/projects">projects</router-link> |
<router-link to="/project/1">project/1</router-link>
<router-view></router-view>
</div>
Also check fiddle : https://jsfiddle.net/nikleshraut/9sgk6yg4/1/
Note : Opening same component is not working by default, you need to use other trick. For just testing above fiddle, go home->/projects and home->/project/1 will work but /projects->/project/1 or /project/1->/projects will not work. To make it work do something like this : https://jsfiddle.net/nikleshraut/9sgk6yg4/
This is my solution.
Router:
Use ? to separate param from literal in route.
const router = new VueRouter({
routes: [
{ path: '/', component: Home },
{ path: '/:loc/:subloc?-host', component: Location },
{ path: '/:loc?-host', component: Location },
]
})
Component:
Set local variables from $route.params.
const Location = {
template: '<div>Location {{loc}} - {{ subloc }}</div>',
data: function () {
return {
loc: this.$route.params.loc,
subloc: this.$route.params.subloc,
}
},
}
Template:
Use :key="$route.fullPath" to ensure component re-creates each navigation.
<div id="app">
<router-link to="/">Home</router-link> |
<router-link to="/usa-host" >loc1</router-link> |
<router-link to="/usa/washington-host" >loc2</router-link>
<router-view :key="$route.fullPath"></router-view>
</div>
Fiddle here
Related
How can I naviagte to the current route using router-link and re-run mounted hook?
HTML
<!-- Include the library in the page -->
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/vue-router"></script>
<!-- App -->
<div id="app">
<nav>
<router-link :to="{ name: 'home' }" exact>Home</router-link>
<router-link :to="{ name: 'about' }" #click.native.prevent="router.push({ name: 'about' })">About</router-link>
</nav>
<router-view :key="$route.fullPath"></router-view>
</div>
JS
console.clear()
console.log('Yes! We are using Vue version', Vue.version)
Vue.use(VueRouter)
const Home = {
template: `<h1>Home</h1>`,
}
const About = {
template: `<h1>{{new Date()}}</h1>`,
mounted(){
console.log('mounted')
}
}
const routes = [
{ path: '/', name: 'home', component: Home },
{ path: '/about', name: 'about', component: About },
]
const router = new VueRouter({
routes,
})
// New VueJS instance
var app = new Vue({
// CSS selector of the root DOM element
el: '#app',
// Inject the router into the app
router,
})
In the above example, if I navigate to 'About' it shows the timestamp from new Date and logs 'mounted'. However, if I'm already on /about, clicking the about link does nothing. I want to re-run the whole component lifecycle when clicking 'About', even if I'm already hit it.
You'll need to change the key in the <router-view> element whenever the user clicks your about page, that will force the mounted hook:
<template>
<div id="app">
<router-link #click.native="updateViewKey" :to="{ name: 'about' }">About</router-link>
<router-view :key="viewKey"></router-view>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
viewKey: 1
};
},
methods: {
updateViewKey() {
this.viewKey+=1;
}
}
};
</script>
Try this :
router.push({
name: 'routeName',
params: {
id: 'new value'
}
})
I'm new using VUE and I was testing a simple vue-router but props are not working in this test.
Here the test on jsfiddle
<div id="app">Menu:
<router-link to="/">Home</router-link> |
<router-link to="/post">Post</router-link> |
<router-link to="/foo">Foo link comment</router-link>
<router-view></router-view>
</div>
const Home = { template: '<div class="page">Welcome to my Home <router-link :to="{name:\'foo\'}">this link</router-link></div>' }
const Foo = {
props:['comment', 'msg'],
template: '<div class="page">{{msg}} Here the comment:<hr><div v-html="comment"></div><hr>Go back to <router-link :to="{name:\'home\'}">home</router-link></div>' }
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/', name:'home',component: Home },
{ path: '/foo', name:'foo', component: Foo }],
})
new Vue({
router,
el: '#app',
data: {
msg: 'Hello World',
comment : '<div class="comment">This is a <strong>bold</strong> link</div>'
}
})
And how to pass the router link in prop HTML code?
You need to add props property in routes attribute
{ path: '/foo', name:'foo', component: Foo , props: true}
Also you need to pass prop value in router-link
<router-link :to="{ name: 'foo',
params: { comment: comment,msg: msg }}">Foo link comment</router-link>
How can I pass an image as prop in a vue-router tag ?
I have :
<router-link :to="{path: '/details', query: {
name: 'item',
//...
}}">
</routerlink
while in my "details" component I have :
<template>
<img :src="url">
</template>
<script>
export default {
name:'child-img',
props:['url'],
data() {
return {
}
}
}
</script>
So it's a case of passing props to your route which you have to set up in your router.
const router = new VueRouter({
routes: [
{ path: '/details/:url', component: Details, props: true },
// ...
]
})
then when you use your route:
<router-link to="`/details/${url}`">Details</router-link>
In the above url is the dynamic element you would be passing to it. If it comes from a v-for loop it would be item.url or whatever you are v-for ing.
OR if you name your route you can pass a param like this:
const router = new VueRouter({
routes: [
{ path: '/details/:url', name: 'Details', component: Details, props: true },
// ...
]
})
then use it like this:
<router-link :to="{ name: 'Details', params: { url } }">
Details
</router-link>
You can read more here
I am using Vue.js 2.0, and I have this exact same code in 2 differents files, so I decided to build only one component and redirect the 2 routes on it, then I just need to pass the ID to the route, this way my 2 components can display differents resultats.
Note: the only thing that changes is the ID dsgh151rhj12t1j5j I would like that each route can send it own ID to my PageContentfulView component
EDIT: I just want to pass data from Route to the component
<template>
<div>
<div class="container">
<hp-row>
<hp-column>
<component v-for="component in content.column" :data="component" :key="component.id" :is="getComponentIdentifier(component.is)"></component>
</hp-column>
</hp-row>
</div>
</div>
</template>
<script>
import ModularView from '#/views/ModularView'
export default {
name: 'PageContentfulView',
mixins: [ModularView],
created () {
this.fetch('blocks/dsgh151rhj12t1j5j')
},
}
</script>
Routes:
{
path: '/satisfaction-guarantee',
name: 'SatisfactionView',
component: load('PageContentfulView'),
},
{
path: '/about-us',
name: 'AboutUsView',
component: load('PageContentfulView'),
},
'props' can solve your problem.
<template>
<div>
<div class="container">
<hp-row>
<hp-column>
<component v-for="component in content.column" :data="component" :key="component.id" :is="getComponentIdentifier(component.is)"></component>
</hp-column>
</hp-row>
</div>
</div>
</template>
<script>
import ModularView from '#/views/ModularView'
export default {
name: 'PageContentfulView',
mixins: [ModularView],
props: ['id'],
created () {
this.fetch('blocks/' + this.id)
},
}
</script>
route
{
path: '/satisfaction-guarantee',
name: 'SatisfactionView',
component: load('PageContentfulView'),
props: { id: 'dsgh151rhj12t1j5j' },
},
{
path: '/about-us',
name: 'AboutUsView',
component: load('PageContentfulView'),
props: { id: 'blablablabla' },
},
You can do it using Dynamic Route Matching. You just need to include the parameter on the definition of the route, like below:
{
path: '/satisfaction-guarantee/:ID',
name: 'SatisfactionView',
component: load('PageContentfulView'),
}
Inside you component, to access the ID, you just need to use the this.$route.params.ID.
Passing props to route component allows an object mode.
Example from the documentation:
const router = new VueRouter({
routes: [
{ path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }
]
})
Route meta fields
Also you always can use the meta property to pass extra data (like a requireAuth flag)
const router = new VueRouter({
routes: [
{ path: '/test', component: TestComponent, meta: { someBoolean: false } }
]
})
And you can access it within your component
created() {
let meta = this.$route.meta;
}
Set the props in your route to true and place /:id at the end of your path
const router = new VueRouter({
routes: [
{ path: '/promotion/from-newsletter/:id',
component: Promotion,
props: true
}
]
})
You can now extract the param id of your route from the props in the corresponding component
<template>
<div>
<div class="container">
<hp-row>
<hp-column>
<component v-for="component in content.column" :data="component" :key="component.id" :is="getComponentIdentifier(component.is)"></component>
</hp-column>
</hp-row>
</div>
</div>
</template>
<script>
import ModularView from '#/views/ModularView'
export default {
name: 'PageContentfulView',
mixins: [ModularView],
props: ['id'],
created () {
this.fetch('blocks/'+id)
},
}
</script>
I have the following router config:
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'notselected',
component: PackageUnselected
},
{
path: '/package/:id',
children: [
{ path: 'meta', name: 'packageMeta', component: ViewPackageMeta },
{ path: 'readme', name: 'packageReadme', component: PackageReadme },
{ path: 'docs', name: 'packageDocs', component: PackageDocs },
{
path: 'playground',
name: 'packagePlayground',
component: PackagePlayground
}
]
},
{
path: '/about',
name: 'about',
component: About
},
{
path: '*',
redirect: '/'
}
]
});
And when I'm at the root route it correctly identifies the route name as notselected. When I route to any of the "/package/[id]" routes though it continues to load the PackageUnselected component instead of the appropriate route (aka, ViewPackageMeta, PackageDocs, etc.).
Now at the point in the DOM where I want the route to insert the route's component I have the following template:
<v-tab-item v-for="item in tabs" :id="'tab-item-' + item" :key="item" exact>
item: {{item}}
<router-view :selectedPackage="selected"></router-view>
</v-tab-item>
And because I have installed vuex-router-sync it's easy to see the route state at any given time. So when clicking on the route that should load PackageDocs:
But the component view window of vue-devtools looks like this:
the highlighted area shows that NO component has been loaded into the tabs. I then tried adding a component to the definition of the parent route /package/:id:
{
path: '/package/:id',
component: Packages,
children: [
{ path: 'meta', name: 'packageMeta', component: ViewPackageMeta },
{ path: 'readme', name: 'packageReadme', component: PackageReadme },
{ path: 'docs', name: 'packageDocs', component: PackageDocs },
{
path: 'playground',
name: 'packagePlayground',
component: PackagePlayground
}
]
},
I then had to create the world simplest component for Packages:
<template>
<view-router-view></view-router-view>
</template>
This results in the following:
Hmmm. Can't figure out what to do next. Anyone have any pointers?
When I route to any of the "/package/[id]" routes though it continues
to load the PackageUnselected component instead of the appropriate
route (aka, ViewPackageMeta, PackageDocs, etc.).
That is the correct behavior of the vue-router.
Children can only be loaded when URL paths are:
/package/[id]/meta
/package/[id]/readme
/package/[id]/playground
/package/[id]/docs
Parent path may not have component defined if you have configured redirect option and your user, who opens /package/[id] will be redirected to your default path (could be anything).
Lets move to the next part of your question...
<v-tab-item v-for="item in tabs" :id="'tab-item-' + item" :key="item" exact>
item: {{item}}
<router-view :selectedPackage="selected"></router-view>
</v-tab-item>
You don't need to create here 4 different <router-view> tags, you just need one where all your children components will display html code.
<v-tab-item v-for="item in tabs" :id="'tab-item-' + item" :key="item" exact></v-tab-item>
<router-view></router-view>
Now you will have only one router-view and it's the default one. When user clicks on any of your tabs you just need to this.$router.push a new path on #click-event in Packages component. That's it.
I have created a simple example (codepen) to demonstrate how this task can be solved:
Vue.use(VueRouter);
// Components
let MetaPackages = {
mounted() { console.log('Mounted MetaPackages...'); },
template: `<div>MetaPackages...</div>`,
};
let DocsPackages = {
mounted() { console.log('Mounted DocsPackages...'); },
template: `<div>DocsPackages...</div>`,
};
let ReadmePackages = {
mounted() { console.log('Mounted ReadmePackages...'); },
template: `<div>ReadmePackages...</div>`,
};
let Packages = {
mounted() { console.log('Mounted Packages... ' + this.$route.path); },
template: '<div>Packages (parent) screen...<br/><router-view></router-view></div>',
};
// Router
const router = new VueRouter({
mode: 'hash',
routes: [
{
path: "/packages/:id",
component: Packages,
children: [
{path:"meta", component: MetaPackages},
{path:"docs", component: DocsPackages},
{path:"readme", component: ReadmePackages}
]
}
]
});
// Vue instance
const vm = new Vue({
el: '#app',
router,
components: {Packages, MetaPackages, DocsPackages, ReadmePackages}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.2/vue-router.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<router-link to="/packages/100/meta">Meta</router-link>
<router-link to="/packages/100/docs">Docs</router-link>
<router-link to="/packages/100/readme">Readme</router-link>
<hr/>
<router-view></router-view>
</div>