I'm trying to create a list of hyperlinks to the last 5 pages (views) visited by a user. However I don't really know where/ how to start...
I thought about somehow storing each route when visited but I don't know what's the best practice to do so.
I'm not asking for a working code, I just need some help to find the right direction to start with.
You can use router.beforeEach((to, from, next) =>{}) and store the url in an array. You can read more details about navigation guards here.
https://router.vuejs.org/guide/advanced/navigation-guards.html#global-before-guards
Found this, it may help:
https://codesandbox.io/s/mutable-glade-qnrxm
It stores the visited routes.
It works like this:
<template>
<div>
<span v-for="crumb in crumbs" :key="crumb.index">
<router-link :to="crumb.path">{{ crumb.name }}</router-link> |
</span>
</div>
</template>
<script>
export default {
data() {
return {
crumbs: []
};
},
watch: {
$route(to) {
if (this.crumbs.length > 3) {
this.crumbs.shift();
}
this.crumbs.push({
path: to.fullPath,
name: to.name/* */
});
}
},
mounted() {
this.crumbs.push({
path: this.$route.fullPath,
name: this.$route.name
});
}
};
</script>
Here, it gets the route name and path on mount and pushes it to crumbs array.
mounted() {
this.crumbs.push({
path: this.$route.fullPath,
name: this.$route.name
});
}
Then it constantly watches and changes on route. On change, it shifts(removes the last and adds a new one) any router if there are more than 3. And then it assignes the name and path for every new router.
watch: {
$route(to) {
if (this.crumbs.length > 3) {
this.crumbs.shift();
}
this.crumbs.push({
path: to.fullPath,
name: to.name/* */
});
}
},
And at last, it loops the crumbs and displays it.
<span v-for="crumb in crumbs" :key="crumb.index">
<router-link :to="crumb.path">{{ crumb.name }}</router-link> |
</span>
Related
I'm wanting to conditionally redirect to a page based on a user's settings.
I have my app where I've passed the user's setting:
<div id="app">
{{ $defaultStartingPage }} <!-- 'search-page' -->
<router-view></router-view>
</div>
I'd like to pass the $defaultStartingPage into my router-view and then handle it there, something like <router-view default-starting-page="{{ $defaultStartingPage }}"> but so far I haven't been able to.
I was able to set the variable to the window in my app.js file and then do this, but it's not reactive and it doesn't feel right.
export default {
routes: [
{
path: '/',
name: 'home',
redirect: () => {
if (window.defaultStartingPage) {
switch (window.defaultStartingPage) {
case 'service-appointments':
return { name: 'services-appointments' };
}
}
return { name: 'services-repairs' };
},
}
]
}
Is there a way to pass attributes to router-view and then access them when returning views? Or maybe a better way to do this?
Thanks!
I have a Vue app like this:
<div id="app">
<Navbar/>
<div class="main">
<h1>{{ title }}</h1>
<router-view/>
</div>
<Foot/>
</div>
As I change pages via router-links, I'd like to also update the {{title}} field. The hacky way I've done it is this:
methods: {
logRoute() {
this.$nextTick(() => {
this.title = this.$route.name
});
}
}
However, sometimes I'd like to have the title be something different according to a property in the component, for example the "About" page is titled "About me." What's the best way to approach this?
Hi Jasper try this way.
Go to your route and and a meta on the router you want to have a title on like the code below
const routes = [
{
path: "/",
name: "Home",
component: Home,
meta: {
title: 'Home'
}
},
]
And go to your App.vue and add this a watch to look up when you go to different pages if you dont have a meta with a title it will put a default value on the website title.
export default {
watch: {
'$route' (to) {
document.title = to.meta.title || 'Default Title'
}
},
};
I hope this solves your problem have a nice day !
I'm in the process of setting up a VueJs SPA. I'm using vue-router and I'm trying to find the best solution to the following problem. I have a series of routes. Each of which needs to call an API to get the meta data for the given ID.
/industry/:id/overview
/industry/:id/top-stories
/industry/:id/top-tweets
/brand/:id/overview
/brand/:id/top-stories
/brand/:id/top-tweets
I've been looking at using created or beforeRouteEnter/beforeRouteUpdate and I'm a bit lost. Ideally, I would only fetch new data when a new /industry/:id is reached, not when navigating between pages within the same ID. Also, I'd like to avoid having to define the fetch to grab data in every page component. Also don't want to over complicate this, so my question is, Is there a standard method for tackling this issue?
Clarification:
When I say meta here, I mean data returned from an API about the given industry or brand which I pull using the ID in the route. The api call includes the name of the industry/brand which I want to have on page as soon as the page is presented to the user.
I have something similar. I tackle this using the following approach:
I use the same component for all /industry/:id Vue likes to reuse components wherever it can so if two routes (for example /industry/:id/overview and /industry/:id/top-stories) are using the same component it will stay the same.
What does change, however, is the route meta. So if you add a page key to the meta object in the route objects, and probably add a computed property called page that return this.$route.meta.page, you can use v-if attributes to conditionally render any component. So you might have something like <div v-if="page === 'overview'"></div><div v-else-if="page==='top-stories'"></div>
What this allows you to do is fetch all the data from the API during created or mounted lifecycle and store it as the state. Since the route change doesn't reload the component the state stays the same.
Here is a code example
// router.js
const Project = () =>
import(/* webpackChunkName: "projects" */ "./views/projects/_id");
export default new Router({
mode: "history",
routes: [
{
path: "/projects/:project_id/views",
name: "ViewProject",
component: Project,
meta: {
page: "views",
}
},
{
path: "/projects/:project_id/export",
name: "ExportProject",
component: Project,
meta: {
page: "exports"
}
},
{
path: "/projects/:project_id/recommendations",
name: "ProjectRecommendations",
component: Project,
meta: {
page: "recommendations"
}
},
]
});
And here is the template
<template>
<div v-if="project">
<h1>{{ project.name }}</h1>
<router-link :to="/project/someid/views">Views</router-link>
<router-link :to="/project/someid/exports">Exports</router-link>
<router-link :to="/project/someid/recommendations">Recommendations</router-link>
<ul v-if="page==='views">
<li v-for="(view, i) in project.views" :key="i">{{ views }}</div>
</ul>
<ul v-else-if="page==='exports">
<li v-for="(export, i) in project.exports" :key="i">{{ export }}</div>
</ul>
<ul v-else-if="page==='recommendations">
<li v-for="(recommendation, i) in project.recommendations" :key="i">{{ recommendation }}</div>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
project: null
}
},
computed: {
page() {
return this.$route.meta.page;
}
},
mounted() {
this.getProject()
},
methods: {
getProject() {
axios
.get(`/projects/someid`)
.then(res => this.project = res.data)
}
}
}
</script>
I want to have 3 main parts in my webapp:
App.vue - this page only has the <router-view> tag and some general configuration + it fetches an API every second
ControlPanel.vue - this page visualizes some data that the App.vue page gets
Profile.vue - this page visualizes some data that the App.vue page gets too
Right now I set up my App.vue with the API call and it passes the data it receives to the two pages with props like the following example. As you can see when it gets mounted it starts a loop that lasts 1 second where it goes and fetches the API and then it returns it to the two routes.
<template>
<div id="app">
<div id="nav">
<router-link :to="{ name: 'control_panel', params: { APIlogs } }">Control panel</router-link>
<span> | </span>
<router-link :to="{ name: 'profile', params: { APIlogs } }">Profile</router-link>
</div>
<router-view/>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
APIlogs: '',
};
},
mounted() {
setInterval(() => this.refreshData(), 1000);
},
methods: {
refreshData() {
axios.get('http://192.168.30.65:5000/logs')
.then((response) => {
this.APIlogs = response.data;
});
},
},
};
</script>
<style>
...
</style>
On the other hand, Control Panel and Profile are fundamentally the same page and they should get the props from the "father" and use it to visualize data but right now it doesn't work. When I click on one route it shows me the value the prop has in that moment and doesn't update as the App.vue page fetches more and more data.
<template>
<div id="app">
{{APIlogs}}
</div>
</template>
<script lang="ts">
import axios from 'axios';
export default {
name: 'control-panel',
props: ['APIlogs'],
data() {
return {
};
},
mounted(){
console.log(this.APIlogs);
},
methods: {
},
};
</script>
<style>
...
</style>
Did I do something wrong? Is my implementation good enough or is it lacking in some way? Really hope someone can help me out with this one, it's really tearing me apart.
Thanks a lot in advance
EDIT
Just to give a bit more context, before having props I was calling the same exact API from both components and it seemd very inefficient to me so I switched to this method.
Also my router.ts looks like this:
import Vue from 'vue';
import Router from 'vue-router';
import ControlPanel from '../src/components/ControlPanel.vue';
import Profile from '../src/components/Profile.vue';
Vue.use(Router);
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'control_panel',
component: ControlPanel,
props: true,
},
{
path: '/profile',
name: 'profile',
component: Profile,
props: true,
},
],
});
there's no params inside your paths i.e: path: '/:apilogs'
A dynamic segment is denoted by a colon :. When a route is matched,
the value of the dynamic segments will be exposed as
this.$route.params in every component.
(source)
After a while and almost an entire afternoon wasted on this problem, I found out this article which helped me achieve my goal. I just created a file with all my api calls and I call it every time I need to fetch something. It's a way more elegant and intelligent solution I think.
An easy way to make this work is to just make your APIlogs an object. Then it would be passed by reference and any updates to it will be reflected in the other components ..
export default {
data() {
return {
APIlogs: {logs: ''},
};
},
mounted() {
setInterval(() => this.refreshData(), 1000);
},
methods: {
refreshData() {
axios.get('http://192.168.30.65:5000/logs')
.then((response) => {
this.APIlogs.logs = response.data;
});
},
},
};
<template>
<div id="app">
{{APIlogs.logs}}
</div>
</template>
PS: You should probably use clearInterval in your beforeDestroy hook.
I am playing around with Vue 2, and I want to make a whole div clickable.
This div have a link, image and text.
I used router-link for links in header and other links but when I try to use something else the page keeps refreshing.
Can someone please help me get over this somehow..
Cheers!
Add click event to you <div> that you want to be clickable as below:
<div #click="clickMethod"></div>
Now in your methods property add rhe clickMethod callback that you want to fire when clicked like below
methods: {
clickMethod() {
//add code that you wish to happen on click
}
}:
For anyone who is stuck here like I did on how to make a Div Clickable
<div #click="clickeMethod">
<p> Some Text Here </p>
</div>
script:
<script>
export default {
name: 'headers',
data() {
return {
};
},
methods: {
clickMethod() {
this.$router.push('home');
},
},
};
</script>
This Event will make a div Clickable.
Hope I helped someone :) and thnx to #user7814783
For those wondering how router.push method works, below are various ways you can use the method:
// literal string path
router.push('home')
// object
router.push({ path: 'home' })
// named route
router.push({ name: 'user', params: { userId: '123' } })
// with query, resulting in /register?plan=private
router.push({ path: 'register', query: { plan: 'private' } })
For me this implementation worked best:
<script>
export default {
name: 'home',
data() {
return {
};
},
methods: {
clickMethod() {
this.$router.push({ path: 'home' });
},
},
};
</script>