Add Active class for multiple routes in Angular - html

I have a side bar which has multiple option in it.I set routerLinkActive class to make particular option active when click but now if I go deeper or other route from that route,the active class is being removed.I wanted to stay one option active for multiple routes.
My HTML code is as per below.
<div class="nav-list">
<ul class="listing" >
<li routerLinkActive="active" [routerLinkActiveOptions]="{exact: true }" >
<a [routerLink]="['/']" (click)="disableOptions()" >
<i class="fas fa-archive"></i> Projects
</a>
</li>
<li routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }" [class.disabled]="isDisabled==true">
<a [routerLink]="['/notebooks']" [style.pointer-events]="isDisabled ? 'none' : 'auto'" >
<i class="fas fa-book"></i> Notebooks
</a>
</li>
<li routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }" [class.disabled]="isDisabled==true" >
<a [routerLink]="['/files']" [style.pointer-events]="isDisabled ? 'none' : 'auto'">
<i class="fas fa-file-alt"></i> Files
</a>
</li>
<li routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }" [class.disabled]="isDisabled==true">
<a [routerLink]="['/screens']" [style.pointer-events]="isDisabled ? 'none' : 'auto'">
<i class="fas fa-desktop"></i>Screen
</a>
</li>
<li routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }" [class.disabled]="isDisabled==true">
<a [routerLink]="['/slides']" [style.pointer-events]="isDisabled ? 'none' : 'auto'">
<i class="fas fa-photo-video"></i> Slides
</a>
</li>
</ul>
</div>
As you can see in first image the route is ['/'] so the active class working fine but in second image the route is ['project/create'] so that the active class is not showing.I want to keep active class for both routes .Please help me to solve this issue.Thank you
My route file is like this.
const routes: Routes = [{
path: '',
component: PagesComponent,
canActivate: [AuthGaurdService],
children: [{
path: '',
component: ProjectListingComponent,
}, {
path: 'slides',
component: ScreenListingComponent,
}, {
path: 'project',
loadChildren: './multi-step-form/multistepform.module#MultistepformModule',
}, {
path: 'project/slide/create',
component: AddEditScenarioComponent
},
{
path: 'project/slide/edit',
component: DragDropToolScenarioComponent
},
{
path: 'notebooks',
component: NotebookListingComponent
},
{
path: 'screens',
component: ScreenTableComponent
},
{
path: 'files',
component: FileListingComponent
},
{
path: 'screens/create',
component: ScreenCreateComponent
},
{
path: 'files/create',
component: FileCreateComponent
},
{
path: 'notebook/create',
component: NotebookCreateComponent
}
]
}];
['project/create'] is in multistepform component which has its own routing file.

You can use nested routing for it. For example define your routes as
routes: Route[] = [
{ path: '', component: PagesComponent, children: [
{ path: 'project', component: ProjectComponent, children: [
{ path: 'slide/create', component: CreateProjectComponent }
]}
]}
];
And then you can have a <router-outlet> inside the PagesComponent and the ProjectComponent. The routerLinkActive will then react to the project/** route in the PagesComponent so it does not matter what follows. The routerLinkActive in the ProjectComponent will then be active for project/slide/create or whatever you route to. And I think you do not need the routerLinkActiveOptions.

Related

Lazy loading route remains unchanged even after passing id

Library is the parent component. In Home page, when I click on Library icon, I am led to Library page with URL localhost:4200/library, which is expected. In Library page, there's list of books. When I click on a book, I am led to book details of the selected book. However, the URL still remains localhost:4200/library which I would like to change to localhost:4200/library/book/selected-book-id.
Here's my attempt at it. The problem is the URL still remains localhost:4200/library, I would really appreciate some guidance.
library.routing.module.ts
const routes: Routes = [
{
path: '',
pathMatch: 'full',
component: LibraryComponent
},
{
path: '**',
redirectTo: ''
},
{
path: 'library/book/:selectedBookId',
component: BookComponent
}
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class LibraryRoutingModule {}
library-list.component.html
<div content class="content">
<scroll-viewer
class="library-list"
>
<mat-list data-custom-parent-group="LibraryList" data-custom-parentid="library-list">
<div class="loading" *ngIf="!ready">
<waiting-spinner
[size]="waitingSpinnerSize.Medium"
></waiting-spinner>
</div>
<ng-container *ngIf="ready">
<mat-list-item role="listitem" *ngFor="let book of library" style="margin-bottom: 2rem;height: auto;">
<button
mat-raised-button
class="menu-button"
[routerLink]="['/', 'library', '/', 'book', '/', book.id]"
routerLinkActive="active"
[ngClass]="{
unknown: true,
valid: false,
warning: false,
issue: false
}"
(click)="selectBook(book)"
[attr.data-custom-name]="book.id"
[attr.data-custom-name]="book.name"
[attr.data-custom-bhvr]="'Book'">
<div style="display: flex;place-content: space-between;align-items: center;line-height: 7rem;">
<div style="display: flex;">
<div class="book-subitem">
<div class="book-element">
<div class="book-name">Book: </div>
</div>
</div>
</div>
</div>
</button>
</mat-list-item>
<router-outlet></router-outlet>>
</ng-container>
</mat-list>
</scroll-viewer>
<mat-paginator #paginator class="paginator" [length]="resultsLength" [pageSize]="pageLength" [pageSizeOptions]="[5, 10, 25, 50, 100]" (page)="updatePage($event)"></mat-paginator>
</div>
</daui-layout-filter>

Passing variable into [icon] for Font Awesome not working

I am using Font Awesome with Angular.
I want to loop through some data via *ngFor to create icons in a navigation bar. However, the [icon] is not accepting the values from the variable.
Component HTML
<div class="navbar-container container" [ngClass] = "expanded ? 'navbar-collapsed': ''">
<div class="navbar-logo-container">
<button class="logo" (click)="toggleCollapsed()">
A
</button>
<div class="logo-text" *ngIf="expanded">My Site</div>
</div>
<ul class="navbar-nav">
<li class="navbar-nav-item" *ngFor="let data of navData">
<a class="navbar-nav-link" [routerLink]="[data.routeLink]">
//works
<fa-icon [icon]="['fas','star']"></fa-icon>
//Error: Type 'string' is not assignable to type 'IconProp'.
<fa-icon [icon]="data.iconfull"></fa-icon>
// Type 'string' is not assignable to type 'IconProp'.
<fa-icon [icon]="[data.iconfirst,data.iconsecond]"></fa-icon>
<span class="navbar-link-text" *ngIf="expanded">{{data.label}}</span>
</a>
</li>
</ul>
</div>
Data
export const navbarData = [
{
routeLink: 'dashboard',
iconfirst: 'fas',
iconsecond: 'star',
iconfull: "['fas','star']",
label: 'Dashboard'
}
]
Cannot reproduce the third scenario.
From IconProp,
export type IconProp = IconName | [IconPrefix, IconName] | IconLookup;
Hence, for the second scenario,
Specify the navbarData type as:
import {
IconProp,
IconPrefix,
IconName,
} from '#fortawesome/fontawesome-svg-core';
navbarData: {
routeLink: string;
iconfirst: IconPrefix;
iconsecond: IconName;
iconfull: IconProp;
label: string;
}[] = [
{
routeLink: 'dashboard',
iconfirst: 'fas',
iconsecond: 'star',
iconfull: ['fas', 'star'],
label: 'Dashboard',
},
];
Sample Demo on StackBlitz

What is the right way to create recursive dynamic expanding nav in angular, and how to toggle its menu item properly?

I have an Angular 8 app I'm working on. I'm using boostrap 4 layout in my application. What I have created yet is a menu which having some nested menu items. I'm following Dynamic Expanding Nav Drawer example to create a dynamic expanding navbar.
The issue which I'm facing is when I click on my (1st Level / Parent) menu item it expands all nested menu items, which I want to prevent.
Below code I've tried:
<div class="row">
<div *ngTemplateOutlet="recursiveMenu; context:{ $implicit: navItems }"></div>
<ng-template #recursiveMenu let-menus>
<ul class="w-100">
<li *ngFor="let menu of menus;">
<a class="align-self-stretch text-left" href="#" title="{{menu.displayName}}" (click)="onItemSelected(menu)">
<i class="fa {{menu.iconName}}"></i> <span class="nav-header-primary p-2">{{menu.displayName}}</span>
<span *ngIf="menu.children" class="fa fa-caret-down fa-2x pull-right" [#indicatorRotate]="expanded ? 'expanded': 'collapsed'">
</span>
</a>
<ul *ngIf="menu.children && expanded" id="nav{{menu.id}}">
<ng-container *ngTemplateOutlet="recursiveMenu; context:{ $implicit: menu.children }"></ng-container>
</ul>
</li>
</ul>
</ng-template>
</div>
Kindly helpHere is a code stackblitz output. Let me know where I'm doing wrong.
All you sub menu items are getting expanded when you expand parent item, as you are maintaining a common/single flag for checking whether the menu is in expanded state or not.
So when you expand a parent item the expanded flag is set to true and all your menu items are also getting expanded.
so instead of maintaining a common flag you can maintain a flag for each item, in map.
You can add a id property in your menu list:
navItems: INavItem[] = [
{
id: 1,
displayName: 'Home',
iconName: 'fa-home fa-lg p-2',
route: 'home'
},
{
displayName: 'Settings',
id: 2,
iconName: 'fa-cog',
children: [
{
displayName: 'Navigation Management',
iconName: 'fa-sliders',
id: 3,
children: [
{
displayName: 'Navigation & Form Mapping',
id: 4,
iconName: 'fa-handshake-o',
route: 'navigation-form-mapping'
}]
}]
}]
You can maintain use expanded as a map of key-value pairs, in update your onItemSelected function as:
onItemSelected(item: INavItem) {
if (item.children && item.children.length) {
this.expanded[item.id] = !this.expanded[item.id];
}
}
And your html can be updated as:
<span *ngIf="menu.children" class="fa fa-caret-down fa-2x pull-right" [#indicatorRotate]="expanded[menu.id] ? 'expanded': 'collapsed'">
</span>
<ul *ngIf="menu.children && expanded[menu.id]" id="nav{{menu.id}}">
<ng-container *ngTemplateOutlet="recursiveMenu; context:{ $implicit: menu.children }"></ng-container>
</ul>
Working Demo

How to select between an actual routerLink and an internal anchor with Angular 8?

I have an array of items, which looks like this:
nav: any = [
{
name: 'Homepage',
url: 'homepage'
internal: false
},
{
name: 'Section 1',
hash: 'section-1'
internal: true
},
];
Now I need to ouput a list of a-elements. These should either contain a routerLink if internal is false – or they should become an internal anchor. I've tried:
<a class="link"
*ngFor="for item of nav"
[href]="item.internal ? '#' + item.hash : null"
[routerLink]="item.internal ? null : item.url">
{{ item.title }}
</a>
This renders homepage correctly, but Section 1 comes out wrongly:
<a class="link" href="/homepage">Homepage</a>
<a class="link" href="/">Section 1</a>
This is what I actually want:
<a class="link" href="/homepage">Homepage</a>
<a class="link" href="#section-1">Section 1</a>
How to achieve this correctly?
Try this...
<a class="link" *ngFor="for item of nav" [routerLink]="item.internal ? '#' + item.hash : item.url">
{{ item.title }}
</a>
The routerLink replaces by href after render.
why not conditionally, use one or the other?
<ng-container *ngIf="internal">
show appropriate link
</ng-container>
<ng-container *ngIf="!internal">
show appropriate link
</ng-container>

Create full menu based on Json file

I have a fully functional menu (static), as im going to post, i want to replicate it based on what i get from a json file, i mean, create menu based on json file.
heres what i want as a menu:
html:
<div class="menu-container" >
<div class="menu">
<nav class="navbar-toggleable-md">
<div id="toggle" class="navbar-toggler"><a></a>
</div>
</nav>
<ul id="my_styles" class="rowcenter" >
<li>
<a role="button" class="button button4 menu-button" ><i role="button" class="icon-ambientais fs1 icon menu-button"></i><span class="button-text rowcenter menu-button">menu1</span></a>
<ul class="menu-list">
<li>
<i style="color: white" class="icon-ambientais fs1"></i>submenu
<ul>
<li>{{ 'submenu</li>
<li>submenu</li>
<li>{{ 'Imagens' | translate }}</li>
</ul>
</li>
<li>
<i style="color: white" class="icon-gestao-ambient fs1"></i>submenu3
<ul>
<li>submenu2</li>
<li>submenu2</li>
<li>submenu2</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
i have javascript to make it work.
I was searching for some help, because i cant figute it out..
i found that example, but i can't make it look like what i need.
https://www.codeproject.com/Articles/311758/Building-Menu-from-JSON
(passing the json obj to json file)
but i can't make it work like the menu i have.. if i change, for example, <ul> to <ul class="bla"> on this one, it breaks.
then i found that: Creating a Menu from JSON
but no success..
heres my trying code:
on html i just call
my typescript file:
.ts
ngOnInit() {
this._menu.getMenu()
.subscribe( res => {
let data = res;
console.log(data);
var getMenuItem = function (itemData) {
var item = $("<li>")
.append(
$("<a>", {
href: itemData.link,
html: itemData.name
}));
if (itemData.sub) {
var subList = $("<ul>");
$.each(itemData.sub, function () {
subList.append(getMenuItem(this));
});
item.append(subList);
}
return item;
};
var $menu = $("#menu");
$.each(data.menu, function () {
$menu.append(
getMenuItem(this)
);
});
$menu.menu();
});
}
had somebody done something like this before?
if someofyou have a working example with one menu item and submenu, even without img, i would appreciate it.
thank you.
Ok i got the solution!
Having al lthe css and html done, i've just got the JSON file to array that way:
this._menu.getMenu()
.subscribe( res => {
let data = res;
console.log(data);
this.arr = data;
this.arr = (<any>Object).values(data);
});
Then, on html i just picked the menus and sub menus names / links / icons, and ngfor them into the already made tags:
<li *ngFor="let item of arr[0]; let i = index;">
<a role="button" class="button button4 menu-button" ><i role="button" class={{item.class}}></i><span class="button-text rowcenter menu-button">{{item.name}}</span></a>
<ul class="menu-list" *ngIf=item.sub>
<li *ngFor="let sub of item.sub; let j = index;">
<i style="color: white" class={{item.sub[j].class}}></i>{{item.sub[j].name}}
<ul *ngFor="let smn of sub.submenu; let x = index;">
<li>{{smn.name}}</li>
</ul>
</li>
</ul>
</li>
heres the JSON i've used:
{
"menu": [
{
"name": "Menu Name",
"link": "link",
"class": "icon-ambientais fs1 icon menu-button",
"sub": [{
"name": "SubMenuTitle1",
"link": "link",
"class": "icon-ambientais fs1",
"submenu":[{
"name": "SubMenu1",
"routerlink": "/link/Qld"
},{
"name": "SubMenu2",
"routerlink": "/link/eQld"
},{
"name": "SubMenu3",
"routerlink": "/link/aQld"
}
]
},
{
"name": "SubMenuTitle2",
"link": "link",
"class": "icon-gestao-ambient fs1",
"submenu":[{
"name": "SubMenu1",
"routerlink": "/link2/oQld"
},{
"name": "SubMenu2",
"routerlink": "/doc/eQld"
}
]
}
]
}
}
Hope that helps somebody on the futurue