Issue with countdown timer when making modifications on my website utilizing Angular and TypeScript

I implemented a countdown timer in typescript on the homepage of my website. However, when I navigate to another page, I encounter a console error every second.

.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>

The code functions properly under 'localhost:4200/', however, if I visit 'localhost:4200/anotherStuff' (for example), I receive a console error each second:

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)

Any insights or suggestions?

Answer №1

When the content of your page is altered, the section of the DOM where your contador element is located gets removed. If you do not properly handle your setInterval in the ngOnDestroy hook, your code will continue to run even after navigating away (when your component is destroyed). This can result in an error such as

cannot read undefined of contadorElement (reading: innerHTML)
or something along those lines.

The solution is straightforward: make sure to clean up your setInterval by calling clearInterval within the ngOnDestroy hook, using the return value from your setInterval as the argument.

private interval;

countDown() {
   this.interval = setTimeout(() => { /* Code omitted for clarity */}, 1000);
}

ngOnDestroy() {
   clearInterval(this.interval);
}

If you are already clearing the interval when it reaches 0, consider refining the process by setting the variable to undefined or null after clearing the interval and triggering clearInterval only if it has not been stopped before.

private interval;

countDown() {
   this.interval = setTimeout(() => { 
      /* Code omitted for clarity */
      
      if (distance < 0) {
        this.stopInterval();
        contadorElement.innerHTML = "EXPIRED";
      }
   }, 1000);
}

ngOnDestroy() {
   clearInterval(this.interval);
}

private stopInterval() {
   if (this.interval) {
      clearInterval(this.interval);
      this.interval = null;
   }
}

If stopping the timer in ngOnDestroy is not feasible (for instance, if your code is part of a service and you prefer not to call a stopCountDown method in

ngOnDestroy</code), you will need to check if the element still exists in each setInterval loop and potentially terminate the interval if it no longer exists.</p>
<pre class="lang-js"><code>countDown() {

    // Update the count down every 1 second
    var x = setInterval(function () {
      /* Code omitted for clarity */
       
      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);
  }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it possible to enhance the configurations within angular.json?

When creating my Angular 6 application, I encounter the need to define two key aspects simultaneously: Whether it's a production or development build The specific locale being utilized Within my angular.json, I have the following setup: "build": { ...

Tips for identifying incognito mode and launching a fresh tab within an already open incognito window

I may not be a professional developer, but I created a Chrome extension app. You can check it out here: Link to Chrome Extension This app currently adds a context menu and opens a new tab in Chrome. However, one of my users has asked me to make the app wo ...

What is the best way to eliminate a specific item from an array of objects within a function?

1. When utilizing the findUnsubmitted function with an array of submission objects, a specified date, and student names array, the function returns the names of students who have not completed any quiz on that particular date. If the findUnsubmitted featu ...

Creating a custom pipe that converts seconds to hours and minutes retrieved from an API can be achieved by implementing a transformation function

Can someone please provide guidance on creating a custom pipe in Angular 8 that converts seconds to hours and minutes? Thank you. <div class="col-2" *ngFor="let movie of moviesList"> <div class="movie"> {{ movie.attributes.title }} ...

What is the best way to retrieve data from the server using Props in React Router and Redux?

In my project, I am utilizing React Router, Redux, Redux Sagas, and antd components. My primary objective is to click on a cell within a table of items, navigate to the Details page for that specific item, and retrieve details from the server using the ID ...

Encountering a CouchDB 401 Unauthorized Error

I have a couchDB database named "guestbook". Initially, I utilized the following code to add a user to the "_users" database: $scope.submit = function(){ var url = "https://sub.iriscouch.com/_users/org.couchdb.user:" + $scope.name; console.log(url); $ht ...

Store the label's value as a JSON object in JavaScript

I've encountered a recurring question with no satisfactory answers. Can someone please clarify things for me? Let's take a look at a JSON file: { 'soapenv:Envelope': { '$': { 'xmlns:soapenv': 'http:// ...

Javascript error in formatting

Currently, I am utilizing an inner join operation on three tables and displaying the resulting table using XML. <SQLInformation> <Table>tblechecklistprogramworkpackagexref prwpxref</Table> <TableJoins> INNER JOI ...

Is there a way to incorporate a responsive side menu using JQuery or CSS3 that can shift the entire page layout?

Hey there, I'm currently trying to incorporate a responsive side menu into my website using either JQuery or CSS3. What I need is a side menu that will smoothly shift the page content when a link is clicked, and also adds a close button (X) to the men ...

What is the best way to send an email with a randomly generated HTML output using a <button>?

I am currently working on a feature where a random HTML output is sent to me via email whenever a user clicks on a button on the website page. The user receives a code when they click the button, and I want that code to be emailed to my address automatical ...

Node.js module mishap

In the package.json file I'm working with, these are the content of my dependencies: "devDependencies": { "chai": "^4.1.2", ... "truffle": "4.1.3" } A new NodeJS script called getWeb3Version.js was created: let web3 = require("web3" ...

Retrieve the scrolling height in Vue.js 2 window

I need to apply the sticky class to the navbar when a user scrolls down, and remove it when they scroll back up. To achieve this, I am attempting to calculate the scrolled height. Currently, my code looks like: mounted(){ this.setUpRoutes(); wind ...

I'm curious about the significance of this in Angular. Can you clarify what type of data this is referring

Can anyone explain the meaning of this specific type declaration? type newtype = (state: EntityState<IEntities>) => IEntities[]; ...

What causes variations in the output of getClientRects() for identical code snippets?

Here is the code snippet provided. If you click on "Run code snippet" button, you will see the output: 1 - p.getClientRects().length 2 - span.getClientRects().length However, if you expand the snippet first and then run it, you will notice a slight dif ...

If the status of any ticket with is_approved=1 is updated to "2", the field ticket_status will be updated based on the order ID in CodeIgniter

This is the table for requests https://i.sstatic.net/NWT4y.png How can I update the ticket_status field with a value of "2" if at least one of the requests has is_approved=1, based on the orderid? I have attempted the following code, but it is not updat ...

I'm having trouble displaying the result of my calculation in the code. Could it be because I forgot to include an output tag?

I am attempting to develop a Miles Per Gallon (MPG) calculator using Javascript. However, I'm encountering difficulties with displaying the results once the "Calculate" button is pressed. <html> <head> <title> MPG Calculator </ti ...

Display nested components without the need for a parent container element - Divide SVG elements into individual components

I am currently working on splitting an SVG element within a component into separate parts and creating nested components dynamically from the parent component. This is necessary as I am constructing the entire SVG graphic based on a json file that dictates ...

With the latest Facebook Graph API integration, we are encountering issues where AJAX calls are returning empty values

Exploring the latest Facebook Graph API and experimenting with fetching data using jQuery Ajax. Below is a snippet of my simple JavaScript code: var apiUrl = 'https://graph.facebook.com/19292868552'; $.ajax({ url: apiUrl, data ...

Is there a more efficient method for translating arrays between JavaScript and PHP?

Currently, I am in the process of developing a web page that has the capability to read, write, and modify data stored in a MySQL database. My approach involves utilizing PHP with CodeIgniter for handling queries while using JavaScript to dynamically updat ...

Struggling to make the upvoting feature function properly in the Thinkster MEAN Stack Tutorial

While following the MEAN Stack tutorial on this website, I decided to modify my code to utilize Controller as instead of using $scope as demonstrated in their examples. I am encountering an issue with the upvote functionality. Whenever I click to upvote a ...