简体   繁体   中英

Why Angular child component ( navbar ) stops updating view after route change?

this is my first question on the platform, hope i do it right.

So, i'm working on a social network using MEAN stack and socket.io, and i'm trying to show the number of unviewed notifications and messages next to the icons. All the data is updated in the component by the sockets and i can see that all works fine in the console, data arrives in real time and updates the array which length i'm using to show the numbers on the navbar. Everything works fine and it updates the numbers in the view with no problem, BUT when i change the route (even if i come back to the same url) it stops updating the view, no matter the data still receiving and updating in console.

I've been days stuck with this, doing research, trying but i can't make it work. I've tried:

Using ChangeDetectionStrategy.OnPush combined with ChangeDetectionRef and its methods like markForCheck, detectChanges with async pipe.

Trying to re-render the component on route change without success.

ngZone but honestly i couldnt understand it so well.

So, i'm looking for some short explanation of what is happening and an idea of how can i could fix it. I know there's some very similar questions like this made before, and i'd checked them but couldn't apply them succesfully to my project. I hope someone can help me with this.

This is the navbar component:

import { Component, OnDestroy, OnInit} from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { UserService } from '../../services/user.service';
import { NotificationService } from '../../services/notification.service';
import { MessageService } from '../../services/message.service';
import { GLOBAL } from '../../services/global';
import { io } from 'socket.io-client';
import { Observable } from 'rxjs';
import { Message } from 'src/app/models/message';

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.scss'],
  providers: [ MessageService ]
})
export class NavbarComponent implements OnInit{
  private socket = io("ws://localhost:3000");
  public identity;
  public token;
  public url:string;
  public newNotifications$: Observable<boolean>;
  public myNotifications;
  public unviewedMessages: Message[];

  constructor(  public user: UserService,
                private _notificationService: NotificationService,
                private _messageService: MessageService,
                private _route: ActivatedRoute,
                private _router: Router
              ) { 
                this.identity = user.identity;
                this.unviewedMessages = [];
                this.token = user.getToken();
                this.url = GLOBAL.url;
                this.checkIfNewNotifications();
                this.checkUnviewedMessages();
              }
              
  ngOnInit(): void {
    this.sockets()
  }
  
  
  sockets(){
    this.socket.emit("addUser", this.identity._id);
    this.socket.on("newNotification", newNotification =>{
      this.checkIfNewNotifications();
      console.log("nueva notificacion")
    });
    this.socket.on("getMessage", msg =>{
      this.checkUnviewedMessages();
      console.log("nuevo mensaje")
    })   
  }

  logout(){
      localStorage.clear();
      this.identity = null;
      console.log();
      this._router.navigate(['/register']);     
  }

  toTop(event){
    window.scroll(0,0);
  }

  seeNotifications(){
    this.newNotifications$ = new Observable(observer=>observer.next(false));
    this.setViewedNotifications(this.token, this.identity._id);
  }

  checkIfNewNotifications(){
    this._notificationService.getNotifications(this.token).subscribe(
      response => {
        this.myNotifications = response.notifications.filter(notification => notification.viewed == false).length;
        console.log(this.myNotifications)
        if(this.myNotifications > 0){
          this.newNotifications$ = new Observable(observer=>observer.next(true));
        }
      },
      error => {
        console.log(<any>error);
      }
    )
  }

  setViewedNotifications(token, id){
    this._notificationService.setViewedNotifications(token, id).subscribe(
      response =>{
        console.log(response);
      },
      error =>{
        console.log(<any>error);
      }
    )
  }

  checkUnviewedMessages(){
    this._messageService.getUnviewedMessages(this.token).subscribe(
      response => {
        this.unviewedMessages = response.unviewed;
      },
      error => {
        console.log(<any>error);
      }
    )
  }

}

This is the navbar component template:

<div class="navigation col-lg-12">
  <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container-fluid">
      <div class="navbar-header mx-xl-5 mx-lg-5">
        <a [routerLink]="['/timeline']" (click)="toTop($event)" class="navbar-brand">V a p o r b o x</a>
      </div>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
        aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
          <div class="d-flex">
            <li class="nav-item mx-xl-3 mx-lg-3 mobile-avatar">
              <!--Imagen de usuario-->
              <a [routerLink]="['/profile', identity._id]"><img src="{{ url + 'get-image-user/' + identity.image }}"
                  alt="Avatar de usuario logueado" *ngIf="identity && identity.image">
                <img src="../../../assets/img/default-user.jpg" class="default-img" alt="Imagen de usuario"
                  *ngIf="!identity.image || identity.image == null">
              </a>
            </li>
          </div>

          <li class="nav-item mx-xl-3 mx-lg-3">
            <a [routerLink]="['/timeline']" (click)="toTop($event)" class="nav-link">
              <i class="fa fa-home fa-lg mx-lg-2"></i>
              Inicio
            </a>
          </li>

          <li class="nav-item mx-xl-3 mx-lg-3">
            <a [routerLink]="['/users/']" class="nav-link">
              <i class="fa fa-users mx-lg-2"></i>
              Usuarios
            </a>
          </li>

          <li class="nav-item mx-xl-3 mx-lg-3">
            <a [routerLink]="['/chat']" class="nav-link" *ngIf="unviewedMessages">
              <i class="fa fa-comments fa-lg mx-lg-2" *ngIf="unviewedMessages.length < 1"></i>
              <i class="fa fa-comments fa-lg mx-lg-2 new-unviewed" *ngIf="unviewedMessages.length >= 1">
                <small>{{unviewedMessages.length}}</small>
              </i>
              Chat
            </a>
          </li>

          <li id="log-out" class="nav-item mx-xl-3 mx-lg-3">
            <a href="#" (click)="logout()" class="nav-link">
              <i class="fa fa-times fa-lg"></i>
              Cerrar Sesión
            </a>
          </li>
        </ul>
        <ul class="nav navbar navbar-right mx-lg-5" *ngIf="identity">
          <li class="avatar">
            <!--Imagen de usuario-->
            <a [routerLink]="['/profile', identity._id]"><img src="{{ url + 'get-image-user/' + identity.image }}"
                alt="Avatar de usuario logueado" *ngIf="identity && identity.image">
              <img src="../../../assets/img/default-user.jpg" class="default-img" alt="Imagen de usuario"
                *ngIf="!identity.image || identity.image == null"></a>
          </li>
          <li class="dropdown">
            <a class="dropdown-toggle" data-bs-toggle="dropdown" href="#">
              {{identity.name}} <span class="caret"></span>
            </a>
            <ul class="dropdown-menu">
              <li>
                <a [routerLink]="['/profile/'+identity._id]"><i class="fa fa-user mx-2"></i>Perfil</a>
              </li>
              <li>
                <a [routerLink]="['/user-edit']"><i class="fa fa-cog mx-2"></i>Configuración</a>
              </li>
              <li>
                <a href="#" (click)="logout()"><i class="fa fa-times mx-2"></i>Cerrar Sesión</a>
              </li>
            </ul>
          </li>
          <li class="nav-item">
            <a (click)="seeNotifications($event)" [routerLink]="['/notifications']" class="nav-link">
              <i class="fa fa-bell fa-lg" *ngIf="!newNotifications$"></i>
              <i class="fa fa-bell fa-lg new-unviewed" *ngIf="newNotifications$"><small>{{myNotifications}}</small></i>
            </a>
          </li>
        </ul>
      </div>

    </div>
  </nav>
</div>

Try unsubscribing the api calls made in components, in ngOnDestroy method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM