Angular 17 не обновляет представление с помощью setInterval с ошибкой NG0500 в консоли

Я создаю компонент таймера обратного отсчета и пытаюсь отображать обновленное значение «секунд» каждую секунду, но я не вижу никаких обновлений в пользовательском интерфейсе.

Когда я не использую отношение к внешней зоне, страница просто пуста и загружается бесконечно.

.ts-файл

import { Component, ElementRef, NgZone, OnInit, ViewChild } from '@angular/core';

@Component({
  selector: 'app-countdown',
  templateUrl: './countdown.component.html',
  styleUrl: './countdown.component.css'
})

export class CountdownComponent implements OnInit {

  static initialized: boolean = false;

  weddingDate: Date = new Date('2024-08-17T15:00:00');

  constructor(private zone: NgZone) {}
  @ViewChild('seconds') seconds: ElementRef;

  ngOnInit(): void {
    if (!CountdownComponent.initialized) {
      this.countdown(this.zone);
      CountdownComponent.initialized = true;
    }
  }

  countdown(zone: NgZone) {
    zone.runOutsideAngular(() => {
      setInterval(() => { 
        this.seconds.nativeElement.innerHTML = (this.weddingDate.getTime() - new Date().getTime()) / 1000;
        console.info(this.seconds.nativeElement.innerHTML);
      }, 1000);
    })
  }
}

HTML-файл

<div #seconds> </div>

Ваш код у меня работает

Get Off My Lawn 23.03.2024 17:02

Ну и в чем тогда может быть дело? Может что-то в конфиге?

Miso Drotar 23.03.2024 17:04

Я упростил ваш код, посмотрите это stackblitz.com/edit/…

Get Off My Lawn 23.03.2024 17:12

Убедитесь, что где-то в вашем приложении есть import 'zone.js';. Удаление его из приведенного мной примера вызывает ту же проблему.

Get Off My Lawn 23.03.2024 17:16

Спасибо, но в моем приложении это все еще не работает. Я использовал тот же код, который вы предоставили при каждом импорте.

Miso Drotar 23.03.2024 17:38

Я предполагаю, что это не связано с вашим компонентом. Вы можете попробовать удалить node_modules, package-lock.json и .angular, а затем npm install еще раз. В противном случае у меня кончились идеи. Извини.

Get Off My Lawn 23.03.2024 17:42

Даже это не сработало, но большое спасибо за ваши усилия.

Miso Drotar 23.03.2024 17:54

Используете ли вы рендеринг на стороне сервера (SSR)?

Shlang 23.03.2024 23:10

@Shlang Я не знаю, если честно. Но в консоли браузера появляется ошибка относительно гидратации NG0500.

Miso Drotar 24.03.2024 07:53

@MisoDrotar, не могли бы вы обновить свой вопрос, указав эту информацию, поскольку это важная деталь отладки?

Shlang 24.03.2024 10:08
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
10
385
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ошибка NG0500 означает, что в вашем проекте используется рендеринг на стороне сервера (SSR). Это означает, что ваше приложение запускает все на сервере, сначала ждет завершения асинхронных задач, а затем отправляет их клиенту, где приложение продолжает выполняться.

Запуск setInterval не позволяет серверу завершить рендеринг, поскольку всегда необходимо выполнить асинхронную задачу. Вот почему его перенос в zone.runOutsideAngular имеет значение, поскольку Angular больше не следит за этим, но этот перенос также делает эти изменения невидимыми для обнаружения изменений на стороне клиента, поэтому счетчик там не обновляется.

Если вы хотите использовать SSR и заставить свой код работать, вы можете добавить проверку для платформы, а счетчик запускать только на клиенте:

@Component({
  selector: 'app-countdown',
  standalone: true,
  template: `<div>{{ secondsLeft }}</div>`,
})
export class CountdownComponent {

  weddingDate: Date = new Date('2024-08-17T15:00:00');
  secondsLeft: number;

  constructor(@Inject(PLATFORM_ID) private platform: Object) {}

  ngOnInit(): void {
    if (!isPlatformServer(this.platform)) {
      this.countdown();
    }
  }

  countdown() {
    setInterval(() => {
      this.secondsLeft = (this.weddingDate.getTime() - new Date().getTime()) / 1000;
    }, 1000);
  }

}

Обратите внимание, что я также удалил обновление элементов innerHTML, поскольку это плохая практика в Angular в целом и приводит к ошибке NG0500. Всегда лучше использовать привязки и избегать прямых манипуляций с DOM.


Я настоятельно советую вам не использовать SSR, если вы не до конца понимаете, как это влияет на ваше приложение. Самый простой способ отключить его — изменить файл angular.json, удалив следующие строки в разделе architect > build > options:

"prerender": false,
"ssr": {
  "entry": "server.ts"
}

Он отключает SSR, и вы можете удалить некоторые файлы, связанные с SSR (у них есть server в качестве суффикса имени файла).

Большое спасибо за объяснение, удаление строк из angular.json сработало, а решение с isPlatformServer — нет. Большое спасибо :)

Miso Drotar 25.03.2024 10:16

Другие вопросы по теме