Search code examples
angularangular-router

Angular 4 dynamic routerlink server/localhost not responding. Works when routerlink is static


I am attempting to create a dynamic navigation menu based on a navigation menu service and a navigation menu component.

First I prototyped the navigation menu to make sure it worked when the component HTML is hardcoded. That code looks like this:

<nav>
  <md-list>
    <md-list-item routerLinkActive="link-active">
      <a [routerLink]="['/users']">
        <md-icon>people</md-icon><span *ngIf="navigationMenuService.getStatus() == navigationMenuService.navigationMenuStatuses.IconsAndLabels">Users</span>
      </a>
    </md-list-item>
    <md-list-item routerLinkActive="link-active">
      <a [routerLink]="['/patients']">
        <md-icon>hotel</md-icon><span *ngIf="navigationMenuService.getStatus() == navigationMenuService.navigationMenuStatuses.IconsAndLabels">Patients</span>
      </a>
    </md-list-item>
    <md-list-item routerLinkActive="link-active">
      <a [routerLink]="['/studies']">
        <md-icon>library_books</md-icon><span *ngIf="navigationMenuService.getStatus() == navigationMenuService.navigationMenuStatuses.IconsAndLabels">Studies Dashboard</span>
      </a>
    </md-list-item>
    <md-list-item routerLinkActive="link-active">
      <a [routerLink]="['/exampleselect']">
        <md-icon>library_books</md-icon><span *ngIf="navigationMenuService.getStatus() == navigationMenuService.navigationMenuStatuses.IconsAndLabels">Example Select list</span>
      </a>
    </md-list-item>
  </md-list>
</nav>

When I run the application with this code and click one of the links the application successfully navigates and the selected route as specified by the routerLink attribute is loaded into the router outlet.

I am trying to modify the above code to use ngFor to generate the list based on the navigationMenuService. I have tried several different bits of code the most recent of which is:

<nav>
  <md-list>
    <md-list-item routerLinkActive="link-active" *ngFor="let menuItem of navigationMenuService.getNavigationMenuItems()">
      <a [routerLink]="['/'+menuItem.route]">
        <md-icon>{{menuItem.iconName}}</md-icon><span *ngIf="navigationMenuService.getStatus() == navigationMenuService.navigationMenuStatuses.IconsAndLabels">{{menuItem.label}}</span>
      </a>
    </md-list-item>

  </md-list>
</nav>

These appear to work in that if you hover over them the link looks like the correct link, but upon clicking them....things break. Rather than successfully navigating and loading the page into the router outlet I get a "localhost is not responding" error.

The navigationMenuService looks like this:

import { Injectable } from '@angular/core';
import { NavigationMenuItem } from '../../models/NavigationMenuItem';

@Injectable()
export class NavigationMenuService {
    public navigationMenuStatuses = NavigationMenuStatus;
    private navigationMenuStatus: NavigationMenuStatus;

    constructor() {
        this.navigationMenuStatus = NavigationMenuStatus.Hidden;//start with the navigation menu closed.
    }

    getNavigationMenuItems(): NavigationMenuItem[] {
        return [
        {
            iconName: "library_books",
            label: "Studies",
            route: "studies"
        },
        {
            iconName: "library_books",
            label: "Example Select",
            route: "exampleselect"
        }];
    }

    getStatus(): NavigationMenuStatus {
        return this.navigationMenuStatus;
    }

    setStatus(status: NavigationMenuStatus) {
        this.navigationMenuStatus = status;
    }

    //toggles visibility of labels. If status is currently hidden this method has no effect.
    toggleLabels() {
        if (this.navigationMenuStatus == NavigationMenuStatus.Icons) {
            this.navigationMenuStatus = NavigationMenuStatus.IconsAndLabels;
        }
        else if (this.navigationMenuStatus == NavigationMenuStatus.IconsAndLabels) {
            this.navigationMenuStatus = NavigationMenuStatus.Icons;
        }
    }
}

export enum NavigationMenuStatus {
    Hidden,
    Icons,
    IconsAndLabels
}

In case it is relevant, this application uses Angular 4.3.6, Webpack and HMR with @angular/platform-server and @angular/platform-browser modules.


Solution

  • I can make this do what I want by adding a navigateToItem method on the navigationMenuService and updating the HTML as follows:

    //Created by Devon Holcombe, September 2017
    import { Injectable } from '@angular/core';
    import { NavigationMenuItem } from '../../models/NavigationMenuItem';
    import { ActivatedRoute, Router, Params } from '@angular/router';
    
    @Injectable()
    export class NavigationMenuService {
        public navigationMenuStatuses = NavigationMenuStatus;
        private navigationMenuStatus: NavigationMenuStatus;
    
        constructor(private router: Router) {
            this.navigationMenuStatus = NavigationMenuStatus.Hidden;//start with the navigation menu closed.
        }
    
        getNavigationMenuItems(): NavigationMenuItem[] {
            return [
            {
                iconName: "library_books",
                label: "Studies",
                route: "/studies"
            },
            {
                iconName: "library_books",
                label: "Example Select",
                route: "/exampleselect"
            }];
        }
    
        navigateToItem(menuItem: NavigationMenuItem) {
            this.router.navigateByUrl(menuItem.route);
        }
    
        getStatus(): NavigationMenuStatus {
            return this.navigationMenuStatus;
        }
    
        setStatus(status: NavigationMenuStatus) {
            this.navigationMenuStatus = status;
        }
    
        //toggles visibility of labels. If status is currently hidden this method has no effect.
        toggleLabels() {
            if (this.navigationMenuStatus == NavigationMenuStatus.Icons) {
                this.navigationMenuStatus = NavigationMenuStatus.IconsAndLabels;
            }
            else if (this.navigationMenuStatus == NavigationMenuStatus.IconsAndLabels) {
                this.navigationMenuStatus = NavigationMenuStatus.Icons;
            }
        }
    }
    
    export enum NavigationMenuStatus {
        Hidden,
        Icons,
        IconsAndLabels
    }
    <nav>
      <md-list>
        <md-list-item routerLinkActive="link-active" *ngFor="let menuItem of navigationMenuService.getNavigationMenuItems()">
          <a (click)="navigationMenuService.navigateToItem(menuItem)">
            <md-icon>{{menuItem.iconName}}</md-icon><span *ngIf="navigationMenuService.getStatus() == navigationMenuService.navigationMenuStatuses.IconsAndLabels">{{menuItem.label}}</span>
          </a>
        </md-list-item>
    
      </md-list>
    </nav>

    While this works it seems like there should be a way to do this using routerLink that I am missing.