30 Days Of JavaScript

Day 23: Timer

Lesson 6: Timer: 7

Like I said at the start of the lesson, there is a better way of actually running a timer application that is more accurate.

Instead of using a 1,000 ms interval to run your timer we do the following:

  • Get the time duration from the user input (like we currently do)
  • Create a Date for when that will be, call it endDate
  • Display the number of seconds between Date.now() and endDate
  • Use an interval with a duration of say 100ms (so a tenth of a second) to update that time difference on the screen
  • Each time that interval runs to update the time between Date.now() and endDate also check to see if Date.now() is after endDate and if it is stop the timer.

This is more accurate and has the benefit that you can save endDate in LocalStorage in order to make a timer that survives page reloads. This way you can see if there is an active timer running when the page loads.

You have all the skills needed to change what you have made here to what I describe above, see how far you get as a challenge - you will learn a lot!

Here is the full complete source code for what we made today (or you can find it at this GitHub repo)

1<html>
2  <head>
3    <style>
4      body {
5        font-family: "Open Sans", "Helvetica Neue", sans-serif;
6      }
7
8      #container {
9        width: 350px;
10        margin: 50px auto;
11      }
12
13      .center {
14        text-align: center;
15      }
16
17      #timer {
18        font-size: 30px;
19        color: black;
20        font-weight: bold;
21      }
22
23      .flex-row {
24        margin-top: 8px;
25        display: flex;
26        flex-direction: row;
27        justify-content: space-between;
28        column-gap: 8px;
29      }
30
31      .flex-row button {
32        border-radius: 8px;
33        padding: 12px;
34        border: none;
35        color: white;
36        cursor: pointer;
37        flex: 1;
38      }
39
40      #time-input {
41        font-size: 30px;
42        padding: 5px;
43        border-radius: 5px;
44        border: 1px solid gray;
45        width: 100%;
46      }
47
48      #start {
49        background-color: #4cbb17;
50      }
51
52      #start:disabled {
53        background-color: #4bbb1771;
54      }
55
56      #stop {
57        background-color: #ff5733;
58      }
59
60      #stop:disabled {
61        background-color: #ff583377;
62      }
63
64      #reset {
65        background-color: orange;
66      }
67
68      #reset:disabled {
69        background-color: rgba(255, 166, 0, 0.5);
70      }
71    </style>
72  </head>
73  <body>
74    <div id="container" class="center">
75      <div id="timer"></div>
76
77      <div>
78        <input
79          id="time-input"
80          type="number"
81          placeholder="Enter time in seconds"
82        />
83      </div>
84
85      <div class="flex-row">
86        <button onclick="startTimer()" id="start">Start</button>
87        <button onclick="stopTimer()" id="stop" disabled>Stop</button>
88        <button onclick="resetTimer()" id="reset" disabled>Reset</button>
89      </div>
90    </div>
91    <script>
92      const timerElement = document.getElementById("timer");
93      const timeInputElement = document.getElementById("time-input");
94      const startButton = document.getElementById("start");
95      const stopButton = document.getElementById("stop");
96      const resetButton = document.getElementById("reset");
97
98      let timerInterval;
99      let timerActive = false;
100      let time = 0;
101
102      function updateTimer() {
103        time--;
104        timerElement.innerHTML = time;
105
106        if (time === 0) {
107          clearInterval(timerInterval);
108        }
109      }
110
111      function startTimer() {
112        console.log("starting timer");
113
114        if (timerActive) {
115          timerInterval = setInterval(updateTimer, 1000);
116          setButtons("running");
117          return;
118        }
119
120        time = timeInputElement.value;
121
122        if (time <= 0) {
123          alert("Time must be more than 0!");
124          return;
125        }
126
127        timerElement.innerHTML = time;
128
129        timerInterval = setInterval(updateTimer, 1000);
130        setButtons("running");
131        timerActive = true;
132      }
133
134      function stopTimer() {
135        console.log("stopping timer");
136        clearInterval(timerInterval);
137        setButtons("stopped");
138      }
139
140      function resetTimer() {
141        console.log("resetting timer");
142        time = 0;
143        timeInputElement.value = "";
144        timerElement.innerHTML = time;
145        setButtons("clear");
146        timerActive = false;
147      }
148
149      function setButtons(state) {
150        if (state === "clear") {
151          startButton.disabled = false;
152          stopButton.disabled = true;
153          resetButton.disabled = true;
154        }
155        if (state === "running") {
156          startButton.disabled = true;
157          stopButton.disabled = false;
158          resetButton.disabled = true;
159        }
160        if (state === "stopped") {
161          startButton.disabled = false;
162          stopButton.disabled = true;
163          resetButton.disabled = false;
164        }
165      }
166    </script>
167  </body>
168</html>

Outline

Go Pro?

If you upgraded to pro, sign in here

  • About
  • Blog
  • Privacy
Looking to email me? You can get me on my first name at allthecode.co