I have a ProjectCard component which, among other things, links to a specific ProjectPage component. The ProjectPage is going to have a bunch of different paragraphs, pictures and so on, not wholly relevant for my question.
How do I pass on props to a ProjectPage? The Vue Docs portion on Boolean Mode is incredibly vague and doesn't really tell me anything useful.
My Router index.js file has the prop decoupling that they mention in the docs
import ProjectPage from "#/views/ProjectPage.vue"
const routes = [
{
path: "projects/:id",
component: ProjectPage,
props: true
}
To test things out, I made the ProjectPage.vue component look like this
<template>
<div>Static text, followed by {{ testString }}</div>
</template>
<script>
export default {
name: "ProjectPage",
props: {
testString: String
}
};
</script>
And I tried passing on a test string to it from my ProjectCard component like this:
<template>
<router-link class="project-link" :to="{ path: `projects/${url}`, params: { testString: 'a dynamic string' } }" exact>
</template>
<script>
export default {
name: "ProjectCard",
props: {
url: String
}
};
</script>
This will correctly take me to the specified route, eg projects/table. However, the {{ testString }} doesn't render and I can only see the Static text, followed by a portion of the component. There's no errors or warnings in the console.
Checking a ProjectCard component in the Vue debugger, the testString exists nested under to/params/testString:
However, on any of the ProjectPage components, testString is undefined
What am I doing wrong here?
what about this
import ProjectPage from "#/views/ProjectPage.vue"
const routes = [
{
name: 'Project',
path: "projects/:id",
component: ProjectPage,
props: true
}
and
<template>
<router-link class="project-link" :to="{ name: `Project`, params: { testString: 'a dynamic string' ,id: url} }" exact>
</template>
As the docs said
params are ignored if a path is provided, which is not the case for query, as shown in the example above.
const userId = '123'
router.push({ name: 'user', params: { userId } }) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// This will NOT work
router.push({ path: '/user', params: { userId } }) // -> /user
The same rules apply for the to property of the router-link component.
Related
I'm creating a blog using Vuejs and I'm fairly new to it.
In short. I have a dynamic list of elements that are loaded onto the screen and when you click on one of the items, I want to go to that page with the rest of the data. I followed somewhat of the same process I did if I was using React.
Router.js
export default new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
name: "Home",
component: Home
},
{
path: "/post/:id",
name: "PostView",
props: true,
component: PostView
}
]
});
I have my router setup to take dynamic links.
Component That Creates List Data
<template>
<router-link v-bind:to="{ path: 'post/' + post.postId, params: { post } }">
<div> .... </div>
</router-link>
</template>
<script>
import moment from "moment";
export default {
name: "recentPostTile",
props: {
post: Object,
},
};
</script>
As you can see that is how I did my router-link and in my actual Page View this is how I'm trying to read the data. 2 different way's I tried to read it.
props: {
post: Object
},
AND
data() {
return {
postData: this.$route.params.post, (also tried with $route)
};
},
and when I try to console out post/postData I just get undefined. I can assure you that the data does exist since the data is hard coded into the browser.
Also I tried to pass the params as key value pairs as well and that didn't work. I also create a new variable for the data I was going to be passing through the link. That didn't work either. I also haven't tired query, just because I don't want an ugly looking link.
Change your link to:
<router-link :to="{ name: 'PostView', params: { id: post.postId, postData: post } }">
<div> .... </div>
</router-link>
The changes:
Used the name property to specify the route
Removed the hardcoded path
Passed the id param, as that is the param name given in the route definition (/:id)
I'm sure this information is out there somewhere, but I've been Googling all afternoon and haven't been able phrase my question in a way that gets me the understanding I need. I want to write a method in my Vue instance and use it in a template that I display using routing. Here's some partial code:
const Home = { template:
'<div class="container">' +
'I\'m leaving some stuff out, but routing works fine in the real code' +
'</div>'
};
const Level = { template:
'<div class="container">' +
'<h2>Level {{ id }}</h2>' +
'{{ say_hello }}' +
'</div>',
props: ['id','say_hello']
}
// === Define our routes ===
const router = new VueRouter({
routes: [
{ path: '/', component: Home, props: true },
{ path: '/level/:id', component: Level, props: true }
]
})
// === Now fire up Vue and display it on screen ===
const vm = new Vue({
el: '#app',
router,
template: '<router-view></router-view><p><router-link to="/level/1">Level 1</router-link></p>',
methods: {
say_hello: function() {
return 'hello';
}
}
})
I realize that's a little bit of a mess, but in the full code it all works EXCEPT that my '{{ say_hello }}' never works, no matter what I try. I basically always get some variety of "is undefined" or "is not a function" error message. My guess is that the method is not making it past the router for whatever reason, but I haven't been able to figure out what to fix to make it work.
Thanks for your help!
EDIT: I just realized that this is basically a variation of a question I asked a couple of weeks ago, which I never really got an answer to that helped me figure out the problem (several answers, but none that clicked for me). I wound up sidestepping the issue using globals last time. I'd really like to figure out how this actually works instead! Previous question: Vue computed property in router template
You can get vue-router to pass any params offered into component props using props: true.
This way, you can construct your <router-link> elements with any extra data you want. All you have to do is pass in params. This is best facilitated by using a named route, eg
<router-link :to="{ name: 'Level', params: { id: 1, say_hello: 'whatever' } }">
For example
const Home = { template:
`<div class="container">
I'm leaving some stuff out, but routing works fine in the real code
</div>`
};
const Level = { template:
`<div class="container">
<h2>Level {{ id }}</h2>
{{ say_hello }}
</div>`,
props: {
id: [String, Number],
say_hello: {
default: 'Nobody said hello 😦'
}
}
}
// === Define our routes ===
const router = new VueRouter({
routes: [
{ path: '/', name: 'Home', component: Home, props: true },
{ path: '/level/:id', name: 'Level', component: Level, props: true }
]
})
// === Now fire up Vue and display it on screen ===
const vm = new Vue({
el: '#app',
router,
data: () => ({
say_hello: 'hello'
})
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<router-view></router-view>
<p>
<router-link :to="{ name: 'Level', params: { id: 1, say_hello } }">Level 1</router-link>
</p>
<pre>$route.fullPath = {{ $route.fullPath }}</pre>
</div>
Im using Vue Router. In my code I used to have:
<div v-bind:is="page.component_name" v-bind:page="page"></div>
Which worked, and the page data was passed to the component. But how do I do the same with a router-view? This doesn't seem to work:
<router-view v-bind:page="page"></router-view>
js:
var vm = new Vue({
...,
router : new VueRouter({
routes : [
{ path: '/foo', component: { template: '<div>foo</div>', created:function(){alert(1);} } },
//{ path: '/bar', component: { template: '<div>bar</div>', created:function(){alert(2);} } },
{ path: '/bar', component: Vue.component("ti-page-report") }
]
}),
...
});
vue-router has a dedicated page in docs on how to pass props to router-view.
Passing Props to Route Components
Example snippet from docs:
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User, props: true },
// for routes with named views, you have to define the `props` option for each named view:
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
})
If you are looking for simplified usage, props can still be passed the same way they are passed to any component. But component that is used for rendering the route (the one that is specified in route definition) should expect to receive the props.
Here is simple usage example of passing props to router-view:
I personally decided to use provide/inject feature: preserving reactivity with minimal overhead.
The component ("ti-page-report") that needs to access the props being sent just needs to add it:
<template>
<div>
<h1>Now you can access page: {{ page }}</h1>
</div>
</template>
export default {
name: "TiPageReport",
props: ['page'], // can now be accessed with this.page
...
};
See https://v2.vuejs.org/v2/guide/components-props.html for how to use props properly.
Suppose I have a Vue.js component like this:
var Bar = Vue.extend({
props: ['my-props'],
template: '<p>This is bar!</p>'
});
And I want to use it when some route in vue-router is matched like this:
router.map({
'/bar': {
component: Bar
}
});
Normally in order to pass 'myProps' to the component I would do something like this:
Vue.component('my-bar', Bar);
and in the html:
<my-bar my-props="hello!"></my-bar>
In this case, the router is drawing automatically the component in the router-view element when the route is matched.
My question is, in this case, how can I pass the the props to the component?
<router-view :some-value-to-pass="localValue"></router-view>
and in your components just add prop:
props: {
someValueToPass: String
},
vue-router will match prop in component
sadly non of the prev solutions actually answers the question so here is a one from quora
basically the part that docs doesn't explain well is
When props is set to true, the route.params will be set as the component props.
so what you actually need when sending the prop through the route is to assign it to the params key ex
this.$router.push({
name: 'Home',
params: {
theme: 'dark'
}
})
so the full example would be
// component
const User = {
props: ['test'],
template: '<div>User {{ test }}</div>'
}
// router
new VueRouter({
routes: [
{
path: '/user',
component: User,
name: 'user',
props: true
}
]
})
// usage
this.$router.push({
name: 'user',
params: {
test: 'hello there' // or anything you want
}
})
In the router,
const router = new VueRouter({
routes: [
{ path: 'YOUR__PATH', component: Bar, props: { authorName: 'Robert' } }
]
})
And inside the <Bar /> component,
var Bar = Vue.extend({
props: ['authorName'],
template: '<p>Hey, {{ authorName }}</p>'
});
This question is old, so I'm not sure if Function mode existed at the time the question was asked, but it can be used to pass only the correct props. It is only called on route changes, but all the Vue reactivity rules apply with whatever you pass if it is reactive data already.
// Router config:
components: {
default: Component0,
named1: Component1
},
props: {
default: (route) => {
// <router-view :prop1="$store.importantCollection"/>
return {
prop1: store.importantCollection
}
},
named1: function(route) {
// <router-view :anotherProp="$store.otherData"/>
return {
anotherProp: store.otherData
}
},
}
Note that this only works if your prop function is scoped so it can see the data you want to pass. The route argument provides no references to the Vue instance, Vuex, or VueRouter. Also, the named1 example demonstrates that this is not bound to any instance either. This appears to be by design, so the state is only defined by the URL. Because of these issues, it could be better to use named views that receive the correct props in the markup and let the router toggle them.
// Router config:
components:
{
default: Component0,
named1: Component1
}
<!-- Markup -->
<router-view name="default" :prop1="$store.importantCollection"/>
<router-view name="named1" :anotherProp="$store.otherData"/>
With this approach, your markup declares the intent of which views are possible and sets them up, but the router decides which ones to activate.
const User = {
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User, props: true }
// for routes with named views, you have to define the props option for each named view:
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
})
Object mode
const router = new VueRouter({
routes: [
{ path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }
]
})
That is the official answer.
link
Use:
this.$route.MY_PROP
to get a route prop
I'm using VueJS 2.3.3 and coffescript and I'm trying to pass a prop to a component from the router, but I'm having no success. Code is not mine, so I'm having some trouble figuring out what am I doing wrong. Here's my router:
App = require './views/App'
Shared = {
header: require('./views/shared/header'),
global_loader: require('./views/shared/global_loader.vue')
}
view = (view_name) ->
require("./views/#{view_name}")
componentize = (view_name, options = {}) ->
options.include_header ?= true
component = options.component || {}
component.app ?= view(view_name)
component.header = Shared.header if options.include_header
component
exports.routes = [
{
path: '/',
component: App
children: [
{
path: '/component',
components: componentize('path/to/component'),
props: { has_groups: true }
},
...
]
}
...
}
Here's my App.vue code:
<template lang="pug">
#app-wrapper
transition(name="fade")
router-view(name="global_loader")
#header-wrapper
router-view(name="header")
#current-view-wrapper.container
transition(name="enter")
router-view(name="app")
</template>
On my component, I'm receiving the prop as usual:
props:
has_groups:
default: false
Everything works fine, except that has_groups doesn't receive the correct prop value from the router. It doesn't change to true.
Can anyone help me finding out what I'm missing?
I found the solution. As I'm using named routes, I have to configure the props like:
props:
global_loader: false
header: false
app: (route) -> ({ has_groups: true })