1

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 class="navbar__items" *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>

1 Answer 1

1

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);
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

This worked perfectly, thank you. So any canges that are done during component loading can be captured by ngOnChanges.
not every change, Only when Input (also known as data-bound properties) value changes, those are captured by ngOnChanges

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.