1

I'm not sure what I've done wrong here. Trying to display user name after they login on the toolbar for the dashboard but when trying to call the interface that I created called UserDetails, the browser console says that name of UserDetails is undefined. I made sure that UserDetails is imported from my other file.

I have my component ts file here

import { Component, OnInit } from "@angular/core";
import {
  BreakpointObserver,
  BreakpointState,
  Breakpoints
} from "@angular/cdk/layout";
import { Observable } from "rxjs";
import {
  AuthenticationService,
  UserDetails
} from "../auth/authentication.service";

@Component({
  templateUrl: "./portal.component.html",
  styleUrls: ["./portal.component.scss"]
})
export class PortalComponent {
  details: UserDetails;

  isHandset: Observable<BreakpointState> = this.breakpointObserver.observe(
    Breakpoints.Handset
  );
  constructor(
    private breakpointObserver: BreakpointObserver,
    private auth: AuthenticationService
  ) {}

  ngOnInit() {
    this.auth.profile().subscribe(
      user => {
        this.details = user;
      },
      err => {
        console.error(err);
      }
    );
  }
}

and my component template here

<mat-sidenav-container>
  <mat-sidenav
    #drawer
    mode="side"
    opened
    fixedInViewport="true"
    [attr.role]="isHandset ? 'dialog' : 'navigation'"
    [mode]="(isHandset | async)!.matches ? 'over' : 'side'"
    [opened]="!(isHandset | async)!.matches"
  >
    <span><h1>Maersk</h1></span>
    <mat-divider></mat-divider>
    <mat-nav-list>
      <ul>
        <li>
          <a routerLink="/portal/dashboard">
            <button mat-flat-button color="accent">
              DASHBOARD
            </button>
          </a>
        </li>
        <li>
          <a routerLink="/portal/orders">
            <button mat-flat-button color="accent">
              ORDERS
            </button>
          </a>
        </li>
        <li>
          <a routerLink="/portal/stats">
            <button mat-flat-button color="accent">
              STATISTICS
            </button>
          </a>
        </li>
      </ul>
    </mat-nav-list>
  </mat-sidenav>
  <mat-sidenav-content>
    <mat-toolbar>
      <mat-toolbar-row>
        <button
          type="button"
          aria-label="Toggle sidenav"
          mat-icon-button
          (click)="drawer.toggle()"
          *ngIf="(isHandset | async)!.matches"
        >
          <mat-icon aria-label="Side nav toggle icon">menu</mat-icon>
        </button>
        <span class="right-align"></span>
        <button mat-button [matMenuTriggerFor]="menu">
          {{ details.name }}
        </button>
        <mat-menu #menu="matMenu">
          <a (click)="auth.logout()">
            <button mat-menu-item>
              LOGOUT
            </button>
          </a>
        </mat-menu>
      </mat-toolbar-row>
    </mat-toolbar>
    <router-outlet></router-outlet>
  </mat-sidenav-content>
</mat-sidenav-container>

The console keeps spitting out "ERROR TypeError: Cannot read property 'name' of undefined". Don't know why it's not finding details in the component ts file.


UPDATE:

Posting some more code after finding that details itself comes up as undefined. This is my call to profile() from authentication.service.ts

public profile(): Observable<any> {
    return this.request("get", "profile");
  }

and then this is request() which gets called in profile()

private request(
    method: "post" | "get",
    type: "login" | "register" | "profile",
    user?: TokenPayload
  ): Observable<any> {
    let base;

    if (method === "post") {
      base = this.http.post("http://localhost:3000" + `/api/${type}`, user);
    } else {
      base = this.http.get("http://localhost:3000" + `/api/${type}`, {
        headers: { Authorization: `Bearer ${this.getToken()}` }
      });
    }

    const request = base.pipe(
      map((data: TokenResponse) => {
        if (data.token) {
          this.saveToken(data.token);
        }
        return data;
      })
    );

    return request;
  }

Also, just in case, here are a few more methods that get called in request()

private saveToken(token: string): void {
    localStorage.setItem("mean-token", token);
    this.token = token;
  }

  private getToken(): string {
    if (!this.token) {
      this.token = localStorage.getItem("mean-token");
    }
    return this.token;
  }

Everything from here was working fine when it came to logging a user in.

1 Answer 1

2

Use the safe navigation operator inside button (where name is displayed) like below,

<button mat-button [matMenuTriggerFor]="menu">
    {{ details?.name }}
</button>
Sign up to request clarification or add additional context in comments.

5 Comments

That got the error to go away from the console but I still don't see the user's name come up on the tool bar. Am I right in calling details?.name ?
On Subscribing to profile, console.log(this.details). What is the console printing? Please check
Hmm, it comes up as undefined. That explains undefined when calling name.
Then check the profile() method in AuthenticationService
Profile method gets called when logging in console. I'm starting to think that this might be a problem with the backend? I updated my post with some code from my methods

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.