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
Related
I want to have a couple of "overview" pages for sections my app, that will all be triggered on the root of that section.
so localhost/hi should display component HiOverview
localhost/he should display component HeOverview
as there are multiple of those, i want to avoid assigning the component to a const, then reusing it in a route. instead i want to handle all that in a single dynamic route.
BUT i'm struggling with the creation of the Components in the beforeEnter hook.
each route object expects a component... but i just want to decide the component depending on route. (sectionsWithOverview is a simple array of strings containing the names of routes where i want an overview displayed
const router = new Router({
linkActiveClass: 'active',
mode: 'history',
routes: [
{ path: '/:section',
component: Placeholder,
beforeEnter: (to, from, next) => {
const section = to.params.section
// how can i use this in the next() call?
// const View = () => import(/* webpackChunkName: 'sectionView' */ `Components/${section}/${section}Overview`)
if (sectionsWithOverview.includes(to.params.section)) {
next({ name: `${to.params.section}Overview` })
} else {
next()
}
},
}
can you guys help me? how can i conditionally assign a component onBeforeEnter, and then route to that exact Component?
it works if i declare each SectionOverview beforehand, but that makes my whole idea pointless.
Thanks for any help :)
I made something similar with a project but instead I used beforeRouteUpdate
Here is an example of how it works. On route.js simply define your dynamic route
const router = new Router({
linkActiveClass: 'active',
mode: 'history',
routes: [
{
path: '/:section',
component: Placeholder,
name: 'placeholder'
},
}
Then in your component (I assume Placeholder.vue) in your HTML add this line of code
<transition name="fade" mode="out-in">
<component :is="section" key="section"></component>
</transition>
then in your JS add the beforeRouteUpdate hook and define all your components that will match your route section param.
import he from './heOverview.vue'
import hi from './hiOverview.vue'
beforeRouteUpdate (to, from, next) {
// just use `this`
this.section = to.params.section
next()
},
components: {
he,
hi
},
data () {
return {
section: ''
}
}
So when a user navigate to localhost/he the heOverview.vue component will be loaded. The only thing you have to make sure is that the section param's value should match an specific view if not an error will be produced
If you need more info about how this work, read
https://v2.vuejs.org/v2/guide/components-dynamic-async.html
https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards
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.
I am developing vue app and now I am on step when I should use vue router.
But I have a little problem with data bind into router template.
Please help me.
HTML:
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<router-view></router-view>
</div>
Script:
const Foo = { template: '<div>{{foo}}</div>' }
const Bar = { template: '<div>bar</div>' }
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
const router = new VueRouter({
routes
})
const app = new Vue({
el: '#app',
router,
data: function(){
return {foo: "asdasdas"}
}
})
{{foo}} bind doesn't work.
Live example:
https://jsfiddle.net/xgrjzsup/4430/
From the guide on components :
Every component instance has its own isolated scope. This means 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.
and Foo is a child component of your app set via the router.
One way to pass data from parent to child is to use props.
Modify your Foo definition to accept a foo property:
const Foo = {
props: ['foo'],
template: '<div>{{foo}}</div>'
}
and bind the parent property in the template
<router-view :foo="foo"></router-view>
An updated Fiddle : https://jsfiddle.net/xgrjzsup/4431/
in your case there are two ways you can access that "foo" var.
{{$parent.foo}}
{{$root.foo}}
But consider using Vuex for sharing data in your application - https://github.com/vuejs/vuex
Or pass that foo as a parameter to the route -https://router.vuejs.org/en/essentials/passing-props.html
Ofc it does not work. you have to set the data on the template you use.
in your case:
const Foo = {
template: '<div>{{foo}}</div>',
data () {
return {
foo: 'magic'
}
}
}
Cheers and happy coding.
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.
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.