Ошибка таймера обратного отсчета при изменении внутри моей веб-страницы с помощью углового, машинописного текста

#javascript #angular #typescript

#язык JavaScript #угловой #машинописный текст

Вопрос:

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

.TS

 countDown() {  var countDownDate = new Date("Jan 1, 2022 00:00:00").getTime();   // Update the count down every 1 second  var x = setInterval(function () {  var now = new Date().getTime();   // Find the distance between now an the count down date  var distance = countDownDate - now;   var days = Math.floor(distance / (1000 * 60 * 60 * 24));  var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));  var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));  var seconds = Math.floor((distance % (1000 * 60)) / 1000);   // Display the result in an element with id="demo"  var contadorElement = document.getElementById("contador") as HTMLElement; // lt;- Line 37  contadorElement.innerHTML = days   "d "   hours   "h "    minutes   "m "   seconds   "s ";   if (distance lt; 0) {  clearInterval(x);  contadorElement.innerHTML = "EXPIRED";  }  }, 1000);  }  

.HTML

 lt;p id="contador" style="font-size:30px"gt;lt;/pgt;  

Приведенный выше код работает в разделе » localhost:4200/». Однако, если я перейду в «localhost:4200/anotherStuf» (например) Я получаю эту ошибку консоли каждую секунду:

 core.js:6456 ERROR TypeError: Cannot set properties of null (setting 'innerHTML')  at home.component.ts:37  at timer (zone.js:2561)  at ZoneDelegate.invokeTask (zone.js:406)  at Object.onInvokeTask (core.js:28661)  at ZoneDelegate.invokeTask (zone.js:405)  at Zone.runTask (zone.js:178)  at invokeTask (zone.js:487)  at ZoneTask.invoke (zone.js:476)  at data.args.lt;computedgt; (zone.js:2541)  

Есть какие-нибудь мысли?

Ответ №1:

Когда вы меняете свою страницу, часть DOM contador , в которой находится ваш элемент, уничтожается. Поскольку вы не очищаете свой setInterval в ngOnDestroy крючке, ваш код все еще выполняется, даже когда вы удаляетесь (т. Е. ваш компонент уничтожается). Это привело бы к ошибке в духе cannot read undefined of contadorElement (reading: innerHTML) или чему-то подобному.

Решение простое: очистите свой setInterval , чего вы можете добиться, вызвав clearInterval ngOnDestroy хук, используя возвращаемое значение вашего setInterval в качестве параметра.

 private interval;  countDown() {  this.interval = setTimeout(() =gt; { /* Omitted for readability */}, 1000); }  ngOnDestroy() {  clearInterval(this.interval); }  

Поскольку вы уже очищаете интервал, когда расстояние достигает 0, вы можете немного отполировать его, установив переменную в undefined значение или null после очистки интервала и вызывая только clearInterval тогда, когда вы еще не остановили его.

 private interval;  countDown() {  this.interval = setTimeout(() =gt; {   /* Omitted for readability */    if (distance lt; 0) {  this.stopInterval();  contadorElement.innerHTML = "EXPIRED";  }  }, 1000); }  ngOnDestroy() {  clearInterval(this.interval); }  private stopInterval() {  if (this.interval) {  clearInterval(this.interval);  this.interval = null;  } }  

Если вы не можете остановить таймер ngOnDestroy (если, например, ваш код находится внутри службы, и вы не хотите вызывать stopCountDown метод ngOnDestroy ), вам придется проверить, существует ли элемент в каждом цикле setInterval, и, возможно, уничтожить интервал, если он больше не существует.

 countDown() {   // Update the count down every 1 second  var x = setInterval(function () {  /* Omitted for readability */    var contadorElement = document.getElementById("contador") as HTMLElement;    if (contadorElement) {  contadorElement.innerHTML = days   "d "   hours   "h "   minutes   "m "   seconds   "s ";  } else {  clearInterval(x);  }   if (distance lt; 0) {  clearInterval(x);  contadorElement.innerHTML = "EXPIRED";  }  }, 1000);  }