ngAfterContentInit hook doesn't work as expected

I have an Angular app with navigation bar. This navbar has 2 states - for logged in users and for users that are not logged yet. My goal is to change this navbar state via *ngIf statement and ng-template block so logged in user can see his name and avatar. This part works fine, except that user's data doesn't load if I use ngAfterContentInit hook, but it works as it should if I use ngDoCheck or ngAfterViewChecked hooks. These solutions don't suit me because they cause too much requests to the backend, and I need only one request after user logs in to set his data. Here is HTML part just for reference:

<nav *ngIf="subscr | async as auth; else elseBlock" class="navbar navbar-expand-lg navbar-dark bg-dark sticky-top">
  <div class="img-logo-block">
    <img class="navbar-brand" src="assets/static/img/logo.svg" alt="Logo" (click)="gt_myprofile()">
  </div>
  <div class="container">
    <div class="collapse navbar-collapse navmenu" [ngClass]="{ 'show': navbarOpen }" id="navbarSupportedContent">
      <ul class="navbar-nav">
        <li class="nav-item sub">
          <a class="nav-link unselectable" (click)="gt_myprofile()"><span
              class="icon icon-profile"></span> profile
          </a>
        </li>
        <li class="nav-item sub">
          <a class="nav-link unselectable" routerLink="/contacts" routerLinkActive="nav-link-active"><span
            class="icon icon-contacts"></span>
            contacts
          </a>
        </li>
      </ul>
  <div ngbDropdown class="profile">
    <a class="nav-dropdown dropdown-toggle" id="dropdownBasic1" ngbDropdownToggle>
      {{user?.first_name}}
      <img *ngIf="!user?.avatar;else userAvatar" src="assets/static/img/avatar.jpg" class="nav-avatar">
      <ng-template #userAvatar><img src="{{user?.avatar}}" alt="" class="nav-avatar"></ng-template>
    </a>
    <div ngbDropdownMenu aria-labelledby="dropdownBasic1">
      <a ngbDropdownItem class="profile-dropdown-link" (click)="gt_myprofile()">profile</a>
      <a ngbDropdownItem class="profile-dropdown-link" (click)="gt_allContacts()">Contacts</a>
      <a ngbDropdownItem class="profile-dropdown-link" (click)="gt_settings()">settings</a>
    </div>
  </div>
</nav>

<ng-template #elseBlock>
  <nav class="navbar navbar-expand-lg navbar-dark bg-dark sticky-top">
      <div class="collapse navbar-collapse" [ngClass]="{ 'show': navbarOpen }" id="navbarSupportedContent">
        <ul class="navbar-nav mr-auto">
          <li class="nav-item">
            <a class="nav-link" routerLink="/about" routerLinkActive="nav-link-active">about<span class="sr-only">(current)</span></a>
          </li>
          <li class="nav-item">
            <a class="nav-link" routerLink="/cooperation" routerLinkActive="nav-link-active">cooperation</a>
          </li>
        </ul>
        <!-- end navbar-nav -->
        <div class="search-form">
          <a class="nav-link" (click)="notif_on()" (click)="home()">Логин</a>
        </div>
      </div>
    </div>
  </nav>
</ng-template>

And TS component relevant part:

ngOnInit() {
  this.subscr = this.auth_service.currentUser;
}

this hook works

ngAfterViewChecked() {
    // check if user is logged in
  if (localStorage.getItem('currentUser') !== null) {
    this.auth_service.getUser().subscribe(
      data => {this.user = data}
      );
  }
}

and this doesn't

ngAfterContentInit() {
    // check if user is logged in
  if (localStorage.getItem('currentUser') !== null) {
    this.auth_service.getUser().subscribe(
      data => {this.user = data}
      );
  }
}

Auth service relevant part:

  private currentUserSubject: BehaviorSubject<User>;
  public currentUser: Observable<User>;

  constructor(private http: HttpClient) {
    this.currentUserSubject = new BehaviorSubject<User> 
  (JSON.parse(localStorage.getItem('currentUser')));
    this.currentUser = this.currentUserSubject.asObservable();
  }

  public get currentUserValue(): User {
    return this.currentUserSubject.value;
  }

login(email: string, password: string) {
  return this.http.post<any>(`${environment.apiUrl}/api/auth/`, { email, password })
    .pipe(map(user => {
      // store user details and jwt token in local storage to keep user logged in between page refreshes
      localStorage.setItem('currentUser', JSON.stringify(user));
      this.currentUserSubject.next(user);
      this.currentUser = this.currentUserSubject.pipe(filter(value => !!value)).asObservable();
      return user;
    }));
}

logout() {
  // remove user from local storage to log user out
  localStorage.removeItem('currentUser');
  this.currentUserSubject.next(null);
}

Any help and tips would be appreciated.

Upvotes: 2

Views: 347

Answers (1)

Ashot Aleqsanyan
Ashot Aleqsanyan

Reputation: 4453

After the meeting, finally I could understand what is the problem.

service code

  // stored current user info
  // tslint:disable-next-line: variable-name
  private _user: User = JSON.parse(localStorage.getItem('currentUser'));
  // current user subject
  currentUserSubject: BehaviorSubject<User> = new BehaviorSubject(this.user);

  // get current userInfo
  get user() {
    return this._user;
  }
  
  // set user info
  set user(user: User) {
    this._user = user;
    if (this._user) {
      localStorage.setItem("currentUser", JSON.stringify(this.user));
    } else {
      localStorage.removeItem("currentUser");
    }

    this.currentUserSubject.next(this.user);
  }

  get userChanges() {
    return this.currentUserSubject.asObservable();
  }

  login(email: string, password: string) {
    return this.http.post<any>("", { email, password }).pipe(
      map(user => {
        // store user details and jwt token in local storage to keep user logged in between page refreshes
        this.user = user;
        return this.user;
      })
    );
  }

  logout() {
    this.user = null;
  }


  getUser(id: number = this.user.id) {
    return this.http.get<any>((`${environment.apiUrl}/api/user/${id}`));
  }

Navbar component code

ngOnInit() {
  this.auth_service.userChanges.pipe(filter(user => !!user)).subscribe(user => {
     this.auth_service.getUser(user.id).subscribe(
        data => {this.user = data}
      );
  });
}

template code

<nav *ngIf="user; else elseBlock" class="navbar navbar-expand-lg navbar-dark bg-dark sticky-top">

Upvotes: 1

Related Questions