Bulma navbar and VueJS router active link - vuejs2

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>

Related

Vue Replace Navbar With Router

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.

Nested routes don't follow the defined pattern. VUEjs

I'm facing a new issue with nested routes. I've 2 levels of nested routes, and they're not working correctly.
Here are the routes object:
import Login from './components/auth/Login.vue';
import Dashboard from './components/dashboard/Dashboard.vue';
import Signup from './components/auth/Signup.vue';
import Home from './components/shared/Home.vue';
import ProductsHome from './components/dashboard/Products/ProductsHome.vue';
import ProductOverview from './components/dashboard/Products/ProductsOverview.vue';
import CreateProduct from './components/dashboard/Products/CreateProduct.vue';
import CreateCategory from './components/dashboard/Category/CreateCategory.vue';
import EditCategory from './components/dashboard/Category/EditCategory.vue';
import {store} from './store/store.js';
export const routes = [
{path: '/', component: Home},
{ path: '/login', component: Login },
{ path: '/registrarse', component: Signup },
{
path: '/dashboard',
component: Dashboard,
name: 'dashboard',
beforeEnter: (to, from, next) => {
if(to.name === 'dashboard') {
if(store.state.User.credentials.tokenId === null) {
next('/');
//TODO, Hacerlo global y verificar que el dashboard y sus hijos no accedan.
} else {
next();
}
}
next();
},
children: [
{
path: 'productosHome',
component: ProductsHome,
children: [
{
path: '',
component: ProductOverview
},
{
path: 'crearProducto',
component: CreateProduct
},
{
path: 'crearCategoria',
component: CreateCategory
},
{
path: 'editarCategorias',
component: EditCategory
}
]
}
]
}
];
The thing is with the dashboard. When I enter the dashboard or any of its sub-routes (with its router-link component) they don't follow the proper URL path. For example: If a visit the 'productosHome' the URL it's just '/productosHome' and not '/dashboard/productosHome. This same problem applies for every productosHome's child route.
Now, let me show to you my templates:
Dashboard.vue
<template>
<div>
<div class="container is-fluid has-background-light">
<h1 class="title has-text-centered pt-3">Dashboard</h1>
</div>
<section class="section py-3 has-background-light prueba section-dashboard">
<div class="container is-fluid remove-padding dashboard">
<aside class="nav-aside has-background-white">
<div>
<!--El anchor sera nuestro router-link-->
<!-- aside-link-active -->
<a href="#" class="aside-link">
<span class="icon">
<i class="fas fa-users"></i>
</span>
<span class="aside-link-text">Clientes</span>
</a>
</div>
<div>
<router-link class="aside-link"
active-class="aside-link-active"
to="productosHome">
<span class="icon">
<i class="fas fa-tags"></i>
</span>
<span class="aside-link-text">Productos</span>
</router-link>
</div>
<div>
<a href="#" class="aside-link">
<span class="icon">
<i class="fas fa-boxes"></i>
</span>
<span class="aside-link-text">
Pedidos
</span>
</a>
</div>
</aside>
<div class="main-content has-background-white">
<router-view></router-view>
</div>
</div>
</section>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.aside-link.aside-link-active:hover {
color: white;
}
</style>
ProductsHome.vue
<template>
<div>
<div class="tabs is-medium pt-2 mb-0">
<ul>
<!-- is-active -->
<router-link to="crearProducto"
active-class="is-active"
tag="li">
<a>Crear</a>
</router-link>
<li><a>Editar</a></li>
<li><a>Buscar</a></li>
<router-link to="crearCategoria"
active-class="is-active"
tag="li">
<a>| Crear categoría</a>
</router-link>
<router-link to="editarCategorias"
active-class="is-active"
tag="li">
<a>Editar categoria</a>
</router-link>
</ul>
</div>
<div class="main-content__content block p-2">
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
Note that Products Home also have children.
Also, I'm debugging routes with the famous Vue plugin and see what says:
'/' is marked has active, Is that correct?
I'm confused :D
The routes file is correct. The issue is with the router link on both files. there are 2 ways you can define router-link>to.
Absolute / Relative Path.
Absolute Path(From any file)
<router-link to="/dashboard/productosHome/">Products Home</router-link>
Relative Path(From dashboard page)
<router-link to="productosHome">Products Home</router-link>
Route object. (From any file)
<router-link :to="{ path: `/dashboard/productosHome/`}">Products Home</router-link>
No 2 gives you a bit more control. you can now name the route and use them. Like you did for dashboard main route. name: 'dashboard',. Now you can name the subroute.
{
path: 'crearProducto',
component: CreateProduct,
name: 'crearProducto'
},
router link will be
<router-link :to="{ name: 'crearProducto'}">Crear Producto</router-link>
Check Documentation for more https://router.vuejs.org/api/#to
When declaring paths in the to attribute of router-link, you need to define the full path including the root "/". E.g.: "/dashboard/productosHome"

Vue how to customize global navbar at view level

Im super new to Vue.
i have a Vue-CLI app, which have a navbar and content.
Navbar is common to all pages, but i want to customize in each page whit some additional content.
Example:
Common-> home | about
View home -> home | about | your are in view home
View about -> home | about | your are in view about
router/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
import NavBar from '#/components/NavBar.vue';
Vue.use(VueRouter);
Vue.component('nav-bar', NavBar);
//...
components/navbar.vue
<template>
<div>
<b-nav-item to="/">home</b-nav-item>
<b-nav-item to="/about">about</b-nav-item>
{{customContent}}
</div>
</template>
<script>
export default {
name: 'NavBar',
props: {
customContent: {
type: String,
default: 'default Content',
},
},
};
</script>
App.vue
<template>
<div id="app">
<nav-bar />
<div class="container-fluid">
<router-view />
</div>
</div>
</template>
views/home.vue
<template>
<div class="row">
<div class="col-12">
<image-card :images="images"/>
</div>
</div>
</template>
<script>
//how can i customize here the navbar by adding for example 'your are in view home'???
</script>
Thanks so much!
There are a few ways in which you can solve this problem. I'll list two of them.
1. Update NavBar by $route
In this approach, the NavBar component already contains all of the possible combinations, and will display the relevant portion(s) depending on what $route contains.
Here's some pseudo code:
navbar.vue
<template>
<div class="navbar">
<div class="navbar-left>
APPNAME
</div>
<div v-if="name === 'landing'">
...
</div>
<div v-else-if="name === 'room'">
...
</div>
</div>
</template>
App.vue
<template>
<div id="app">
<NavBar :name="$route.name"/>
<main>
<router-view/>
</main>
</div>
</template>
In this example, the NavBar component is very rigid, and doesn't really lend itself to much reuse. However, it does encapsulate all the relevant code relating to the nav bar.
2. Extensible NavBar with slots
In this approach, the NavBar only provides the bare-minimum to create a nav bar. The rest of the route-specific elements are to be filled in by the views.
navbar.vue
<template>
<div class="navbar">
<div class="navbar-left">
<div class="navbar-brand">
APPNAME
</div>
<slot name="left"></slot>
</div>
<div class="navbar-right">
<slot name="right"></slot>
</div>
</div>
</template>
App.vue
<template>
<div id="app">
<router-view/>
</div>
</template>
landing.vue
<template>
<div>
<header>
<NavBar>
<template slot="right">
<span>
<div class="navbar-item">
<div class="buttons">
<button class="button" #click="...">Start Watching</button>
</div>
</div>
</span>
</template>
</NavBar>
</header>
<main>
...
</main>
</div>
</template>
This approach has a bit of repetition in terms of DOM elements, but gives you an extremely flexible NavBar that can be customized by each view.
The approach you want to use depends on what is important to you.
If strict encapsulation is what you want, then you may want to use approach 1, as all of the NavBar-related code is contained within a single file.
However, if you believe that there is a potential for reuse, or if you would like all view-related code to live in one place, then it makes sense to use slots instead and extend the NavBar as required by each view.
I use a breadcrumb to achieve a similar thing. Just an idea but Vue router allows you to add meta data to the current route which you always have access to
router.js
path: '/add',
name: 'add',
component: () => import(/* webpackChunkName: "add" */ '../../views/Add.vue'),
meta: {
breadCrumb: [
{ name: 'Add New' }
]
},
Notice the meta object attached to the route.. this will be used to describe the current view.
Breadcrumb.vue component
<template>
<div class="breadcrumb">
<ul class="d-flex m-0 p-0"
<li
v-for="(breadcrumb, idx) in breadcrumbList"
:key="idx">
{{ breadcrumb.name }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Breadcrumb',
data () {
return {
breadcrumbList: []
}
},
mounted () { this.updateList() },
watch: { '$route' () { this.updateList() } },
methods: {
routeTo (pRouteTo) {
if (this.breadcrumbList[pRouteTo].link) this.$router.push(this.breadcrumbList[pRouteTo].link)
},
updateList () { this.breadcrumbList = this.$route.meta.breadCrumb },
formatPath(path) {
const newPath = path.replace(/\//g, " > ")
return newPath
}
}
}
</script>
And then you can import the breadcrumb into your navbar or where ever you would like to place it
<Breadcrumb class="breadcrumb" />
import Breadcrumb from '#/components/Breadcrumb.vue'
components: {Breadcrumb}
So basically the breadcrumb will always watch your current route and change the data based on the meta data you provide in your router.js file
You can access to router name like this:
<div v-if="this.$route.name == 'home'">
<HeaderTransparent />
</div>
<div v-else>
<HeaderWhite />
</div>

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.

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
})