7.10: Displaying Profile Photo in the NavBar

The next to modules are optional and are really a design decision. However, it is also a really good learning opportunity for passing data between components that isn't Parent -> Child or Child -> Parent.

Return UserForList DTO on Login

In our .API project - in the AuthService.cs file, let's modify the login method to make sure we're returning photos with the user:

public async Task<User> Login(string username, string password)
{
    var user = await _context.Users.Include(p => p.Photos).FirstOrDefaultAsync(x => x.Username == username);        //  <--- Added Include(p => p.Photos)

Now let's open up our old friend the AuthController.cs file.

We're going to map the user we're retrieving from the database to a UserForList DTO. We don't want to send back a full user because it has too much information.

Just before the return statement in the Login() method, add the following mapping and update the object in the return statent to also return a user:

var user = new UserForList
{
    Id = userFromDb.Id,
    Username = userFromDb.Username,
    Specialty = userFromDb.Specialty,
    Age = userFromDb.DateOfBirth.CalculateAge(),
    KnownAs = userFromDb.KnownAs,
    Created = userFromDb.Created,
    LastActive = userFromDb.LastActive,
    City = userFromDb.City,
    State = userFromDb.State,
    PhotoUrl = userFromDb.Photos.FirstOrDefault(p => p.IsMain).Url,
};

return Ok( new { tokenString, user });

Updating the AuthService in Angular

Add a property called currentUser, add the user item to local storage, and populate the currentUser property:

currentUser: User;

//  ...

login(model: any) {
    return this._http.post<AuthUser>(this.baseUrl + 'auth/login', model, { headers: new HttpHeaders()
      .set('Content-Type', 'application/json') })
      .map(user => {
        if (user) {
          localStorage.setItem('token', user.tokenString);
          localStorage.setItem('user', JSON.stringify(user.user));                      //  <--- Added
          this.decodedToken = this._jwtHelperService.decodeToken(user.tokenString);
          this.currentUser = user.user;                                                 //  <--- Added
          this.userToken = user.tokenString;
        }
      });
}

In order to load this information when the page loads, let's also update our root app.component.ts file:

export class AppComponent implements OnInit {
  constructor(
    private _authService: AuthService,
    private _jwtHelperService: JwtHelperService) {}

  ngOnInit() {
    const token = localStorage.getItem('token');
    const user: User = JSON.parse(localStorage.getItem('user'));

    if (token) {
      this._authService.decodedToken = this._jwtHelperService.decodeToken(token);
    }

    if (user) {
      this._authService.currentUser = user;
    }
}

When we logout - we also need to make sure that the user item from local storage is removed along with the token:

Open up nav.component.ts file and add the following:

logout() {
    this.authService.userToken = null;
    this.authService.currentUser = null;            //  <--- Added
    localStorage.removeItem('token');
    localStorage.removeItem('user');                //  <--- Added
    this._alertify.success('Logged out');
    this.router.navigate(['/home']);
}

Adding Profile Photo in the NavBar

In nav.component.html, edit the dropdown <div> to the following:

We'll also add some styling in nav.component.scss:

img {
    max-height: 50px;
    border: 2px solid white;
    display: inline;
}

Now, our profile page is displayed next to the dropdown when we're logged in. But, we're faced with a similar problem: if we change our profile picture - it is updated in the profile tab of our edit profile component - but, the change is not reflected in our navbar.

This is a little trickier since the NavBar is not a parent or a child component of our Photo Editor component. We'll see how to do it next.

Last updated