Proper way to use "props" in VueJS - javascript

I'm creating a new project using VueJS as first time, and trying to use a toolbar on all of my pages. But I want to make the title present in the toolbar, dynamic.
I tried to use props, but I must be wrong the way I use it. Check the example below :
In my index.html :
<div id="app" v-cloak>
<v-app>
<spa-toolbar :title="title"></spa-toolbar>
<router-view></router-view>
</v-app>
</div>
<script>
Vue.use(VueRouter);
Vue.use(VeeValidate);
Vue.config.devtools = true;
const routes = [
{
path: '/',
component: spaLogin,
props: {title: 'Connexion'}
},
{
path: '/parametres',
name : 'parametres',
component: spaParametres,
props: {title: 'Paramètres'}
},
];
let router = new VueRouter({
hashbang: false,
routes
});
router.beforeEach((to, from, next) => {
next();
});
var app = new Vue({
el: '#app',
watch: {},
data: {
title: 'Connexion',
},
router
});
</script>
toolbar.vue.js (with the "props: ["title"]) :
<v-toolbar-title class="white--text">{{title}}</v-toolbar-title>
And in another page "parametres.vue.js" I'm using the props["title"], but the value of the title is always "Connexion", the value defined in my main App in index.html.
How can I make this value dynamic ? Thought passing it through the router would be great...
Thanks !

You are passing the property title from the v-app component to the spa-toolbar component. Then you are setting a property on the routes which is also called title.
These two are not related in any way. Also the title prop from the route is passed to the component in router-view, i.e. spaLogin and spaParametre.
So I think a better way would be to define a meta field on the route:
<div id="app" v-cloak>
<v-app>
<spa-toolbar :title="(($route.matched[0] || {}).meta || {}).title"></spa-toolbar>
<router-view></router-view>
</v-app>
</div>
<script>
Vue.use(VueRouter);
Vue.use(VeeValidate);
Vue.config.devtools = true;
const routes = [
{
path: '/',
component: spaLogin,
meta: {title: 'Connexion'}
},
{
path: '/parametres',
name : 'parametres',
component: spaParametres,
meta: {title: 'Paramètres'}
},
];
let router = new VueRouter({
hashbang: false,
routes
});
var app = new Vue({
el: '#app',
data: {},
router
});
</script>

Related

Cannot pass props in component from Vue router

Hi I'm trying to pass props from my vue router but it's not printing anything and when logged in mounted it's returning undefined, but its giving value when I'm trying console.log(this.$route.params.id); when I try for this.id returns undefined or rather in my User template its not outputting anything, same code is working in the online tutorial that I'm watching, please help me, is there any modification happened in a recent release
let User = {
props: ['id'],
template: `
<div>Hello # {{id}}</div>
`,
mounted() {
console.log(this.$route.params); // this is returning the value
console.log(this.id); // this is giving undefined
}
}
let App = {
template: `
<div class="wrapper">
<router-view></router-view>
</div>
`
}
let router = new VueRouter({
routes: [{
path: '/user/:id',
component: User,
props: true
}, ],
})
let app = new Vue({
el: '#app',
router: router,
components: {
'app': App
}
})
router.push('/user/1')
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.14/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router#2.0.0/dist/vue-router.js"></script>
<div id="app">
<app></app>
</div>
You are using very old version of Vue Router. Just switch to current version - 3.5.2 - and your code will work as expected....
let User = {
props: ['id'],
template: `
<div>Hello # {{id}}</div>
`,
mounted() {
console.log(this.$route.params); // this is returning the value
console.log(this.id); // this is giving undefined
}
}
let App = {
template: `
<div class="wrapper">
<router-view></router-view>
</div>
`
}
let router = new VueRouter({
routes: [{
path: '/user/:id',
component: User,
props: true
}, ],
})
let app = new Vue({
el: '#app',
router: router,
components: {
'app': App
}
})
router.push('/user/1')
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.14/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router#3.5.2/dist/vue-router.js"></script>
<div id="app">
<app></app>
</div>

Getting error while adding new routes, path is required in a route configuration

I wanted to add the dynamic routes and use the same component for all the dynamic routes. I have tried the following code to render the components, but I have got the error that says:
[vue-router] "path" is required in a route configuration.
What is the proper way of adding the dynamic routes and display the same components?
const Foo = {
template: '<div>Foo</div>'
}
const Home = {
template: '<div>Home</div>'
}
const router = new VueRouter({
mode: 'history',
routes: [{
path: '/',
component: Home
}]
})
const app = new Vue({
router,
el: "#vue-app",
methods: {
viewComponent: function(path, method) {
debugger;
let tf = `${path}/${method}`;
let newRoute = {
path: tf,
name: `${path}_${method}`,
components: {
Foo
},
}
this.$router.addRoute([newRoute])
},
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.14"></script>
<script src="https://npmcdn.com/vue-router/dist/vue-router.js"></script>
<div id="vue-app">
<a v-on:click="viewComponent('api/contact','get')">ddd</a>
<router-view></router-view>
</div>
Main problem is you are passing array into addRoute
Second problem is missing / at the beginning of the path (without it, you will get a "Non-nested routes must include a leading slash character" error)
Finally use $router.push to go to the new route
const Foo = {
template: '<div>Foo</div>'
}
const Home = {
template: '<div>Home</div>'
}
const router = new VueRouter({
mode: 'history',
routes: [{
path: '/',
component: Home
}]
})
const app = new Vue({
router,
el: "#vue-app",
methods: {
viewComponent: function(path, method) {
let tf = `/${path}/${method}`;
let newRoute = {
path: tf,
name: `${path}_${method}`,
component: Foo,
}
this.$router.addRoute(newRoute)
this.$router.push({ name: newRoute.name })
},
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.14"></script>
<script src="https://npmcdn.com/vue-router/dist/vue-router.js"></script>
<div id="vue-app">
<a v-on:click="viewComponent('api/contact','get')">ddd</a>
<router-view></router-view>
</div>

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.

Set page title with Vue Router

I have created a vue-router with a page title (h1).
Every vue-router link has a meta-title. How can I dynamically set my h1 page title?
I have tried $emit, but this is not working in my router. How can I change my page title?
const dashboard = {
template: `<div>DASHBOARD</div>`
}
const about = {
template: `<div>ABOUT</div>`
}
const routes = [
{path: '/dashboard', component: dashboard, name:'dashboard', meta: { title: 'Dashboard' }},
{path: '/about', component: about, name:'about', meta: { title: 'About' }}
]
const router = new VueRouter({
routes // short for routes: routes
})
router.beforeEach((to, from, next) => {
this.$emit('pagetitle', to.meta.title); // DOESN'T WORK!!
next();
});
new Vue({
el: '#app',
router,
data() {
return {
pagetitle: 'not set'
}
},
watch: {
'$route': function(value) {
// I can use things like value.name === 'about', but "watch" doesn't set the page title at the first page load.
}
}
})
<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="/dashboard">Dashboard</router-link>
<router-link to="/about">About</router-link>
<router-view></router-view>
<h1 v-text="pagetitle"></h1>
How can I change the page title???
</div>
In your <h1></h1> tag, just use the following
{{ $route.meta.title }}
If you would like to have correct browser history use this one:
router.afterEach((to, from) => {
Vue.nextTick( () => {
document.title = to.meta.title ? to.meta.title : 'default title';
});
})
Also if you need to change the document's title-tag, in your router.beforeEach replace this line :
this.$emit('pagetitle', to.meta.title);
with
document.title = to.meta.title;
It will work.

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