Pass var to vue router in meta - vue.js

I have a route created with vue-router.
{
path: '/events/:id',
component: Event,
name: 'Event',
meta: {
title: 'Design Web'
}
},
In "meta", I give it the name of my page.
I can call the title of my page by doing this: $route.meta.title
But now, I'm facing a problem. In the title of my page, I would like to pass a variable (the name of my event).
meta: {
title: $nameOfEvent
}
How to do ?
Thank you

It is possible if you define the title attribute as a function :
{
meta: { title: route => { /* return custom title based on route, store or anything */ } }
}
and
router.beforeEach((to, from, next) => {
if (to.meta.title) {
document.title = to.meta.title(to);
}
next();
})
Codepen: https://codepen.io/anon/pen/roRmdo?editors=1111 (you need to inspect inner iframe to see the title change).
or create a directive:
Vue.directive('title', {
inserted: (el, binding) => document.title = binding.value,
update: (el, binding) => document.title = binding.value
})
Then use that directive on the router-view component:
<router-view v-title="title" ></router-view>
Component:
export default {
data(){
return {
title: 'This will be the title'
}
}
}
Source: https://github.com/vuejs/vue-router/issues/914

Related

Vue router - path #ID scrollBehavior

I have created a MENU where I link via <router-link> but certain links are linked to the same page using (anchors).
When I'm on the Work page and I click on the #services section, which is on the Bio page, the section is displayed correctly, but if I want to go to the services section on the Bio page, the URL just changes, but it won't go to the right section for me.
noubtest.com
NAVIGATION
<router-link v-show="!mobile" class="link bio" :to="{ name: 'Home' }">Bio</router-link>
<router-link v-show="!mobile" class="link link2" :to="{ name: 'Services' }">Services</router-link>
<router-link v-show="!mobile" class="link link2" :to="{ name: 'SelectedWork' }">Work</router-link>
ROUTER
{
path: "/home",
name: "Home",
component: Home,
meta: {
title: "Bio",
requiresAuth: false,
},
},
{
path: "/home#fifthPage",
name: "Services",
component: Home,
meta: {
title: "Services",
requiresAuth: false,
},
},
const router = new VueRouter({
mode: "history",
routes,
scrollBehavior() {
return { x: 0, y: 0 };
},
});
router.beforeEach((to, from, next) => {
document.title = `${to.meta.title} | YounesFilm`;
next();
});
router.beforeEach(async (to, from, next) => {
let user = firebase.auth().currentUser;
let admin = null;
if (user) {
let token = await user.getIdTokenResult();
admin = token.claims.admin;
}
if (to.matched.some((res) => res.meta.requiresAuth)) {
if (user) {
if (to.matched.some((res) => res.meta.requiresAdmin)) {
if (admin) {
return next();
}
return next({ name: "Home" });
}
return next();
}
return next({ name: "Home" });
}
return next();
});
export default router;
How can I click through the page between sections?
You must switch your VueRouter from hash mode to history mode of routing - then hashtags will work but in a different way.
Your routes should not have a hash symbol # inside their path - instead, you should provide it under the hash attribute of the route link:
<router-link :to="{ name: pathName, hash: '#text' }">
Jump to content
</router-link>
But this alone is not enough. You also need to alter the scrollBehavior of the VueRouter:
import { routes } from './routes.js';
const router = new VueRouter({
routes,
scrollBehavior(to, from, savedPosition)
{
if (savedPosition)
{
return savedPosition;
}
if (to.hash)
{
return { selector: to.hash }; // <==== the important part
}
return { x: 0, y: 0 };
}
});
With a few research, I found two things that could help you.
First, this error is known and discussed on github vue-router issues page.
Second, I found that Workaround on npmjs.com, and you could probably give it a try.
EDIT
I found another solution to a similar problem here.
And from that page, I found a scrollBehavior example like this:
scrollBehavior: function (to) {
if (to.hash) {
return {
selector: to.hash
}
}
}
And if it still doesn't work, you could try to use
:to="{ name: 'Home', hash: 'fifthPage'}".

I want to get a router params in Vue Component before it created

I develop a ecommerce website with Vue.js2,
for the single product page, I have a route like
{
path: '/product/:code',
name: 'product',
props:true,
component: Product
},
And in the component I have somthing like
props: {
code: {
type:String
}
},
data: ()=> {
return {
product:{}
}
},
beforeMount(){
axios
.get('http://127.0.0.1:8000/api/products/'+this.code)
.then((response) => {
this.plan = response.data,
this.ListImages = response.data.ListImages;
console.log(this.ListImages)
console.log(this.plan)
})
}
The data is retrieved but the component is already create but if I do the request "beforeCreate()" the "this.code" is "undefined" and when I use "$router.params.code" an error is occured stating that "$router" is not the define.
Please can I have some help?
You should be able to use it like this:
this.$route.params.code
In the component, You can use this:
User {{ $route.params.getUserName }}
Route.js
{
path: "/#:getUserName",
name: "profile",
component: () => import("../views/ProfileView.vue"),
}

(Vue Router) Push params when on a certain route

I have a component, which has programmatic routing based on external data.
The external data is fetched in the App.vue component and used in child components as props.
The data is used in the child component like this:
props: {
externalData: Array
},
computed() {
data() {
return this.externalData
}
}
Here is my router.js (excerpt)
const routes = [
{
path: "/:hae?",
name: "Home",
component: Home
},
{
path: "*",
name: "NotFound",
component: NotFound
}
];
And my Home.vue with the $router.push method (excerpt):
created() {
if (this.$route.path === "/") {
this.$router.push({
params: {
hae: this.data[0].id
}
});
}
},
So here is what i want to achieve:
This is my example array: [{hae: "hae001"}, {hae: "hae002"}, {hae: "hae003"} ...]
When you navigate to https://website.com/ i want the router to redirect you to a param which is the first element of the array, but if you navigate to somewhere else which is not existing in the array (e.g. /something) i want the router to render my NotFound.vue component.
What am i missing?
created() {
const firstDataElementExists = this.data && this.data[0] && this.data[0].hae
if (!firstDataElementExists) {
this.$router.push('/404')
return
}
const isRootPath = this.$route.path === '/'
if (isRootPath) {
this.$router.push(this.data[0].hae)
return
}
const pathIsInData = !!this.data.find(d => d.hae === p)
if (!isRootPath && !pathIsInData) {
this.$router.push('/404')
}
}

vue-router does not stay on same page after a page refresh

I have two routes on vue-router, /user/:uid and /itinerary/:id. The first route is shown after the user logs in and from there they select the itinerary they want to view which would bring them to the next route.
While on /itinerary/:id, if I do a page refresh/reload/f5 I see the browser address bar back on /user/:uid. In the vue-devtools, it just resets to showing /user/:uid (not a case of some router.push() or whatever). Why is this happening and how can I keep the user on /itinerary/:id even if they refresh the page?
const routes = [
{ path: '/', component: LoginPanel },
{
path: '/user/:uid',
component: ItineraryList,
beforeEnter: authGuard,
},
{
path: '/itinerary/:itinerary_id',
name: 'itineraryView',
component: ItineraryBuilder,
beforeEnter: authGuard,
},
];
function authGuard(to, from, next) {
// retrieved from localStorage
if (idToken && userEmail) {
next();
} else {
next('/');
window.alert('Please login first');
}
}
Edit: Added relevant code from ItineraryBuilder
beforeRouteLeave(to, from, next) {
if (this.confirmed) { // set on data() property
next();
} else {
this.$modal.show('dialog', {
title: 'Confirm save new changes?',
text: '',
buttons: [{
title: 'Yes',
handler: () => {
let itinerary_id = this.$route.params.itinerary_id
let queries = [];
this.itinerary.forEach(item => {
console.log(item);
let board_id = item.doc_id;
queries.push(db.collection('itineraries').doc(board_id).set(item, { merge: true }));
});
Promise.all(queries).then(() => {
// this.$store.commit('UPDATE_ITINERARY', this.itinerary);
this.$modal.hide('dialog');
this.confirmed = true
eventBus.$emit('itinerary_saved', true);
next();
})
}
},
{
title: 'No',
handler: () => {
this.$modal.hide('dialog');
next(false);
}
}]
});
}
}
I didn't notice it at first, but could it be related? I'm using this.confirm as a flag to handle if there are any changes made by the user, I'll emit a change event and set the flag to false - meaning there are unsaved changes so the current state is unconfirmed.

VueJS and dynamic titles

Trying to use vue-meta
I can't understand how to set title based on XHR response. So far I have:
<script>
export default {
name: 'Model',
data() {
return {
model: [],
}
},
metaInfo: {
title: 'Default Title',
titleTemplate: '%s - site slogan'
},
methods: {
getModels() {
window.axios.get(`/api/${this.$route.params.manufacturer}/${this.$route.params.model}`).then((response) => {
this.model = response.data;
this.metaInfo.title = response.data.model_name; // THIS NOT WORKING
});
}
},
watch: {
$route(to, from) {
if ( to.name === 'model' ) {
this.getModels();
}
},
},
created() {
this.getModels();
}
}
</script>
when I try to set
this.metaInfo.title = response.data.model_name;
Getting error: Uncaught (in promise) TypeError: Cannot set property 'title' of undefined
So this.metaInfo is undefined...
I need my title be based on response from XHR request.
You need to use the function form of metaInfo and have it get updates from reactive data
<script>
export default {
data() {
return {
title: "Default Title",
// ...
};
},
metaInfo() {
return {
title: this.title,
// ...
};
},
methods: {
getModels() {
window.axios.get("url...").then((response) => {
this.title = response.data.model_name;
});
}
},
// ...
I assume you call this.metaInfo.title = response.data.model_name; inside a method on the vue instance. The problem I see is that you should put the metaInfo object inside the return object from data(). Like this:
data() {
return {
model: [],
metaInfo: {
title: 'Default Title',
titleTemplate: '%s - site slogan'
},
};
},
Here is my solution:
I have a root component in my SPA app: App.vue with this code in it:
export default {
/**
* Sets page meta info, such as default and page-specific page titles.
*/
metaInfo() {
return {
titleTemplate(titleChunk) {
const suffix = "Marvin Rodank's dank site";
return titleChunk ? `${titleChunk} - ${suffix}` : suffix;
},
};
},
};
That sets up my default page title for all pages, and then after that, the answer by Stephen Thomas contains the key logic.
For all pages with static page titles, it's easy:
metaInfo() {
return { title: 'List examples' };
},
But dynamic page titles were more difficult, but still easy once you realize the page loads in two phases:
phase 1: browser displays the default page title
phase 2: page title is updated with the dynamic title
metaInfo() {
return {
title: this.example.name,
};
},
In the dynamic title example there, my child component fetches the object this.example from an API endpoint, so it is important to note that this.$metaInfo().title updates itself when this.example is populated.
You could test it with code such as this:
metaInfo() {
return {
title: this.example.name,
};
},
mounted() {
const obj = {
name: 'Sally',
age: 1337,
};
this.example = obj;
},