Я создаю компонент таймера обратного отсчета и пытаюсь отображать обновленное значение «секунд» каждую секунду, но я не вижу никаких обновлений в пользовательском интерфейсе.
Когда я не использую отношение к внешней зоне, страница просто пуста и загружается бесконечно.
.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>
Ну и в чем тогда может быть дело? Может что-то в конфиге?
Я упростил ваш код, посмотрите это stackblitz.com/edit/…
Убедитесь, что где-то в вашем приложении есть import 'zone.js';
. Удаление его из приведенного мной примера вызывает ту же проблему.
Спасибо, но в моем приложении это все еще не работает. Я использовал тот же код, который вы предоставили при каждом импорте.
Я предполагаю, что это не связано с вашим компонентом. Вы можете попробовать удалить node_modules
, package-lock.json
и .angular
, а затем npm install
еще раз. В противном случае у меня кончились идеи. Извини.
Даже это не сработало, но большое спасибо за ваши усилия.
Используете ли вы рендеринг на стороне сервера (SSR)?
@Shlang Я не знаю, если честно. Но в консоли браузера появляется ошибка относительно гидратации NG0500.
@MisoDrotar, не могли бы вы обновить свой вопрос, указав эту информацию, поскольку это важная деталь отладки?
Ошибка 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 — нет. Большое спасибо :)
Ваш код у меня работает