Configuré un temporizador de cuenta regresiva en mecanografiado para mi página web en la página de inicio. Pero cuando cambio a otra página, aparece un error de consola cada segundo.
.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; // <- Line 37 contadorElement.innerHTML = days + "d " + hours + "h " + minutes + "m " + seconds + "s "; if (distance < 0) { clearInterval(x); contadorElement.innerHTML = "EXPIRED"; } }, 1000); }.HTML
<p id="contador" style="font-size:30px"></p>El código anterior funciona bajo 'localhost:4200/'. Sin embargo, si voy a 'localhost:4200/anotherStuf' (por ejemplo), aparece este error de consola cada segundo:
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.<computed> (zone.js:2541)¿Alguna idea?
Cuando cambia su página, la parte del DOM en la que reside su elemento de contador se destruye. Dado que no limpia su setInterval en el gancho ngOnDestroy , su código aún se está ejecutando, incluso cuando se aleja (es decir, su componente se destruye). Esto daría lugar a un error del tipo cannot read undefined of contadorElement (reading: innerHTML) o algo similar.
La solución es simple: limpie su setInterval , lo que puede lograr llamando a clearInterval en el gancho ngOnDestroy , usando el valor de retorno de su setInterval como parámetro.
private interval; countDown() { this.interval = setTimeout(() => { /* Omitted for readability */}, 1000); } ngOnDestroy() { clearInterval(this.interval); } Dado que ya está borrando el intervalo cuando la distancia llega a 0, es posible que desee pulir esto un poco configurando la variable como undefined o null después de borrar el intervalo y solo llamando a clearInterval cuando aún no lo detuvo.
private interval; countDown() { this.interval = setTimeout(() => { /* Omitted for readability */ if (distance < 0) { this.stopInterval(); contadorElement.innerHTML = "EXPIRED"; } }, 1000); } ngOnDestroy() { clearInterval(this.interval); } private stopInterval() { if (this.interval) { clearInterval(this.interval); this.interval = null; } } Si no puede detener el temporizador en ngOnDestroy (si, por ejemplo, su código reside dentro de un servicio y no desea llamar a un método stopCountDown en ngOnDestroy ), deberá verificar si el elemento existe en cada bucle setInterval y posiblemente destruir el intervalo si ya no existe.
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 < 0) { clearInterval(x); contadorElement.innerHTML = "EXPIRED"; } }, 1000); }