Angular 8 routlerlink works only after page reload - angular8

After a successful login, it is navigated to the dashboard URL. From that menu, links aren't working even though URL is changing in the address bar. router link in the menu is working when we forcefully do a page reload in the browser. otherwise, nothing is happening. There is no error in the console as well. The code is given below.
login navigation which works currently
this.usermanagementService.login('login', {username: userName, password})
.subscribe(message => {
this.jwt.saveToken(message.data.token);
if (window.localStorage.getItem('locale') === null) {
window.localStorage.setItem('locale', 'en');
}
this.router.navigate(['/dashboard']);
// More lines which handles the error section
The app menu html
<div *ngIf="m.submenus?.length > 0" class="collapse" id="{{ m.name }}" aria-expanded="false">
<ul class="flex-column pl-2 nav submenu-dark">
<li *ngFor="let secondlevel of m.submenus" class="nav-item">
<a class="nav-link collapsed text-truncate" routerLink="{{ secondlevel.slug }}"><span>{{ secondlevel.name }}</span></a>
</li>
</ul>
</div>
Currently routerlink works after we do a forceful redirect instead of angular router navigation. how to fix it?

Put the navigation URL in if a condition or in else condition.
Or another problem is your menu component did not get which user is login, so you should try event emit when user login and subscribe into menu component and set condition related to login user.

Fixed the issue with the following changes in app.component
<app-header></app-header>
<div *ngIf="router.url !== '/login'; else loginTemplateName" id="wrapper" class="toggled container-margin-fix">
<app-menu></app-menu>
<router-outlet></router-outlet>
<app-footer></app-footer>
</div>
<ng-template #loginTemplateName>
<app-menu></app-menu>
<router-outlet></router-outlet>
<app-footer></app-footer>
</ng-template>
Inside the app-menu and app-footer there is an *ngIf checking whether it is not the login url. We need to add app-menu container in both cases in the app.component.html then only it will work eventhough it is hidden inside app-menu. Earlier it was just <router-outlet> only for the login route in the aapp.component.html

Related

<router-link> Vue Router #click event

I tried using a click event on a <router-link>. It works, but it is reloading the page everytime the link is clicked. I would like to avoid it but I can't figure out how.
I am aware that <router-link> does not accept a simple #click event. I saw on some forums that #click.I native would work, but as we know, that is deprecated.
So I would like to know if there is any solution other than wrapping the router link in a div and putting the listener on that div.
The reason why I want to do this is that I want to bind a class dinamicaly when the link is clicked. I have created a dropdown menu which is triggered onClick. But then when I follow a link inside that dropdown menu, the menu remains open. Therefore, I would like to have an additional #click event to dinamically bind a class (display: none) to the dropdown menu. The thing is that the items inside the dropdown are iterated which send parameters to a Vuex Mutation and therefore i can’t use regular tags and wrapping the router-links with a span or div is also not giving me the desired effect.
Thank you !
Regards,
T.
I have managed to solve the problem using a div wrapper and changing my css (that was preventing the code to work properly)
<div class="dropdown">
<a class="dropbtn" #click="dropClick"><i class="ri ico ri-draft-line"></i> Docs <i class="ri ico ri-arrow-drop-down-line ri-1x"></i></a>
<div class="dropdown-content" :class="{ 'dropdown-content-display': clicked }">
<div class="wrapper" v-for="route in $store.state.menuItems" :key="route.name" #click="dropClick">
<router-link :to="{ name: 'docs', params: { title: route.name } }"> <i :class="'ico ri ' + route.icon"></i> {{ route.name }}
</router-link>
</div>
</div>
</div>
If a understand your question, there is a "active-class" property on vue-router(router-link). You can set your classes dynamically by based on an active route.

To reopen the same page with different filter

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.

using v-if to use different route-links in header cause route to wrong path

I am new to JavaScript Frameworks(although I used vanilla js or jquery(a little)) and I started with VueJS for my project.
I am writing a single page application that uses an restful-api as server.
I wanted that in header some links will appear if user is not logged-in(register, login) and disappear once logged in. And, of course, different set of links will appear.
a bit visualization :)
before login
HEADER => | Register(to='/register') Login(to='login')
after a successful login
HEADER => | Home(to='/') Profile(to='/profile') SomeOtherLink(to='/someOtherPath')
but sometimes, after login, although header is rendered correctly(I look in inspect and links were correct), It goes wrong pathes.
Such as first link before login was register and first link after login is home. When I clik home it goes to register. It is same for Profile and login. when I click profile it goes to /login. But third one works.
It seems somehow renders (not) wrong eventListener for links.
Here is my template.
...
<ul class="navbar-nav">
<template v-if="loggedIn">
<router-link :to="{name: 'Home'}"
tag="li"
class="nav-item"
active-class="active">
<a class="nav-link"> Home </a>
</router-link>
<router-link to="/profile"
tag="li"
class="nav-item"
active-class="active">
<a class="nav-link"> Profile </a>
</router-link>
<router-link :to="{name: 'SomeRoute'}"
tag="li"
class="nav-item"
active-class="active">
<a class="nav-link"> SomeLink </a>
</router-link>
</template>
<template v-else>
<router-link :to="{name: 'Register'}"
tag="li"
class="nav-item"
id="register-link"
active-class="active">
<a class="nav-link"> Kayıt Ol! </a>
</router-link>
<router-link
:to="{name: 'Login'}"
tag="li"
class="nav-item"
id="login-link"
active-class="active">
<a class="nav-link"> Giriş Yap </a>
</router-link>
</template>
</ul>
...
here loggedIn is computed property which is set true if user logs in, and false vice versa. It works correctly.
I tried using div instead of template tag but result was same.
How can I fix this?
Am I in wrong place? Or is it a bug?
I printed loggedIn and it was correct as I mentioned before.
Problem was not that though, Component rendered correctly. Problem was the click event listener I suppose.
Adding unique key to each route-link solved problem.
Most probably vue create an event-listener for each link, and once old links are destroyed and new links are rendered, it creates new listeners for new link but not remove old ones. Since there was no identity in links, it maps according to order.
Once old link is replaced with new one, it has two listener, one for old link that stayed in the same place, one for intended for the link. So it triggers one of them when clicked.
Actually it explains that why it works as intended first, after refresh works wrong, after another refresh again works correctly.
I'm not sure if it is a bug or not, but adding key is the only and true solution as it seems.

Unable to create the correct link with vue router-link

I am using the vue rounter-link tag to navigate to a different page. My problem is that it does not seem to navigate to a different page. I think the problem lies within the "params" of the router-link. I do have a blog_id as 2 but it always shows the current page blog_id that I am at.
Initially I have
<router-link v-bind:to="{name:'datascience-single', params: {blog_id: blog.blog_id}}">
<i class="fa fa-cogs" aria-hidden="true"></i>
</router-link>
but then I started to think that maybe it's not taking the blog.blog_id correctly so I replaced it with a fixed value
<li v-for="blog in blogs" v-bind:key="blog.id">
<h1>{{blog.title}}</h1>
{{blog.content}}
<router-link v-bind:to="{name:'datascience-single', params: {blog_id: 2}}">
<i class="fa fa-cogs" aria-hidden="true"></i>
</router-link>
</li>
However the problem remains the same.
This answer assumes you are already on the same route you are navigating to.
Navigating to the same route does not refresh your components. We are used that whenever we go to a different URL the page should refresh, with multipage websites. However Vue router handles this differently. For the router the route, eg: /blogs/{id}, is not changing whenever id is being updated, we are still on /blogs/{id} but with a different parameter.
In order to detect this change we can simply make a watcher on the route parameter:
watch: {
'$route.params.id': (id) => {
// The route is the same, but our parameter changed.
}
}

Aurelia router-view inside dialog not working on reopening dialog

As per example given in aurelia documentation I am opening dialog box with viewmodel (say prompt ). This prompt has view inside in which I am adding "router-view" tag.
My routes are already configured. So when first time I open dialog it opens correct views as configured in routes and everything works well. But when I close dialog and re-opens dialog, It's not showing first route view. If I click other route link and come back to first route it works.
I have observed it's not creating instance of view model of first route( when opened dialog second time).
How to fix this issue?
Prompt html
<template><div class="row">
<left-menu ></left-menu>
<router-view></router-view>
</div></template>
<template>
and left-menu.htm
<template>
<div class="list-group">
<template repeat.for="item of items">
<a class="list-group-item ${$parent.selectedNav === item.routeName ? 'active' : ''}" route-href="route.bind: item.routeName;" click.delegate="$parent.select(item)">${item.text}</a>
</template>
</div>
Using a router inside a modal window seems off to me. The router is used to manage pages, but a modal is used to manage content within a page.
I would suggest building a modal window component, you can use <slot> tags to inject content and set it's model bindings to any data within the current view model.
Here's an example of my component that I use for this.
<template>
<div show.bind="visibility" class="modal-window">
<div>
<button class="btn btn-danger btn-sm close-button" click.delegate="close()">close</button>
</div>
<slot></slot>
</div>
<div show.bind="visibility" class="modal-window-overlay" click.delegate="close()"></div>
</template>
-
import { bindable } from 'aurelia-framework';
export class ModalContent {
#bindable visibility: boolean;
close(){
this.visibility = false;
}
}
<modal-content id.bind="'add-variant-window'">
<h4>Modal Content</h4>
<div>you can bind this to things on the current viewmodel</div>
</modal-content>