To reopen the same page with different filter - vuejs2

In my Laravel 5/vuejs 2/ VueRouter / app I have navigation area :
<li class="navigation_item_top">
<router-link :to="{ name: 'DashboardIndex' }" class="a_link">
Dashboard
</router-link>
</li>
<li class="active navigation_item_top" >
Customers
<ul class="collapse list-unstyled ml-2" id="backendCustomersSubmenu">
<li class="mt-2">
<router-link :to="{name : 'listCustomers'}" class="a_link">
Customers
</router-link>
</li>
<li class="mt-2">
<router-link :to="{name : 'listCustomers', params: { filter: 'new' } }" class="a_link">
New Customers
</router-link>
</li>
<li class="mt-2">
<router-link :to="{name : 'listCustomers', params: { filter: 'inactive' } }" class="a_link">
Inactive Customers
</router-link>
</li>
</ul>
</li>
Where there are 3 links listCustomers with different default filter opening page and it works ok if from
DashboardIndex page I move to any listCustomers.
But it does not work if from opened listCustomers page I open listCustomers with other filter.
I suppose as VueRouter considers all listCustomers as 1 page.
If there is a way to make it and selecting other listCustomers to reopen filter?

Not sure if i understand your Q very well, but i think you want to:
Append query to url. e.g company.com/listCustomers?filter=new
Make Vue notice the change and do something with that change
If that's the case then try this :
<template>
<--! HTML HERE -->
</template>
<script>
export default {
watch: {
'$route'(to, from){
// you don't need this but just in-case.
//this.$forceUpdate();
//If you're using query like ?filter=new, this should work
if (this.$route.query.filter) {
if (this.$route.query.filter== 'new') {
}else{
}
}
}
}
}
</script>
N.B
If you want use parameters it means you expect your url to be:
domain.com/listCustomers/inactive.
so just try the basics and link like this:
<router-link to="/listCustomers/inactive">
or
<router-link to="/listCustomers/new">.
And if your want queries your url is going to be:
domain.com/listCustomers?filter=new.
and you should pass exact prop to activate active page style.
then you need to watch for changes in the watch hook just like i did my answer
Now all the been said,
linking with parameters should work without any problem, but if you decide to use any Navigation Guards technique, like router.afterEach.
Please do not forget to add next(), to allow it to move on after your code. otherwise it won't navigate.
read Navigation Guards.
I hope you will understand.

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.

How to make vuejs navbar link active on click without route

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

Passing prop value after switching tabs

I have one header page that has two tabs. The two tabs direct to two different pages. I am using the area prop that I defined in the header page router view for the system page. It works fine when I am on the system page, but when I go to the product tab and come back to system tab, the prop in the system tab
loses the value. It shows as the string "area" in the prop. I would like to get the same value when I switch tabs.
<div class="tabs">
<ul>
<li #click="$router.push({ name: 'system' })">
<a>SYSTEM</a>
</li>
<li #click="$router.push({ name: 'product' })">
<a>Product</a>
</li>
</ul>
</div>
<router-view :area="area"/>
</div>
</template>
System view:
export default {
props: ['area'],
Instead of using #click binding you will be much better off using <router-link> especially since you are using the router-view
this will allow you to pass params simply in your app.
https://router.vuejs.org/api/
you declare your routes like so
const routes = [
{
path: '/glossary/:subjectName',
name: 'glossaryWithParams',
component: GlossaryPage,
},
]
Then in your code you can build the element simply like so:
<router-link
:to="`/glossary/${subjectName}`"
class="tabs__link"
>
Subject Glossary
</router-link>
```
Once you implement Router-link your history push state will also be resolved, and your params will work normally.

Vue router-link active-class when some child route duplicates the parent

I have a routing structure such as:
{
path: '/post/'
component: Post,
children: [
{
path: '/',
component: Text,
},
{
path: 'text/',
component: Text,
},
{
path: 'video/',
component: Video,
},
],
}
The important thing is that the route /post/text/ is just an "alias" to the /post/ (root point in this case). Also the router configuration has the custom linkActiveClass option such as 'act' with some defined styles.
In the parent template I have the kind of tabs with router-link's:
<ul>
<li>
<router-link to="/post/text/">Text</router-link>
</li>
<li>
<router-link to="/post/video/">Video</router-link>
</li>
</ul>
So the question is: when going to the /post/ route it would be nice the Text tab to be marked as "active" with that 'act' class because it's just a duplicate of the /post/text/ (or vice versa).
I haven't found any mention of this in the Vue Router docs. How such problems are solved competently?
Thanks in advance!
Solution (TL;DR - currently unsupported, fixed in v4)
The easiest way to achieve this - to use route alias prop, like:
{
path: 'text/',
component: Text,
alias: '/',
},
But, unfortunately, active-class doesn't work properly with aliases yet. It has been fixed in Vue Router v4.
You can do something like this
<ul>
<li :class="[currentPage.includes('/post/text/') ? 'activeClass' : 'no-active-class']">
<router-link to="/post/text/">Text</router-link>
</li>
<li :class="[currentPage.includes('/post/video/') ? 'activeClass' : 'no-active-class']">
<router-link to="/post/video/">Video</router-link>
</li>
</ul>
If your header or browser is a single component, you can include all this functionality in each of your links and it should work correctly.
NOTE: The variable with your current path will depend on the type of project and certain settings in it.
Use the Vuex state.
When every pages go to the tab area are mounted, call a setter for currentPage state.
And you can give an active class according to the state value
<li>
<div :class="{ 'active': currentPage === 'Text'}">
<router-link to="text">Text</router-link>></div>
</li>
<li>
<div :class="{ 'active': currentPage === 'Video'}">
<router-link to="video">Video</router-link>></div>
</li>
using exact-active-class solved a similar problem to yours.
docs: https://router.vuejs.org/api/#exact-active-class

Nav not showing up in aurelia

I am learning Aurelia and have stuck at this for quite a while. I want to add a navigation bar at the top of the screen using routing in Aurelia.
app.js:
export class App {
configureRouter(config, router) {
this.router = router;
config.map([
{
route: "add",
moduleId: "./add",
title: "Add new Post",
nav: "true",
name: "Add"
}
]);
}
... rest of the code
app.html:
<template>
<nav class="navbar navbar-default">
<div class="container-fluid">
<ul class="nav navbar-nav">
<li repeat.for="row of router.navigation">
<a href.bind="row.href">${row.title}</a>
</li>
</ul>
</div>
</nav>
</template>
Nothing shows up when I load the app. The navbar remains empty. Is there any required dependency to use the router? Am I missing anything? Thanks.
Note: Not sure if this is enough context to answer my question. I can add config.js or any other file if it's required.
Update : I replaced ${row.title} with hello (any hard coded string) and it's not showing up.
Thanks to comment from doeck I fixed the issue. I had to do two things:
add a <router-view></router-view> tag in my app.html
add an empty route in my app.js as follows: route: ["", "home"],
(When I didn't give the empty route, aurelia gave an error asking route "/" is not defined.)