I'm tying to make a dynamic navbar with Angular materials.
The idea is to create a "template" of a navbar that could be re-used in future projects, however I'm facing a difficulty while trying to order my navbar components.
Let's say we have 4 components:
- 1 parent component (app-nav-bar)
- 3 child components (app-nav-bar-logo-image, app-nav-bar-logo-text, app-nav-bar-links)
What I would like to do is whenever I'm calling a parent component with specific agument only these components to appear, on the other hand I would like to be able to order those child components as I like. A simple representaion of an idea
For some reason the placeElementsInOrder() function sorts the array with default values (100, 101, 102) instead of the ones that I'm passing in the app.component.html.
How can I first pass the arguments to a component and after they are passed then to sort them based on their order?
app.component.html
<app-nav-bar
[logoIcon]="logo"
[logoText]="logoText"
[navigationOptions]="navigationOptions">
</app-nav-bar>
app.component.ts
logo = {
src: '../assets/images/logo.svg',
path: './home',
alternativeText: 'Logo',
order: 3
};
logoText = {
path: './home',
text: 'LOGO',
order: 2
};
menuItems = [
{ label: 'HOME', path: '#' },
{ label: 'ABOUT', path: '#' },
{ label: 'PROJECTS', path: '#' },
{ label: 'CONTACT', path: '#' }
];
navigationOptions = {
navigationMenuItems: this.menuItems,
order: 1
};
nav-bar.component.html
<mat-toolbar color="primary">
<mat-toolbar-row fxLayoutAlign="space-around center">
<ng-container *ngFor="let itemToAdd of listOfOrder">
...
</ng-container>
</mat-toolbar-row>
</mat-toolbar>
nav-bar.component.ts
export class NavBarComponent implements OnInit {
@Input() logoIcon: logoIconModel = {
src: '',
path: '',
alternativeText: '',
order: 100
};
@Input() logoText: logoTextModel = {
path: '',
text: '',
order: 101
}
@Input() navigationOptions: navigationMenuLinksModel = {
navigationMenuItems: [{
label: '', path: ''
} as navigationMenuItemModel
],
order: 102
}
constructor(){}
listOfOrder = placeElementsInOrder(this.logoIcon, this.logoText, this.navigationOptions);
ngOnInit(): void {}
}
function placeElementsInOrder(logoIcon: logoIconModel, logoText: logoTextModel, navigationOptions: navigationMenuLinksModel): Array<any> {
const listOfItems: any[] = [
{ order: logoIcon.order, type: 'logoIcon' },
{ order: logoText.order, type: 'logoText' },
{ order: navigationOptions.order, type: 'navMenuLinks' }
];
return listOfItems.sort( (a,b) => a.order - b.order );
}
nav-bar.models.ts
export interface logoIconModel {
src: string
path: string
alternativeText: string
order: number
}
export interface logoTextModel {
path: string
text: string
order: number
}
export interface navigationMenuItemModel {
label: string
path: string
}
export interface navigationMenuLinksModel {
navigationMenuItems: navigationMenuItemModel[]
order: number
}
nav-bar-logo-image.component.html
<a *ngIf="logoIcon" [routerLink]="logoIcon.path">
<img [src]="logoIcon.src" [alt]="logoIcon.alternativeText">
</a>
nav-bar-logo-text.component.html
<a *ngIf="logoText" [routerLink]="logoText.path">
{{logoText.text}}
</a>
CodePudding user response:
You need to run placeElementsInOrder
function on ngOnChanges
.
ngOnChanges
lifecycle hook runs when Input
value changes. Since you are already running the placeElementsInOrder
function when component loads it disregards the new values (coming from Input
) and use the default values you have in the component.
import { OnChanges, SimpleChanges } from '@angular/core';
export class NavBarComponent implements OnChanges
{
public ngOnChanges(changes: SimpleChanges): void
{
this.listOfOrder = this.placeElementsInOrder(this.logoIcon, this.logoText, this.navigationOptions);
}
}