How to make vuejs navbar link active on click without route - vue.js

I have a vue bootstrap navbar. All of the nav items have a route except one. The one that doesn't (Contact) launches a modal on click. When an item is selected I want the item to be white.
I do this and it works for items that have a corresponding route:
:active='$route.name ==""'
Navbar
<ul class="navbar-nav">
<li class="nav-item">
<router-link class="nav-link" :to="{
path: '/',
hash: 'home',
}" :active='$route.name =="home"'>Home</router-link>
</li>
<li class="nav-item">
<router-link to="/About" :active='$route.name =="about"' class="nav-link">About</router-link>
</li>
<li class="nav-item">
<a class="nav-link" v-b-modal.modal-contact>Contact</a>
</li>
</ul>
How do I get the Contact item to be active on click?

I had the same problem as you and solved it like this.
First, you define a method that will use the name property of this.$route
export default {
name: 'App',
methods: {
getActiveNavLink(name) {
//This is for the navbar classes, you can modify them as
//as you need. (This will be assigned every-time we call this
//function).
let classString = "nav-item nav-link "
//We compare the given name with the route current name.
if (this.$route.name === name) {
//If it is true, we append to the class string the "active" value
classString += "active"
}
//Return the class string.
return classString;
}
}
}
Then in your navbar you do something like this
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">The navegation bar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav">
<router-link
:to="{ name: 'home'}"
:class="getActiveNavLink('home')" >
Home
</router-link>
<router-link
:to="{ name: 'secondRoute'}"
:class="getActiveNavLink('secondRoute')"><!--class="nav-item nav-link">-->
To the second route!
</router-link>
<router-link :to=...>
...
</router-link>
</div>
</div>
</div>
</nav>
That way, everytime you call the getActiveNavLink you pass the name of the route to compare, and if the name of the route is the same as your $route.name you will get an active navbar element!
Also, dont worry about the router-link classes being overwritten, they are not, the classes that we add, are appended, not overwritten.

its works for me for add class attributte and methods calling

You could use router.push(). When you open the modal, push to that path, when you leave the modal, push to the previous path.
https://router.vuejs.org/guide/essentials/navigation.html

Related

How to emit event in Vue.js depending on the width of the screen

I've got the following code from my sidebar. When any link is clicked, I'm also emitting an event to my root component and then invoking a function to hide the sidebar. This is working well but now I would like the event to be emitted only when the width of the screen is less than 768px so that I can emit the event only when I want to invoke the function.
<div class="side-links">
<ul>
<li>
<router-link #click="$emit('navLinkClicked')" :to="{ name: 'Home' }"
>Home</router-link
>
</li>
<li>
<router-link #click="$emit('navLinkClicked')" :to="{ name: 'Blog' }"
>Blog</router-link
>
</li>
<li>
<router-link #click="$emit('navLinkClicked')" :to="{ name: 'About' }"
>About</router-link
>
</li>
</ul>
</div>
You can use window.innerWidth to check the width of the current viewport. Global scope variables however is not available in the template, because its scoped to your component. You can either create a handler method:
<script>
methods: {
onNavLinkClicked() {
if (window.innerWidth < 768) {
this.$emit('navLinkClicked')
}
}
}
</script>
<template>
<div class="side-links">
<ul>
<li>
<router-link
#click="onNavLinkClicked"
:to="{ name: 'Home' }"
>
Home
</router-link
</li>
</ul>
</div>
</template>
or create a computed variable that defines if the width is below the treshold:
<script>
computed: {
isMobile() {
return window.innerWidth < 768;
}
}
</script>
<template>
<div class="side-links">
<ul>
<li>
<router-link
#click="isMobile ? $emit('navLinkClicked') : null"
:to="{ name: 'Home' }"
>
Home
</router-link
</li>
</ul>
</div>
</template>
Personally i'd go with the first option, so you'll only have to do the check once.
In Vue 2 it is also recommended to use kebab-case for event names.

Can't get the params from components to the target route

I have a menu which is imported to the home and mine page. In home page I passed a data(user_id) to the menu.
<li>
<router-link to="/">
<i></i>
<div class="icon home"></div>
<span class="text">Home</span>
</router-link>
</li>
<li>
<router-link :to="{ path: '/mine', params: {id: user_id} }">
<i></i>
<div class="icon user"></div>
<span class="text">Mine</span>
</router-link>
</li>
On mine page, when I tried to display the params in console, it doesn't show.
but If the passing of data is from home to mine page it works.
I hope you can help me.
Thanks.
Structure
components
menu
views
home
mine
try this
<router-link :to="`/mine/${user_id}`">
to see information about your route try this command
console.log(this.$route)

Show Div When Hover Based on ID in Vue JS

I have a div that when i want hover to it, it will show other div. However, my first div is dynamic, it has an ID. So how will i able to hover to ID based on its ID?
It should be #mouseenter="hoverService{{services.id}} = true" but it causes error. So i made the code below to just static.
Here's my code below:
<template>
<div
class="col-md-3"
v-for="(services, index) in servicesFiltered"
:key="index"
#mouseenter="hoverService = true"
#mouseleave="hoverService = false"
>
<div class="service_background" v-if="hoverService">
<div class="mb-1" v-for="(sub_services, index) in services.menu_items" :key="index">
<router-link
:to="{ path: `/${sub_services.data}`}"
>
<a
href="#"
class="btn btn-outline-primary w-100 services_button"
>{{sub_services.text }}</a>
</router-link>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
hoverService: false
};
}
};
</script>
Try this code
https://codesandbox.io/s/y7p9qyyovz
You need to maintain hover for each item you can not manipulate using single variable for multiple items.

Class and Style binding on certain conditions

I'm making a navigation component with nuxt.js, vue and storyblok. In this navigation i have a few items. i'm getting my navi items out of the storyblok API. i want to style certain navi items differently when the 'highlighted' attribute in the API equals to true or false.
My problem is that i dont exactlty know how to do that. this is what i have at this point.
div in my navigation component:
<div v-if="items" class="main-nav">
<nav>
<ul>
<li v-bind:class="{ highlighted: item.highlighted === isHighlighted, not_highlighted: item.highlighted === isNotHighlighted}" v-editable="items" :key="index" v-for="(item, index) in items">
<LinkType class="nav-link" :link="item.link" :linkText="item.name">{{ item.name }}</LinkType>
</li>
</ul>
</nav>
</div>
this is how i retrieve my data:
data() {
return {
items: this.$store.state.settings.main_nav ? this.$store.state.settings.main_nav : [],
isHighlighted: true,
isNotHighlighted: false
}
}
whenever i try to console.log item.hightlighted it gives back an undefined error. i would appreciate some help.
Try as below =>
<div v-if="items" class="main-nav">
<nav>
<ul>
<li v-bind:class="item.highlighted === isHighlighted ? 'highlighted' : 'not_highlighted'" v-editable="items" :key="index" v-for="(item, index) in items">
<LinkType class="nav-link" :link="item.link" :linkText="item.name">{{ item.name }}</LinkType>
</li>
</ul>
</nav>
</div>
You can also remove isNotHighlighted: false from data.

After I refresh the website the selectedIndex will change to the initial value

I have the
after I refresh the browser, the selected class go to the 首页, do not stay in 数据中心.
Who can help me with the issue?
my key code:
template:
<ul class="nav">
<li class="nav-item" ><router-link :to="homePath" :class="selectedIndex===0 ? 'selected' : '' " #click.native="selectedIndex=0">首页</router-link></li>
<li class="nav-item" ><router-link :to="dataCenterPath" :class="selectedIndex===1 ? 'selected' : '' " #click.native="selectedIndex=1">数据中心</router-link></li>
</ul>
script:
data(){
return {
selectedIndex: 0,
...
}
}
Whenever you refresh the page the JavaScript is reloaded and all the properties revert back to their initial values.
In your case selectedIndex is set back to 0.
To add the selected class to the link automatically when the target route is active make use of active-class prop on the ,router-link> as follows
<ul class="nav">
<li class="nav-item" ><router-link :to="homePath" active-class="selected" #click.native="selectedIndex=0">首页</router-link></li>
<li class="nav-item" ><router-link :to="dataCenterPath" active-class="selected" #click.native="selectedIndex=1">数据中心</router-link><li>
</ul>
edit
<ul class="nav">
<li class="nav-item" ><router-link :to="homePath" exact active-class="selected" #click.native="selectedIndex=0">首页</router-link></li>
<li class="nav-item" ><router-link :to="dataCenterPath" active-class="selected" #click.native="selectedIndex=1">数据中心</router-link><li>
</ul>
Make use of exact prop on home router link