I have managed to implement breadcrumbs in my vue.js application using npm.
But I'd like my breadcrumb to display a link to previous page, with the link to the current page(id included) next to it. Like this:
Home Page > Details page (as clickeble links)
I've tried following the example from this link https://www.npmjs.com/package/vue-2-breadcrumbs]
this is my index.js file
import Vue from 'vue'
import Details from '#/components/Details'
import Router from 'vue-router'
import HomePage from '#/components/HomePage'
import VueBreadcrumbs from 'vue-2-breadcrumbs'
Vue.use(Router)
Vue.use(VueBreadcrumbs,{
template:
' <ul class="breadcrumb">\n' +
' <li v-for="(crumb, key) in $breadcrumbs" v-if="crumb.meta.breadcrumb" :key="key" class="breadcrumb-item active" aria-current="page">\n' +
' <router-link :to="{ path: getPath(crumb) }">{{ getBreadcrumb(crumb.meta.breadcrumb) }}</router-link>' +
' </li>\n' +
' </ul>\n'
})
export default new Router({
routes: [
{
path: '/',
component: HomePage,
name: 'HomePage',
meta: {
breadcrumb: 'Home Page',
},
},
{
path: '/Details/:id',
component: Details,
meta:{
breadcrumb: function () {
const {name} = this.$route;
return `${name}`;
}
},
name: 'Details',
props: true
}
]
})
It all compiles, and it does render (but only one link, which is to the current page). Now I'd like to add the history link to my breadcrumb (the home page link). How do I do that?
Ok, so I got some inspiration from all of your comments and this is how I fixed it:
So I added one extra <li> to hold the "home page" and the second <li> for looping over the current page... I also wrapped everything inside a root- so no errors about double root elements would occur.
Vue.use(VueBreadcrumbs,{
template:
' <div v-if="$breadcrumbs.length" aria-label="breadcrumb">\n' +
' <ol class="breadcrumb">\n' +
' <li class="breadcrumb-item">Home</li>' +
' <li v-for="(crumb, key) in $breadcrumbs" v-if="crumb.meta.breadcrumb" :key="key" class="breadcrumb-item active" aria-current="page">\n' +
' <router-link :to="{ path: getPath(crumb) }">{{ getBreadcrumb(crumb.meta.breadcrumb) }}</router-link>' +
' </li>\n' +
' </ol>\n' +
' </div>'
})
Thank you everyone for your help!
Add another router-link to your template:
<div id="root">
<router-link :to="/">Home</router-link>
<ul class="breadcrumb">
<li v-for="(crumb, key) in $breadcrumbs" v-if="crumb.meta.breadcrumb" :key="key" class="breadcrumb-item active" aria-current="page">
<router-link :to="{ path: getPath(crumb) }">{{ getBreadcrumb(crumb.meta.breadcrumb) }}</router-link>
</li>
</ul>
</div>
Edit:
Declare your template in this way:
Vue.use(VueBreadcrumbs, {
template: ```
<div id="root">
<router-link :to="/">Home</router-link>
<ul class="breadcrumb">
<li v-for="(crumb, key) in $breadcrumbs" v-if="crumb.meta.breadcrumb" :key="key" class="breadcrumb-item active" aria-current="page">
<router-link :to="{ path: getPath(crumb) }">{{ getBreadcrumb(crumb.meta.breadcrumb) }}</router-link>
</li>
</ul>
</div>
```
})
You can create your own breadcrumb
In file 'index.ts' from router
export let activedRoutes: RouteRecord[] = []
router.beforeEach((to, from, next) => {
activedRoutes = [];
to.matched.forEach((record) => { activedRoutes.push(record) })
next();
});
In route definition
{
path: 'my-path-route',
name: 'MyNameRoute',
component: () => import('./MyComponent/MyComponent.component.vue'),
meta: {
title: 'Title',
icon: 'my-icon',
breadcrumb: { label: 'Label of bradcrumb', routeName: 'MyNameRoute'}
},
}
Create a BreadbrumbComponent
import Vue from 'vue';
import Component from 'vue-class-component';
import { Watch } from 'vue-property-decorator';
import { activedRoutes } from '#/router';
#Component({})
export default class BreadcrumbsComponent extends Vue {
breadcrumbs = []
#Watch('$route')
changeRoute() {
this.breadcrumbs = activedRoutes.map(e => e.meta?.breadcrumb).filter(e => e);
}
created() {
this.changeRoute()
}
}
In html BreadcrumbComponent
<template>
<div class="breadcrumbs" v-if="breadcrumbs.length > 1">
<ul class="v-breadcrumbs">
<template v-for="(item, i) in breadcrumbs">
<li :key="item.label">
<router-link
class="v-breadcrumbs__item"
:to="{ name: item.routeName }"
v-html="item.label"
:class="{ disabled: breadcrumbs.length - 1 == i }"
/>
</li>
<li
v-if="breadcrumbs.length - 1 > i"
class="v-breadcrumbs__divider"
:key="item.label"
>
<v-icon>mdi-chevron-right</v-icon>
</li>
</template>
</ul>
</div>
</template>
In scss of BreadcrumbComponent
.breadcrumbs {
.disabled {
text-decoration: none;
color: rgba(0, 0, 0, 0.38);
cursor: default;
}
}
Now is only use your component where wish
You can use the breadcrumb of vuetify to complement
https://vuetifyjs.com/en/components/breadcrumbs/#large
Related
i have code below and i want to navigate the user's profile when click on the name after asked by, i tried code below but it's not working and my json file structured as below
**
questions:Array[10] 0:Object category:"General Knowledge" user:"Saffron" difficulty:"medium" incorrect_answers:Array[3] 0:"Cinnamon" 1:"Cardamom" 2:"Vanilla" question:"What is the world's most expensive spice by weight?" type:"multiple"
**
<template>
<div class="container" width=800px>
<b-row>
<b-col cols="8">
<h1> Recently Asked </h1>
<ul class="container-question" v-for="(question1,index) in questions" :key="index"
>
<li v-if="answered" >
{{question1.question.selectedAnswer[index]}}
<li v-else >
{{question1.question}}
<b-row id="asked-info">
<p>Asked by: </p>
<div
id="user"
v-for="(answer, index) in answers(question1)"
:key="index"
>
<router-link to='/profile'> {{ answer }} </router-link>
</div>
</b-row>
<b-row>
<div class="category" v-for="(category,index) in category(question1)" :key="index" #click="selectedAnswer(index)">
<mark> {{ category }} </mark>
</div>
<b-button class="outline-primary" style="margin:auto;">Answer</b-button>
</b-row>
</li></ul>
</b-col>
<b-col>
<div class="ask-button">
<b-button href="#" class="primary">Ask Question</b-button>
</div>
<div>
<b-card
title="Card Title"
style="max-width: 20rem;"
class="mb-2"
>
<b-card-text>
Some quick example text to build on the card title and make up the bulk of the card's content.
</b-card-text>
</b-card>
</div>
<div>
<b-card
title="Card Title"
style="max-width: 20rem;"
class="mb-2"
>
<b-card-text>
Some quick example text to build on the card title and make up the bulk of the card's content.
</b-card-text>
</b-card>
</div>
</b-col>
</b-row>
<router-view />
</div>
</template>
<script>
export default {
data(){
return{
questions: [],
answered: null,
index: 0,
selectedIndex: null,
}
},
watch: {
question1: {
handler() {
this.selectedIndex = null;
this.answered = false;
},
},
},
methods: {
answers(question1) {
let answers = [question1.correct_answer];
return answers;
},
category(question1){
let category = [...question1.incorrect_answers];
return category
},
selectedAnswer(index) {
this.selectedIndex = index;
this.answered = true;
},
// filteredCategory(question1){
// return (question1.filter((question) => question.incorrect_answers == "Kfc"));
// },
},
mounted: function(){
fetch('https://opentdb.com/api.php?amount=10&category=9&difficulty=medium&type=multiple',{
method: 'get'
})
.then((response) => {
return response.json()
})
.then((jsonData) => {
this.questions = jsonData.results
})
}
}
</script>
routes.js
import question from './views/question.vue';
import App from './App.vue';
import Register from '#/components/Register'
import Login from '#/components/Login'
import Logout from '#/components/Logout'
import profile from '#/components/profile'
import contactus from '#/views/contactus'
export const routes = [
{ path: "/question", component: question },
{ path: "/", component: App },
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/register',
name: 'Register',
component: Register
},
{
path: '/logout',
name: 'Logout',
component: Logout
},
{
path: '/profile',
name: 'profile',
component: profile
},
{
path: '/contactus',
name: 'contactus',
component: contactus
},
]
There are a few things I want to point out here, you don't have to implement all of these, but understand what you are doing wrong:
You are missing the <router-view> tag, which is where you want your component to render because you use <router-link>
params are ignored if a path is provided. Instead, you need to provide the name of the route or manually specify the whole path with any parameter. Here for your reference: https://router.vuejs.org/guide/essentials/navigation.html
if you don't v-bind your property to, it will treat the value as a string. So you want to go like this <router-link :to="yourLink" />
In your case, you want to use <router-link :to="" /> with a dynamic string. There are 2 ways to achieve this: Declarative (<router-link>) and Programmatic (router.push)
Declarative:
<router-link> is like an anchor tag, so you should return a string.
<router-link :to="yourLink"> {{ userr }} </router-link>
computed: {
yourLink() {
return `/profile/${user(question1)}`
}
}
Programmatic
When you do a router.push, you are not doing a “link” anymore. It’s just a click event at that point. So change your router-link to a button with a click event
<button #click="yourLink"> {{ userr }} </button>
methods: {
yourLink() {
this.$router.push({name:'yourComponentName'} ,params:{user(question1)}})
}
}
EDIT
In your router.js:
{
path:'/profile/:user',
name: 'profile,
component: profile,
props: true
}
In your router-link:
<router-link :to="`/profile/${user(question1)}`"> {{ userr }} </router-link>
Then in your profile.vue, you can query the params by this.$route.params.user, for example, if you want to output it in a <p> tag:
<p>{{ this.$route.params.user }}</p>
I have this default vue navbar which I want to make it more dynamic by using v-for.
Before changes, this is the code:
<template>
<div>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
</template>
After changes, this is the code:
<template>
<div>
<div v-for="navbar in navbars" :key="navbar.id">
<router-link :to="navbar.router">{{ navbar.names }}</router-link>
</div>
</div>
</template>
<script>
export default {
name: "Header",
navbars: [
{ names: "Home", router: "/" },
{ names: "About", router: "/About" }
]
};
</script>
But after converted it, the navbar doesn't show up. Anything I miss out?
You need to define navbars as a data of the component using data
<template>
<div>
<div v-for="navbar in navbars" :key="navbar.id">
<router-link :to="navbar.router">{{ navbar.names }}</router-link>
</div>
</div>
</template>
<script>
export default {
name: "Header",
data: function () {
return {
navbars: [
{ names: "Home", router: "/" },
{ names: "About", router: "/About" }
]
}
}
};
</script>
I am trying to create a navigation and when someone clicks. It should navigate to another Vue.component.
Note: This app is Electron+Vue based, but it should work as normal Vue Project, as i've tried same concept in other Electron+Vue Project too.
Right now it shows no Content because of error of Router.
Am i missing anything?
Error Shows like this in Screenshot
===================================
----HelloWorld.vue-----
<template>
<div class="collapse navbar-collapse nav-item-outer" id="navbarNav">
<ul class="nav navbar-nav nav-list">
<li class="nav-item active" #click="navigate('information')">
<span class="nav-item-icon nav-item-icon-info"></span>
<span class="nav-item-title">Info</span>
</li>
<li class="nav-item" #click="navigate('map')">
<span class="nav-item-icon nav-item-icon-location"></span>
<span class="nav-item-title">Location</span>
</li>
<li class="nav-item" #click="navigate('videocontent')">
<span class="nav-item-icon nav-item-icon-video"></span>
<span class="nav-item-title">Video</span>
</li>
<li class="nav-item" #click="navigate('surfstation')">
<span class="nav-item-icon nav-item-icon-surf"></span>
<span class="nav-item-title">Surf</span>
</li>
<li class="nav-item" #click="navigate('telephone')">
<span class="nav-item-icon nav-item-icon-telephone"></span>
<span class="nav-item-title">Telefon</span>
</li>
<li class="nav-item" #click="navigate('/')">
<span class="nav-item-icon nav-item-icon-home"></span>
<span class="nav-item-title">Home</span>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
methods: {
navigate(route) {
this.$router.push(route)
},
}
}
</script>
===================================================
----main.js-------
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
Vue.config.productionTip = false
Vue.use(VueRouter)
export default new VueRouter({
routes: [
{
path: '/',
name: 'dashboard',
component: require('#/views/Dashboard').default
},
{
path: '/information',
name: 'information',
component: require('#/views/Information').default
},
{
path: '/map',
name: 'map',
component: require('#/views/Map').default
},
{
path: '/surfstation',
name: 'surfstation',
component: require('#/views/Surfstation').default
},
{
path: '/telephone',
name: 'telephone',
component: require('#/views/Telephone').default
},
{
path: '/videocontent',
name: 'videocontent',
component: require('#/views/VideoContent').default
},
{
path: '*',
redirect: '/'
}
]
})
new Vue({
render: function (h) { return h(App) },
}).$mount('#app')
=====================================================
----App.vue------
<template>
<div id="app">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<main>
<router-view></router-view>
</main>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
A help would be Appreciated.
Instead of exporting the router, put in a const and specify it inside new Vue({
main.js
const router = new VueRouter({
routes: [
...
],
// Prevent white screen on reload (in production build)
mode: process.env.IS_ELECTRON ? 'hash' : 'history'
})
new Vue({
router,
render: h => h(App),
mounted () {
// Prevent white screen when the app is launched (in production build)
this.$router.push('/').catch(error => { })
}
}).$mount('#app')
I'm attempting to add a custom handler InlineButtonClickHandler to a <router-link> component's click event, so that I can emit a custom appSidebarInlineButtonClick event.
But, my code isn't working. What am I doing wrong?
<template>
<router-link :to="to" #click="InlineButtonClickHandler">
{{ name }}
</router-link>
</template>
<script type="text/babel">
export default {
props: {
to: { type: Object, required: true },
name: { type: String, required: true }
},
methods: {
InlineButtonClickHandler(event) {
this.$emit('appSidebarInlineButtonClick');
}
}
}
</script>
You need to add the .native modifier:
<router-link
:to="to"
#click.native="InlineButtonClickHandler"
>
{{name}}
</router-link>
This will listen to the native click event of the root element of the router-link component.
<router-link:to="to">
<span #click="InlineButtonClickHandler">{{name}}</span>
</router-link>
Maybe you can try this.
With vue 3 and vue router 4 the #event and tag prop are removed according to this and instead of that you could use v-slot:
const Home = {
template: '<div>Home</div>'
}
const About = {
template: '<div>About</div>'
}
let routes = [{
path: '/',
component: Home
}, {
path: '/about',
component: About
}, ]
const router = VueRouter.createRouter({
history: VueRouter.createWebHashHistory(),
routes,
})
const app = Vue.createApp({
methods: {
test() {
console.log("test")
}
}
})
app.use(router)
app.mount('#app')
<script src="https://unpkg.com/vue#3"></script>
<script src="https://unpkg.com/vue-router#4"></script>
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/" v-slot="{navigate}">
<span #click="test" role="link">Go to Home</span>
</router-link>
<br/>
<router-link to="/about">Go to About</router-link>
</p>
<router-view></router-view>
</div>
Im using Vue.js with Vue-router. I'm trying to create a list of components, each of which shows a subroute.
Example of What I am trying to do:
<ul>
<li>first
<ul><li>nested sub</li></ul>
</li>
<li>second
<ul><li>nested sub</li></ul>
</li>
<li>third
<ul><li>nested sub</li></ul>
</li>
</ul>
I am only able to get the nested subroute to appear in the first component. The rest of my components rendered in the v-for loop have no subroutes appearing.
Here is a fiddle of my code, showing the problem: https://jsfiddle.net/retrogradeMT/73zza1ah/
HTML:
<div id="page-content">
<router-view></router-view> <!-- renders campaign block list -->
</div>
<template id="campaignBlock" >
<ul>
<li v-for="campaign in campaigns">{{ campaign.name }}
<router-view> </router-view> <!-- should show subroute -->
</li>
</ul>
</template>
<template id="subroute">
<ul>
<li>Nested View</li>
</ul>
</template>
JS:
Vue.use(VueRouter)
Vue.component('app-page', {
template: '#campaignBlock',
data: function() {
return{
campaigns: []
}
},
ready: function () {
this.fetchCampaigns();
},
methods: {
fetchCampaigns: function(){
var campaigns = [
{
id: 1,
name: 'First List item'
},
{
id: 2,
name: 'Second List item'
},
{
id: 3,
name: 'Third List item'
},
];
this.$set('campaigns', campaigns);
}
}
})
Vue.component('subroute', {
template: '#subroute'
})
var App = Vue.extend({})
var router = new VueRouter()
router.map({
'/': {
component: Vue.component('app-page'),
subRoutes: {
'/': {
component: Vue.component('subroute')
},
}
}
})
router.start(App, '#page-content')
There can only be one single nested and identical router-view inside another. No way around it. For different routes, you can have multiple instances of router-view.
What you can do is something like this:
<li v-for="campaign in campaigns">{{ campaign.name }}
<subroute></subroute>
</li>