Nuxt.js 3 and on-site anchor navigation - vue.js

I am learning Nuxt.js 3 and am writing a simple project with a one-scroll design that has a menu with anchor links. Clicking a link, the site should automatically scroll to the anchor (like a div with an id).
To test this I set up a simple Nuxt 3 installation with npx nuxi init nuxt-app, removed the demo content and replaced it with this:
pages/index.vue
<template>
<div>
<div id="home"><p>hello world</p></div>
<div class="menu">
<nuxt-link :to="{ path: '/', hash: '#ciao' }">
link
</nuxt-link>
</div>
<div style="height: 3000px">placeholder</div>
<div id="ciao"><p>ciao world</p></div>
<div class="menu">
<nuxt-link :to="{ path: '/', hash: '#home' }">
link
</nuxt-link>
</div>
<div style="height: 3000px">placeholder</div>
</div>
</template>
The problem is, that it is not working. The url in the browser is changed to localhost:3000/#ciao or localhost:3000/#home on click. But the view is not being changed.
Is there something else I need to set up in nuxt, to get anchor navigation to work?

As answered here: https://github.com/nuxt/framework/discussions/5561#discussioncomment-3007717
Using a regular a tag solves the issue
<a href="/#ciao">
go to ciao's hash
</a>
Otherwise, you can also use
<nuxt-link :to="{ hash: '#home' }" :external="true"> <!-- no need for a path if same page -->
go to home's hash
</nuxt-link>
The external prop (Nuxt3 only) is detailed here: https://v3.nuxtjs.org/api/components/nuxt-link#props
Quote from the documentation
Forces the link to be considered as external (true) or internal (false). This is helpful to handle edge-cases.

Related

router-link VueJS can't link to an element in the same page

I'm trying to developp a sidebar of a documentation who it links to elements on th same page
<div class="mt-6">
<li class="relative">
<router-link class="menuItem-active-link" to="#users">
{{$t('navigation.users')}}
</router-link>
</li>
<li class="relative">
<a href="#advanced" class="menuItem-active-link" >
{{$t('navigation.advanced')}}
</a>
</li>
</div>
when I use the a tag I can navigate between each elements but I didn't know how styling the active link
And when I use router-link the URL change but the page stay on the current element, it does'nt go to the specified element on to attribute. And with router-link I can styling the active link easly:
.router-link-exact-active.menuItem-active-link{
background-color: cyan;
}
Have you any idea to solve this problem ?
This should work
<router-link :to="{ hash: '#users' }">{{ $t('navigation.users') }}</router-link>
Similar to this answer.

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)

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.

How to add the 'exact' prop in a v-for loop

I am trying to figure out how to add the exact property to the root link in a dynamically loaded menu. The menu entries are loaded from a REST API.
Currently the root path is always matched since it does not contain the exact property. In similar examples the root link is hard coded which I want to avoid.
This is the route that should be matched exactly
{ path: '/', component: HomePage }
The router-link is part of the menu, which is loaded via axios from the REST API and mapped to the state, including the root link "/". How can I access only this one item in the for loop to add the exact property?
<router-link tag="li" class="link" v-for="item in menu" v-bind:key="item.id" :to="item.slug">{{ item.content }}</router-link>
May be I am missing something, or there is a better way to achieve this?
Many thanks
Conditionally bind the exact prop like this.
<router-link tag="li" class="link" v-for="item in menu" :key="item.id" :to="item.slug" :exact="item.slug === '/' ? true : false">
{{ item.content }}
</router-link>
Have you ever try
<router-link tag="li" class="link" v-for="item in menu" v-bind:key="item.id" :to="item.slug" v-bind={ "exact": item.slug === "/" ? true : false }>{{ item.content }}</router-link>

bootstrap vue all b-dropdown-item with router link are active

I'm really enjoying Vue and Bootstrap Vue - very nice. However, one small issue - here's my template:
<template>
<div >
<b-dropdown variant="link" size="lg" no-caret>
<template slot="button-content">
<img src="../assets/logo.png">
</template>
<div v-for="row in navOptions" :key="row.id">
<b-dropdown-item v-bind:to="row.url" >{{ row.text }}</b-dropdown-item>
</div>
<b-dropdown-item>User</b-dropdown-item>
</b-dropdown>
</div>
</template>
The generated html for the items in the v-for loop is:
<a data-v-6949e825="" href="/xxxx/map" class="dropdown-item active" role="menuitem" target="_self">Map</a>
My problem is the "active" that is added to the class, it looks poor:
and isn't relevant as the items are not active.
I have the same issue with <b-nav-item>
Is there bootstrap vue way to disable 'active'?
You can do something like this:
<router-link to="/" tag="li" active-class="active" exact><a>Home</a></router-link>
This is going to create an tag with the active property and is going to change on the bases of the route.
If you are creating nested routes like /something/somethingelse is order to add the active class at /something li you need to add the exact property
For me does not work. The solution that worked for me:
<b-dropdown-item :to="{ path: '/new-task' }">New Task</b-dropdown-item>
More here: https://github.com/bootstrap-vue/bootstrap-vue/issues/3066#issuecomment-491258662