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.
Related
I'm having trouble understanding how to get a computed property all the way out through the router to my template. Here's a basic idea of what I'm doing:
const Home = {
template: '<router-link to="/level/1">Level 1</router-link>'
}
const Level = {
template: '<template>|{{ id }}|{{ message }}|</template>',
props: ['id','message']
}
const router = new VueRouter({
routes: [
{ path: '/', component: Home, props: true },
{ path: '/level/:id', component: Level, props: true }
]
})
const vm = new Vue({
el: '#app',
router,
template: '<router-view></router-view>',
computed: {
message() {
return 'HELLO';
}
}
})
When I click the "Level 1" link, the result I expect to see is:
|1|HELLO|
The result I actually see is:
|1||
The final usage will be a bit more functional than this, but hopefully that's enough to expose whatever it is that I'm not understanding about props, or routing, or computed properties.
There are 2 issues:
1) There's an error:
Cannot use <template> as component root element because it may contain multiple nodes.
So change that to a div. When using the Vue CLI, templates are wrapped in <template> but there still needs to be a different root element inside of it.
2) The Level component has a prop called message but it isn't passed. The Home route passes id but not message. Home can't pass message at the moment, because it's in the root component, and Home didn't receive it.
You could:
Use Vuex to solve this most cleanly
Define message in Home instead of the root and pass it to Level
Pass the message from root to Home and then again from Home to Level
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've am new at Vue and i've got a problem with unaccessible. I've got two files.
1st is App.vue where is defined <router-view>
<script>
export default {
name: 'app',
data(){
return{
info: false,
}
},
beforeMount(){
example...
this.info= true
this.$router.push('/main'); //where in router-view visible is component Main.vue
}
}
</script>
2nd is component Main.vue which is clear:
<script>
export default{
name: 'main',
data(){
return{
}
},
beforeMount(){
//what i want to do:
console.log(App.data().info) //here should be visible true in console log
}
}
i would like to have accessible in 2nd file the property from file number one. How to do it properly? Thank you in advance
Two options that i can think of :
Passing Props to Route Components
Source : link
In your router :
import main from './main.vue'
const router = new VueRouter({
routes: [
{ path: '/main/:id', component: main }
]
})
In your Main.vue
Access to the variable : this.$route.params.id
Save the data in state manager and get access to him through the state in another component Vuex
Every component instance has its own isolated scope. As stated here: https://v2.vuejs.org/v2/guide/components.html#Passing-Data-with-Props
you cannot (and should not) directly reference parent data in a child component’s template. Data can be passed down to child components using props.
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 })
It's my first post on stackoverflow, so sorry in advance if I do something incorrectly. My question;
I've setup a VueJS project, and I'm trying to reach data that I put in the App.vue from another component. To do this, I use this.$root.count for example, but it returns undefined.
Main.js:
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App'
Vue.use(VueRouter);
const router = new VueRouter({
mode: 'history',
routes: [{
path: '/',
name: 'home',
component: function (resolve) {
require(['./components/Hello.vue'], resolve)
}
}, {
path: '/race-pilot',
name: 'racePilot',
component: function (resolve) {
require(['./components/RacePilot.vue'], resolve)
}
}
});
new Vue({
el: '#app',
router,
template: '<App/>',
components: { App }
});
App.vue:
<template>
<div>
<div class="menu" ref="menu">
<router-link :to="{ name: 'home' }">Home</router-link>
<router-link :to="{ name: 'racePilot' }">Race Pilot</router-link>
</div>
<div id="app">
<router-view></router-view>
</div>
</div>
</template>
<style src="./assets/css/app.scss" lang="scss"></style>
<script>
import Hello from './components/Hello'
export default {
name: 'app',
components: {
Hello
},
data () {
return {
count: '0'
}
}
}
</script>
RacePilot.vue:
<template>
<div class="race-pilot">
</div>
</template>
<script>
export default {
name: 'RacePilot',
mounted() {
console.log(this.$root.count);
}
}
</script>
So the last log returns undefined. However, if I log this.$root, I do get the object. Anybody any idea? Thanks in advance!
Vuex is fine and all, but if you just want to expose a property to all of your views in a router based app, you can set it on the router-view.
<router-view :count="count"></router-view>
Then your view component just needs to accept it as a prop.
export default {
props:["count"],
name: 'RacePilot',
mounted() {
console.log(this.count);
}
}
this.$root references the top level Vue instance (new Vue...) and not the App VueComponent.
it is really hacky, other solutions are preferable, but this could work:
new Vue({
el: '#app',
router,
template: '<App/>',
components: { App },
methods: {
getCount() {
return this.$children[0].count
}
},
});
and using getCount() in RacePilot.vue:
export default {
name: 'RacePilot',
mounted() {
console.log(this.$root.getCount());
}
}
You are trying to access data which is stored in App.vue but this data will be local to the component and not accessible globally.
App.vue is not the root instance (referred to by $root), instead it is the first component within the root instance which is actually created at main.js. It is during this creation time, you need to pass the data which will then be exposed for all child components via $root.
Here is the relevant portion of main.js, modified accordingly :-
new Vue({
el: '#app',
data: { count: 0 },
router,
template: '<App/>',
components: { App }
});
Tip : To confirm that App.vue is indeed the first child of root instance, try comparing the references of this.$root with this.$parent. It should returntrue which means that root instance is the parent of App.vue.
References :-
https://v2.vuejs.org/v2/guide/instance.html
https://v2.vuejs.org/v2/api/#vm-root
https://v2.vuejs.org/v2/guide/components-edge-cases.html#Accessing-the-Root-Instance
It should had worked as it is, as it is working here.
However a better way to manage global variables, which are available across components should be solved by state machine. Vue has Vuex for that purpose as stated here.
You should not do it like that.
Definitely you should not try to access other components like that.
To share data between components you can either use props (one-way binding) or Vuex to make data accessible and editable from all components through store.
You can use global $store or $router if you will start your Vue app this way:
new Vue({
el: '#q-app',
router,
store
render: h => h(require('./App'))
})
Then you can access store (for state change or access state (do not mutate state this way)) - this.$store.state.yourStaneName
You can also make the App component the actual root by passing the component directly to the Vue instance, which would look something like this:
new Vue(App).$mount('#app')
You'll probably have to move the router to App.vue, but this will make sure that this.$root will resolve to your App component directly.