Home > Net >  Parse Input to child component Angular
Parse Input to child component Angular

Time:08-30

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);
    }
}
  • Related