Vue Replace Navbar With Router - vue.js

Vue newbie here. With the out-of-box default app created by Vue-CLI, including Vue Router, you have the top navbar with the Home and About links. What I want is: when you click on the About link, instead of updating the content below the navbar, it will update the entire page i.e. making the navbar disappear.
In App.vue:
<template>
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view />
</template>
The router is set-up in router/index.js as:
import { createRouter, createWebHashHistory } from "vue-router";
import Home from "../views/Home.vue";
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/about",
name: "About",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ "../views/About.vue"),
},
];
const router = createRouter({
history: createWebHashHistory(),
routes,
});
export default router;
This is to simulate a typical login page where you often don't get navbar.
I played with nested routers but no luck. I'm using Vue 3.

I solved this by extracting the nav links into its own component, and only display the nav links on the pages that need it. This means in the sign-up page I do not include the nav links.
So after creating the default Vue-CLI starting app, I removed the nav components:
<template>
<!-- <div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> |
<router-link to="/signin">Sign In</router-link>
</div> -->
<router-view />
</template>
And created a new Nav.vue component:
<template>
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> |
<router-link to="/signin">Sign In</router-link>
</div>
</template>
Added the Nav component to the pages where I want the nav to show, e.g. Home.vue:
<template>
<Nav />
<div class="home">
<img alt="Vue logo" src="../assets/logo.png" />
<HelloWorld msg="Welcome to Your Vue.js App" />
</div>
</template>
I do not include the nav in my sign-in:
<template>This is the SIGN IN page - note there is no navigation links.</template>
Being a Vue noob, not sure if the above is the best approach, but it is working for now.

Related

Vue subrouting with navbar and sidebar

I'm trying to set up a routing system with vue. For my purpose, I need a fixed navbar on the top that needs to be displayed on every page and a sidebar that I want to display only on the settings page. Following the documentation I tried:
const routes = [
{
path: '/settings',
name: 'Settings',
component: Settings,
children: [
{
path: 'route1',
name: 'Route1',
component: Route1
},
{
path: 'route2',
name: 'Route2',
component: Route2
}
]
}
]
Then on the settings template:
<template>
<div class="flex items-start">
<div class="lg:w-3/12 w-12 sm:w-16 md:w-24 pb-10 lg:pr-8">
<Sidebar />
</div>
</div>
<div class="lg:w-9/12 w-full pt-10 pb-8 text-justify">
// My subroute goes here
</div>
</template>
I feel that I'm missing something. First, I can't understand how to properly display the subroutes. I tried with <router-view /> but it seems to refer to the parent navigation.
Second, I don't want the user to visit the /settings route but only /settings/route1 and settings/route2.
I can achieve this by simply adding the sidebar in every settings route but this seems bad because it forces the <Sidebar/> component to be mounted every time
Where am I wrong?
Thanks
As you probably have guessed, the <router-view /> element goes in your Settings component:
<template>
<div class="flex items-start">
<div class="lg:w-3/12 w-12 sm:w-16 md:w-24 pb-10 lg:pr-8">
<Sidebar />
</div>
</div>
<div class="lg:w-9/12 w-full pt-10 pb-8 text-justify">
<router-view /> <!-- Here is your router view -->
</div>
</template>
Then as it was pointed out in the comments, /settings will always be a valid route.
What you can do when the client directly navigates to /settings is to replace the current route with one of the two children (possibly based on some logic) in the mounted hook:
mounted() {
if(this.$router.currentRoute.path.endsWith('/settings')) {
this.$router.replace('/settings/route1')
}
}
Or use $router.push() instead based on what you want the navigation history to look like.

Set up router for subpages in Vue.js

I wounder how I best set up the router in Vue.js for handling ”subpages”. For example I got a navbar that routes to different pages. From one of these pages I want to have links to subpages. How do I best set this up?
I have done like this so far:
App.js
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view />
</div>
</template>
Then I set up my router:
export default new Router({
routes: [
{
path: "/",
name: "home",
component: Home
},
{
path: "/about",
name: "about",
component: About,
children: [
{
path: "/child1",
name: "child1",
component: Child1
}
]
}
]
})
And my About.vue where I provide the link to Child1
<template>
<div class="about">
<h1>This is an about page</h1>
<router-link to="/child1">Child1</router-link>
<router-view></router-view>
</div>
</template>
And finally my Child1.vue
<template>
<div class="child1">
<p>My message</p>
</div>
</template>
My problem is that the link to Child1 is displayed both on the About page and on Child1 page. I just want to display it on the about page and only the content from the Child1 on the Child1 page
How is the best practice of setting up things like this?
Thanks
My problem is that the link to Child1 is displayed both on the About page and on Child1 page. I just want to display it on the about page
Just to clarify what's happening here: the link to Child1 is always visible within the About component even if child routes are active, but you don't want to show the link when the child route is active.
Way 1
You can provide fallback content to <router-view> when there is no matching route (i.e. when no child route is active). This would be a good opportunity to show the link.
<template>
<div class="about">
<h1>This is an about page</h1>
<router-view>
<router-link to="/child1">Child1</router-link>
</router-view>
</div>
</template>
Way 2
The above solution may not work if your template is more complicated and if you want to situate the link elsewhere in the template.
So you'll have to manually control the visibility of the link by using v-if so that it is only visible when the child route is not active.
<template>
<div class="about">
<h1>This is an about page</h1>
<!-- Show only when no child routes are active -->
<router-link v-if="$route.name === 'about'" to="/child1">Child1</router-link>
<!-- Or, do not show when Child1 route is active -->
<router-link v-if="$route.name !== 'child1'" to="/child1">Child1</router-link>
<router-view></router-view>
</div>
</template>

vue-router: How to use view-router in more than one element?

A very simple example for using a vue-router in template is the following code:
<template>
<div id="app">
<router-view/>
</div>
</template>
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
}
]
})
what I understand is that the content of router-view will be switched by the relevant component to the path.
However, if I have a template with more than one element affected by router. For example,
<template>
<div id="app">
<h1> header </h1>
<router-view 1/>
<h1> Inner </h1>
<router-view 2/>
<h1> Footer </h1>
</div>
</template>
and let's say that router-view 1 and router-view 2 both can get different components based on the path.
In this case, how would you recommend me to use router?
Based on official doc, you have to use named-views.
Like that, you can have multiple router-view rendering differents components for the same path.
With your example, it becomes :
<template>
<div id="app">
<h1> header </h1>
<router-view /> // this will be the default
<h1> Inner </h1>
<router-view name="inner"/>
<h1> Footer </h1>
</div>
</template>
and your router will look like :
// Don't forget your imports
const router = new VueRouter({
routes: [
{
path: '/',
components: {
default: HeaderComponent, // Will render in default router-view
inner: InnerComponent // Will render in router-view named "inner"
}
}
]
})
More complex layouts are also describes in the official doc.

Bulma navbar and VueJS router active link

I've started using Bulma 0.7.1 and VueJs 2.5.17. Now, I'm using Vue router component and I'd like to make the buttons in the navigation bar to be set as active whenever I'm on the "page" represented by the link.
My code is the following
<template>
<div id="app">
<nav class="navbar" role="navigation" aria-label="main navigation" id="nav">
<div class="container">
<div id="navMenu" class="navbar-menu">
<div class="navbar-end">
<a class="navbar-item is-active">
<router-link to="/" exact>Home</router-link>
</a>
<a class="navbar-item">
<router-link to="/about" exact>About</router-link>
</a>
<a class="navbar-item">
<router-link to="/project" exact>Project</router-link>
</a>
</div>
<div class="navbar-end">
</div>
</div>
</div>
</nav>
<router-view/>
</div>
</template>
I know that router component uses class router-link-active to mark the active link. But Bulma probably requires the is-active class applied to the current button.
How should I automate this? I've read that probably I should bind the class is-active to the router-link-active, but I tried:
let routes = ...
new VueRouter({
mode: "history",
routes,
linkActiveClass: "is-active"
});
And did not worked.
Any hint is really appreciated.
You are on the right track and are right, 'is-active' is the answer. In router add.
export const router = new VueRouter({
mode: 'history',
routes,
linkActiveClass: 'is-active'
})
And construct your HTML like.
<nav class="navbar is-white">
<div class="container">
<div id="navMenu"
class="navbar-menu">
<div class="navbar-start">
<router-link :to="{ name: 'templateInfo' }"
class="navbar-item">Template info</router-link>
<router-link :to="{ name: 'thirdpartylibraries' }"
class="navbar-item">Third party libraries</router-link>
</div>
</div>
</div>
</nav>
This works for me so I guess there's some issue with the order of your div's or classes.
Check Bulma Guide, is-active is one modifier, you have to use it together with bulma element.
Most Bulma elements have alternative styles. To apply them, you only
need to append one of the modifier classes. They all start with is- or
has-.
So change the configuration to like linkActiveClass: 'tag is-active' it will work well.
Like below demo which uses tag (you can choose others like box, button etc):
let UserView = Vue.component('user', {
template: '<div>I am User</div>'
})
let AdminView = Vue.component('admin', {
template: '<div>I am Admin</div>'
})
const router = new VueRouter({
linkActiveClass: 'tag is-active',
routes: [
{
path: '/Admin',
name: 'Admin',
component: AdminView
},
{
path: '/User',
name: 'User',
component: UserView
}
]
})
Vue.use(VueRouter)
app = new Vue({
el: "#app",
router
})
.loading {
background-color:red;
font-weight:bold;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css" rel="stylesheet"/>
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<h2>Test Vue Router</h2>
<router-link to="Admin">Admin</router-link>
<router-link to="User">User</router-link>
<router-view></router-view>
</div>

Why is my router-link tag not working with my bootstrap framework?

I am using vue.js to create a navigation task bar along with bootstrap for the frontend framework.
I configured the router in a router.js file I created.
router.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
//enter code here`import components
import levi from './containers/levi'
import product from './containers/product'
import price from './containers/price'
//application routes
const routes = [
{path: '/', component: levi },
{path: '/product', component: product },
{path:'/price', component: price }
]
//export router instance
export default new Router({
mode: 'history',
routes,
linkActiveClass:'is-active'
})
I created the containers with the files for the navigation bar.
price.vue
<template>
<div id = "price" >
What is the price!
</div>
</template>
<script>
export default{
name: 'price'
}
</script>
<style scoped>
</style>
product.vue
<template>
<div id = "product">
Understanding the levi product
</div>
</template>
<script>
export default {
name: 'product'
}
</script>
<style scoped>
</style>
The components folder has the navigation component
<template>
<div>
<div class="navbar navbar-default navbar-static-top">
<div class="container ">
levi
<button class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse" name="button">
<span class="navbar-toggle-Menu">Menu</span>
</button>
<div class="collapse navbar-collapse"></div>
</div>
</div>
</div>
</template>
This div section contains the router-link tags that are not working properly
<div class="nav navbar-nav navbar-right">
<router-link to='/product'> product </router-link>
</div>
end tag for the router-link
<template></template>
<script>
export default {
name : 'navigation'
}
</script>
<style scoped = "true">
</style>
All the initial navigation links are no longer showing when I surround them with the router-link. How can I fix this?
You need to pass the instance of your router to your main Vue instance like so:
//your router is declared as default in its own file so
//in your main Vue instance...
import router from './my_router'
new Vue({
el: '#app',
router
})