I have 2 issues with my ngx bootstrap navbar that will no doubtably be fixed with the same solution. My navbar has two different toggles separated with an ng-container whether the user is logged in or not. I created my navbar using the example in the docs
Now the issue I am having is the not logged in view does not have enough items for it to collapse when the screen size is reduced, so instead of it being a dropdown it is just a narrowed version.
not logged in full screen navbar:
not logged in small screen navbar:
now this could be bearable if it wasn't for the logged in version having much more nav links that get added in at log in. But when they get added in while the window is small the navbar doesn't collapse it just remains narrow (and actually goes off screen)
small screen then log in
when logged in, the navbar works correctly as intended for full screen and after logging in then reducing the screen size
logged in full screen
logged in small screen - closes into just a hamburger menu icon
However if the user is already logged in on page load in a small screen (tested with a hardcoded variable) then the navbar is collapsed correctly to be the hamburger menu/dropdown list. (I don't want to refresh the page as it defeats the purpose of having an angular app).
And what is even more interesting is if the user logs out while in the small screen then the navbar stays in its collapsed state.
So what I want is the navbar to go into that state while logged out.
template:
<nav ngxNavbarDynamicExpand class="navbar navbar-expand-lg">
<button class="navbar-toggler" type="button" (click)="collapse.toggle()">
<span><fa-icon [icon]="hamburger"></fa-icon></span>
</button>
<div class="container-fluid">
<ngx-navbar-collapse #collapse="ngxNavbarCollapse">
<a class="navbar-brand abs" href="https://example.com/">
<img width=auto
height="30px"
src="example.png"
alt=""
loading="lazy"sizes="(max-width: 1595px) 100vw, 1595px">
</a>
<ul class="navbar-nav me-auto mb-2 mb-md-0">
<li class="nav-item">
<a class="nav-link" routerLink="/" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="/about" routerLinkActive="active">About</a>
</li>
</ul>
<ng-container *ngIf="(accountService.loggedIn$ | async); else notLoggedIn">
<div class="dropdown" dropdown>
<button class="dropdown-toggle text-light transparent-button ml-2" dropdownToggle>Admin</button>
<div class="dropdown-menu mt-3" *dropdownMenu>
<a routerLink="/" class="dropdown-item">1</a>
</div>
</div>
<div class="dropdown" dropdown>
<button class="dropdown-toggle text-light transparent-button ml-2" dropdownToggle>Manage</button>
<div class="dropdown-menu mt-3" *dropdownMenu>
<a routerLink="/userdetails" class="dropdown-item">My details</a>
</div>
</div>
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" routerLink="/install" routerLinkActive="active">Install</a>
</li>
<li class="nav-item">
<button class="btn btn-primary"
routerLink="/"
(click)="logout()"
role="button">
<span class="d-none d-md-inline">Logout</span>
<fa-icon [icon]="faPowerOff" [classes]="['ml-md-2']"></fa-icon>
</button>
</li>
</ul>
</ng-container>
<ng-template #notLoggedIn>
<ul class="navbar-nav">
<li class="nav-item">
<button class="btn btn-primary"
routerLink="/login"
role="button">
<span class="d-none d-md-inline">Login/Register</span>
<fa-icon [icon]="faUser" [classes]="['ml-md-2']"></fa-icon>
</button>
</li>
</ul>
</ng-template>
</ngx-navbar-collapse>
</div>
</nav>
typescript:
import { Component, OnInit } from '#angular/core';
import { faPowerOff, IconDefinition, faBars, faUser } from '#fortawesome/free-solid-svg-icons';
import { AccountService } from '../services/account.service';
#Component({
selector: 'app-nav',
templateUrl: './nav.component.html',
styleUrls: ['./nav.component.css']
})
export class NavComponent implements OnInit {faPowerOff: IconDefinition = faPowerOff;
hamburger: IconDefinition = faBars;
faUser: IconDefinition = faUser;
constructor(public accountService : AccountService) { }
ngOnInit(): void {
}
logout(){
this.accountService.logout();
}
}
Related
This is a similar question to How can I make navbar items with vue-router-links to toggle the navbar? but I am not allowed to comment there, and the solution given doesn't work me anyway.
I am using Vue 3 and Bootstrap 5 and the following code works exactly as the standard Bootstrap code does i.e. toggling the hamburger menu opens and closes the menu but clicking a link does nothing (other than correctly route to the page being clicked, meaning user has to then tap hamburger menu again to close)
NavBar component:
<template>
<nav class="navbar navbar-dark bg-dark navbar-expand-sm">
<div class="container-fluid">
<router-link class="navbar-brand" to="/">Birch Farm</router-link> |
<button class="navbar-toggler" type="button"
:class="visible ? null : 'collapsed'"
data-bs-toggle="collapse"
data-bs-target="#navContent"
aria-controls="navContent"
:aria-expanded="visible ? 'true' : 'false'"
#click="visible = !visible"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navContent">
<ul class="navbar-nav ms-auto mb-2 mb-lg-0">
<li class="nav-item active">
<router-link class="nav-link px-3" active-link="active" to="/" #click="visible = !visible">Home</router-link>
</li>
<li class="nav-item">
<router-link class="nav-link px-3" to="/camping" #click="visible = !visible">Camping & Caravanning</router-link>
</li>
<li class="nav-item">
<router-link class="nav-link px-3" to="/fishing" #click="visible = !visible">Cat Rough Fishery</router-link>
</li>
<li class="nav-item">
<router-link class="nav-link px-3" to="/contact" #click="visible = !visible">Contact Us</router-link>
</li>
</ul>
</div>
</div>
</nav>
</template>
<script setup>
import {ref} from 'vue'
const visible = ref(false);
</script>
<script>
export default {
name: "NavBar",
created() {},
data() {},
props: {},
methods: {},
components: {}
};
</script>
<style lang="scss" scoped></style>
Not having any of the 'visible' stuff works exactly the same way - this was added when trying the solution given in the above link.
"toggling the hamburger menu opens and closes the menu but clicking a link does nothing (other than correctly route to the page being clicked"
That's how the Bootstrap Navbar works. It doesn't collapse/hide automatically after clicking a link. Normally you'd have to do something like this to close the Navbar after clicking a link.
But when using Vue you would toggle the collapse class as needed on the navbar-collapse div using your visible value...
<div class="navbar-collapse" :class="!visible?'collapse':''" id="navContent">
Demo: https://codeply.com/p/lHTzN4amfe
You have to follow this guide if you are using bootstrap via NPM. As long as I see, the way to use it is different in Angular or React, for example.
In addition to that, if you want to use bootstrap in your project and set it up the easiest way possible, is to use the CDN, I will show you how:
In your main layout, inside the head tag, put this:
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
And inside your body tag, this:
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/js/bootstrap.bundle.min.js"></script>
I had the same issue, bootstrap (5.1.3) and Vue (3.2.36). So I installed bootstrap-vue-3 (0.1.13) and use and to make it work.
Also without "navbar-light bg-light) the hamburger icon didn't appear at first.
Hope this helps.
<template>
<nav class="navbar navbar-expand-lg fixed-top navbar-light bg-light">
<div class="container-fluid">
<RouterLink class="navbar-brand" to="/">
<img class="logo" src="../assets/svg/logo.svg" />
</RouterLink>
<b-button
v-b-toggle.collapse-1
variant="primary"
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#menuItems"
aria-controls="menuItems"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</b-button>
<b-collapse id="collapse-1" class="mt-2 collapse navbar-collapse">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<RouterLink class="nav-link" to=" /">home </RouterLink>
</li>
<li class="nav-item">
<RouterLink class="nav-link" to=" /something"
>something
</RouterLink>
</li>
<li class="nav-item">
<RouterLink class="nav-link" to="/about"
>about
</RouterLink>
</li>
</ul>
<form class="d-flex">
<input
class="form-control me-2"
type="search"
placeholder="Search"
aria-label="Search"
/>
<button class="btn btn-outline-success" type="submit">
Search
</button>
</form>
</b-collapse>
</div>
</nav>
I changed data-toggle to data-bs-toggle and data-target to data-bs-target and it worked.
My main.js(main entry file) has this
...
import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap";
...
I found a tweak in this other thread for Vue 3 / Bootstrap 5 / vue-router :
How to hide collapsible Bootstrap navbar on click
Adding a simple span tag around menu label and inside li / routerling worked for me:
<div class="collapse navbar-collapse" id="navigation">
<ul class="navbar-nav me-auto mb-2 mb-sm-0">
<li class="nav-item">
<RouterLink class="nav-link" to="/"><span data-bs-target="#navigation" data-bs-toggle="collapse">Menu 1</span></RouterLink>
</li>
<li class="nav-item">
<RouterLink class="nav-link" to="/ventes.html"><span data-bs-target="#navigation" data-bs-toggle="collapse">Menu 2</span></RouterLink>
</li>
</ul>
I hope it helps!
I thought to share my workaround/solution for this specific issue.
Do not use the router-link component, rather trigger the navigation manually via the push method in vue-router by handling the click event in vue.
This allows for a "static" layout of the HTML so that you can preserve the functionality in Bootstap which allows for controlling the collapsing of the navbar via data attributes.
In order to trigger the active navigation style you can use class binding in vue and the route.name value from vue-router. It would also work with the path given slight modification.
Here is a basic example:
<script setup>
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
const route = useRoute()
const navigate = name => router.push({ name })
</script>
<template>
<div class="container">
<span class="navbar-brand">EXAMPLE NAVBAR</span>
<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">
<li class="nav-item">
<span :class="['nav-link', route.name === 'camping' ? ' active' : '']"
role="button"
data-bs-toggle="collapse"
data-bs-target="#navbarNavAltMarkup"
#click="navigate('camping')">CAMPING</span>
</li>
<li class="nav-item">
<span :class="['nav-link', route.name === 'fishing' ? ' active' : '']"
role="button"
data-bs-toggle="collapse"
data-bs-target="#navbarNavAltMarkup"
#click="navigate('fishing')">FISHING</span>
</li>
</div>
</div>
</div>
</template>
<li class="nav-item mx-1">
<NuxtLink class="btn nav-button nav-text" to="/eventi">
<span data-bs-target="#navbarSupportedContent" data-bs-toggle="collapse">Servizi</span>
</NuxtLink>
</li>
I solved adding a span tag with data-bs-target="#navbarSupportedContent" and data-bs-toggle="collapse" around the name of the links (in my case they are NuxtLink but I think works either with Router-link)
So I want to hide the navbar while in a mobile view state. The navbar was created on a seperate component. Here is my admin.component.html like here:
<div *ngIf="!isMobile">
<div class="admin-container">
<!-- sidebar -->
<nav class="col-2 d-md-block sidebar collapse">
<div class="sidebar-sticky pt-3">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link" routerLink="/admin/dashboard"> Dashboard </a>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="/admin/orders"> Orders </a>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="/admin/adminProduct"> Products </a>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="/admin/reports"> Reports </a>
</li>
</ul>
</div>
</nav>
<!-- content -->
<div class="admin-content p-3">
<div
class="d-flex justify-content-end align-items-center pb-2 mb-2 border-bottom"
>
<form novalidate #loginForm="ngForm" (ngSubmit)="logout()">
<button type="submit" class="btn btn-juliet mt-3">Logout</button>
</form>
</div>
<router-outlet></router-outlet>
</div>
</div>
</div>
<div *ngIf="isMobile">
<div class="admin-container">
<!-- sidebar -->
<nav class="col-2 d-md-block sidebar collapse">
<div class="sidebar-sticky pt-3">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link" routerLink="/admin/dashboard"> Dashboard </a>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="/admin/orders"> Orders </a>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="/admin/adminProduct"> Products </a>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="/admin/reports"> Reports </a>
</li>
</ul>
</div>
</nav>
<!-- content -->
<div class="admin-content p-3">
<div
class="d-flex justify-content-end align-items-center pb-2 mb-2 border-bottom"
>
<form novalidate #loginForm="ngForm" (ngSubmit)="logout()">
<button type="submit" class="btn btn-juliet mt-3">Logout</button>
</form>
</div>
<router-outlet></router-outlet>
</div>
</div>
</div>
Here is the admin.component.ts
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../auth.service';
import { Router } from '#angular/router';
import { NavbarService } from '../services/navbar.service';
import { RibbonService } from '../services/ribbon.service';
import { ResponsiveService } from 'src/app/services/responsive.service';
import { FooterService } from '../services/footer.service';
#Component({
selector: 'app-admin',
templateUrl: './admin.component.html',
styleUrls: ['./admin.component.css'],
})
export class AdminComponent implements OnInit {
public isMobile: boolean;
constructor(
private authService: AuthService,
public nav: NavbarService,
public ribbon: RibbonService,
public footer: FooterService,
private router: Router,
private responsive: ResponsiveService,
) {}
ngOnInit(): void {
this.nav.hide();
this.ribbon.hide();
this.footer.hide();
this.onResize();
this.responsive.checkWidth();
}
logout() {
this.authService.clear();
this.router.navigate(['home']);
}
onResize() {
this.responsive.getMobileStatus().subscribe((isMobile) => {
this.isMobile = isMobile;
this.nav.hide();
});
}
}
And my app.component.html
<app-ribbon></app-ribbon>
<app-navbar></app-navbar>
<div class="app-body" (window:resize)="onResize()">
<router-outlet></router-outlet>
</div>
<app-footer></app-footer>
I tried applying *ngIf on the admin.component.html but the navbar won't go away. Thanks for the future answers!
In the mobile Version the navbar is not collapsing... Can somebody help?
I copy the source from bootstrap but it didn't work. Do I forget something?
In the index.html, I have input the css and js file.
I dont also receive any errors.
import React from 'react'
import Logo from "../img/logo_large.png"
// React Font awesome imports
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faBars } from "#fortawesome/free-solid-svg-icons"
//React-scroll install
//Navbar
const Navbar = () => {
return (
<nav className="navbar navbar-expand-lg navbar-light bg-dark fixed-top">
<div className="container">
{/*Logo variable von oben*/}
<a className="navbar-brand" href="#home"><img className="Logo" src={Logo} /> </a>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<FontAwesomeIcon icon={faBars} style={{ color: "#fff" }} />
</button>
<div className="collapse navbar-collapse" id="navbarSupportedContent">
<ul className="navbar-nav ml-auto">
<li className="nav-item active">
<a className="nav-link" href="#about" >About Me<span className="sr-only">(current)</span></a>
</li>
<li className="nav-item">
<a className="nav-link" href="#services">Services</a>
</li>
<li className="nav-item">
<a className="nav-link" href="#experiences">Experiences</a>
</li>
<li className="nav-item">
<a className="nav-link" href="#abilities">Abilities</a>
</li>
<li className="nav-item">
<a className="nav-link" href="#blog">Blog</a>
</li>
<li className="nav-item">
<a className="nav-link" href="#freetime">Freetime</a>
</li>
<li className="nav-item">
<a className="nav-link" href="#contact">Contact</a>
</li>
</ul>
</div>
</div>
</nav >
)
}
export default Navbar
In fact you have copied the elements, which seems to be a react code, not pure html. The bootstrap slogan is "mobiles first", so they are ready to small screens out of the box, you don't need at first time create a different code for that.
In order to make bootstrap work properly, you have to add the pure html bootstrap elements and bootstrap resources: js and css files at least.
Your start point can be this: https://getbootstrap.com/docs/5.0/getting-started/introduction/#starter-template where you have already a "Starter template" with those dependencies done.
After that, you can go to https://getbootstrap.com/docs/5.0/components/navbar/ and copy the html code and experiment if it works.
Make sure that you've included the appropriate bootstrap CSS and JS CDN in your link and script. It seems to me that you're using bootstrap yet you did not include it in your tags.
In app.component.html, I have a top menu bar which contains 3 links
named as Home, About and contactus.
If I click a home link then I should show leftmenubar of Home page(Home.component.html)
If I click about link then I should show leftmenubar of About page(About.component.html)
so my question is "How to access the Home page, about page divs i.e leftmenubar from my main page(app.component) image button click.
app.component.html
<nav class="navbar navbar-dark bg-dark mb-5">
<img src="src/assets/images/ham1.png" (click)="ShowLeftMenubar();">
<div class="navbar-nav">
<a class="nav-item nav-link" routerLink="homepage">Home</a>
<a class="nav-item nav-link active" routerLink="aboutpage">ABOUT</a>
<a class="nav-item nav-link active" routerLink="contactpage">CONTACTUS</a>
</div>
</nav>
<router-outlet></router-outlet>
Home.component.html
<div id="leftmenubar" class="leftmenuclass">
<a routerLink="showcontent">sample1 </a>
<a routerLink="showcontent">sample2 </a>
<a routerLink="showcontent">sample3 </a>
</div>
aboutpage.component.html
<div id="leftmenubar" class="leftmenuclass">
<a routerLink="showcontent">sample3 </a>
<a routerLink="showcontent">sample4 </a>
<a routerLink="showcontent">sample5 </a>
</div>
Create a Subject in a service myservice.service.ts as follows:
In your myservice.service.ts
public sidebar$ = new Subject<boolean>();
In your app.component.ts, import the myservice in the constructor then create a flag as follows:
public isShowMenu = true;
constructor(private myservice: MyService){}
When the user clicks the image
ShowLeftMenubar() {
this.isShowMenu = !this.isShowMenu;
this.myservice.sidebar$.next(this.isShowMenu);
}
In your home.component.ts and about.component.ts, you should listen for the Subject using subscribe method inside the ngOnInit
public isShowSidebar = false;
constructor(private myservice: MyService){}
ngOnInit() {
this.myservice.sidebar$.subscribe((value) => this.isShowSidebar = value);
}
In home.component.html and about.component.html
<div *ngIf="isShowSidebar" id="leftmenubar" class="leftmenuclass">
<a routerLink="showcontent">sample1 </a>
<a routerLink="showcontent">sample2 </a>
<a routerLink="showcontent">sample3 </a>
</div>
I am creating a single page website using Angular 2 and Bootstrap 4.
I created a navbar component that is always on top of the page and I am using page anchor navigation (#id). Please note that I haven't created a routing module (so far it hasn't been necessary to do this).
The navbar code is below:
<nav class="navbar navbar-default fixed-top navbar-inverse navbar-toggleable-md">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggler navbar-toggler-right btn btn-outline-secondary" (click)="isCollapsed = !isCollapsed" [attr.aria-expanded]="!isCollapsed" aria-controls="collapseExample">
<i class="fa fa-bars" aria-hidden="true"></i>
</button>
<a class="navbar-brand" href="index.html">Garatéa</a>
</div>
<div id="collapseExample" class="navbar-collapse collapse" [ngbCollapse]="isCollapsed">
<ul class="nav navbar-nav ml-auto">
<li class="nav-item"><a class="nav-link" href="#home">Início</a></li>
<li class="nav-item"><a class="nav-link" href="#about">Sobre</a></li>
<li class="nav-item"><a class="nav-link" href="#team">Quem Somos</a></li>
<li class="nav-item"><a class="nav-link" href="#contact">Contato</a></li>
</ul>
</div>
</div>
</nav>
Each link corresponds to a section of the single page website, for example, the home component template is:
<div id="home" class="text-center home-background">
<div class="overlay">
<div class="content">
<h1>Bem vindo à <strong><span class="title-text">Garatéa</span></strong></h1>
<p class="lead">Somos uma inciativa que <strong>aumenta a taxa de sobrevivência</strong> em emergências médicas.</p>
</div>
</div>
</div>
My question is: how can I highlight the link in the navbar that corresponds to the section of the website that I am currently browsing? For example, if I am looking at the team about section, I expect to have an active CSS class on the navbar: <li class="nav-item active"><a class="nav-link" href="#about">Sobre</a></li>.
You can use the srcElement on click of that <a> tag as below
<a class="nav-link" (click)="clickedLink($event)">Início</a>
<a class="nav-link" (click)="clickedLink($event)">Início</a>
<a class="nav-link" (click)="clickedLink($event)">Início</a>
Method will be as
clickedLink(e){
let element = e.srcElement;
console.log(e)
for(let i =0; i <element.parentElement.children.length ; i++){
if(element.parentElement.children[i].classList.contains('active')){
element.parentElement.children[i].classList.remove('active')
}
}
element.classList.add('active');
}
LIVE DEMO