Почему угловой дочерний компонент ( навигационная панель ) перестает обновлять представление после изменения маршрута?

#javascript #angular #typescript #socket.io #angular2-template

Вопрос:

это мой первый вопрос на платформе, надеюсь, я все сделаю правильно.

Итак, я работаю в социальной сети, используя MEAN stack и socket.io, и я пытаюсь показать количество непросмотренных уведомлений и сообщений рядом со значками. Все данные обновляются в компоненте с помощью сокетов, и я вижу, что все работает нормально в консоли, данные поступают в режиме реального времени и обновляют массив, длину которого я использую для отображения чисел на панели навигации. Все работает нормально, и он без проблем обновляет номера в представлении, НО когда я изменяю маршрут (даже если я возвращаюсь на тот же URL-адрес), он перестает обновлять представление, независимо от того, какие данные все еще поступают и обновляются в консоли.

Я уже несколько дней занимаюсь этим, провожу исследования, пытаюсь, но не могу заставить это работать. Я пытался:

Использование стратегии определения изменений.OnPush в сочетании с ChangeDetectionRef и его методами, такими как markForCheck, обнаруживает изменения с помощью асинхронного канала.

Попытка повторно отобразить компонент при изменении маршрута не увенчалась успехом.

NgZone, но, честно говоря, я не мог понять это так хорошо.

Итак, я ищу краткое объяснение того, что происходит, и представление о том, как я могу это исправить. Я знаю, что есть несколько очень похожих вопросов, подобных этому, которые я задавал раньше, и я проверил их, но не смог успешно применить их к своему проекту. Я надеюсь, что кто — нибудь сможет мне в этом помочь.

Это компонент навигационной панели:

 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);
      }
    )
  }

}
 

Это шаблон компонента navbar:

 <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 amp;amp; 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 amp;amp; 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>
 

Ответ №1:

Попробуйте отменить подписку на вызовы api, выполняемые в компонентах, в методе ngOnDestroy.