Vue Router. Bind data - javascript

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.

Related

Vue computed property in router template

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

How to pass data to vue router router-view?

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.

Vue2.0 unaccessible variable

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.

Can't access root data in VueJS

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.

vue.js - Organize big single page application with multiple views

I'm playing with new MVVM framework - Vue.js (http://vuejs.org/).
It was really nice in simple examples and demos but now I'm trying to create big SPA with multiple views and I'm realizing that the best pattern how to do it is not described in framework's docs.
The main problem is that I don't know how to handle views on different routes.
For example, I'm using Director (https://github.com/flatiron/director) for routing but how can I change views?
var booksCtrl = function () {
var booksViewModel = new Vue({
el: '#books'
data: { ... }
ready: function () {
// hide previous ViewModel and display this one??
}
});
};
var editBookCtrl = function (id) {
var editBookViewModel = new Vue({
el: '#editBook'
data: { ... }
ready: function () {
// hide previous ViewModel and display this one??
}
});
};
var routes = {
'/books': booksCtrl,
'/books/:id/edit': editBookCtrl
};
var router = new Router(routes);
router.init();
Do I need to create separate Vue.js ViewModels and just display:block / display:none them like in this example?
What would be the right way in your opinion? Thanks!
Nested subviews can be resolved by using v-view and v-ref.
html
<div id="main">
<div v-view="currentView" v-ref="view"></div>
</div>
<ul>
<li>top</li>
<li>nest/view1</li>
<li>nest/view2</li>
</ul>
<script id="top" type="x-template">
<div>top view</div>
</script>
<script id="nest" type="x-template">
<div>
<span>nest view</span>
<div v-view="subview"></div>
</div>
</script>
javascript
Vue.component('top', Vue.extend({
template: "#top",
}));
Vue.component('nest', Vue.extend({
template: '#nest',
components: {
view1: Vue.extend({
template: '<span>this is subview 1</span>',
}),
view2: Vue.extend({
template: '<span>this is subview 2</span>',
}),
},
data: {
subview: "view1",
},
}));
var main = new Vue({
el: "#main",
data: {
currentView: "top",
},
});
var router = new Router({
'/': function() { main.currentView = 'top' },
'/nest/:view': function(view) {
main.currentView = 'nest';
main.$.view.subview = view;
},
});
router.init();
jsfiddle: http://jsfiddle.net/koba04/WgSK9/1/
The officially recommended way to use routing in vuejs applications is to use vue-router :
Quoting from the documentation :
vue-router is the official router for Vue.js. It
deeply integrates with Vue.js core to make building Single Page
Applications with Vue.js a breeze. Features include:
Nested route/view mapping
Modular, component-based router configuration
Route params, query, wildcards
View transition effects powered by Vue.js' transition system
Fine-grained navigation control
Links with automatic active CSS classes
HTML5 history mode or hash mode, with auto-fallback in IE9
Restore scroll position when going back in history mode
The well-written documentation elaborates further on Modular, component-based router configuration, including examples on handling nested routes.
A router-view outlet is made available into which the route configuration can specify which component to render. These components can contain embedded router-view outlets allowing component oriented nested route management.
Example from the docs:
<div id="app">
<router-view></router-view>
</div>
router.map({
'/foo': {
component: Foo,
// add a subRoutes map under /foo
subRoutes: {
'/bar': {
// Bar will be rendered inside Foo's <router-view>
// when /foo/bar is matched
component: Bar
},
'/baz': {
// Same for Baz, but only when /foo/baz is matched
component: Baz
}
}
}
})
You might be able to use v-view and component?
http://vuejs.org/guide/application.html
like this.
javascript
Vue.component('top', Vue.extend({
template: "<div>top view</div>",
}));
Vue.component('other', Vue.extend({
template: "<div>other view</div>",
}));
var main = new Vue({
el: "#main",
data: {
currentView: "top",
},
});
var router = new Router({
'/': function() { main.currentView = 'top' },
'/other': function() { main.currentView = 'other' },
});
router.init();
html
<div id="main">
<div v-view="currentView"></div>
</div>
You could use Named Views if you don't want to nest them.
html
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
javascript
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const Baz = { template: '<div>baz</div>' }
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/',
// a single route can define multiple named components
// which will be rendered into <router-view>s with corresponding names.
components: {
default: Foo,
a: Bar,
b: Baz
}
},
{
path: '/other',
components: {
default: Baz,
a: Bar,
b: Foo
}
}
]
})
jsfiddle: https://jsfiddle.net/posva/6du90epg/
The fiddle is from the doc: https://router.vuejs.org/en/essentials/named-views.html

Categories