A timer where user enters variable for future date

Viewed 121

It would be great if someone could point me in the right direction for a school project I am working on. Below you see a super simple timer I made with the help of a tutorial from a youtuber called Web Dev. The example had the New Years eve hardcoded into the script. But I would like to take this one step further and ask the user to enter their special date - so as to make the timer count down to their birthday for example.

So far I have managed to make the counter count down from a given date, not just a hard coded date, and I have managed to create entry forms for user generated data. But once I tried to combine the two something went wrong. I am guessing I need to enter the user generated numbers into one of the functions, not just list them on top as let, var and const?

Oh, and I should ideally figure out a way to make the entry form disappear as soon as the user clicks on the 'enter' button.

For my previous StackOverflow question someone very kindly coded out the entire answer for me. But since this is very much a learning process I would be perfectly happy with a few hints and pointers in the right direction.

        let userYear = userYearEntered;
        let userMonth = userMonthEntered;
        let userDay = userDayEntered;

        const userDate = new Date(userYear, userMonth, userDay, 0, 0, 0);
        const userOccasion = 'I need to present this project';


        function enterSpecialDate() {
            var userYearEntered = document.getElementById('userYear').value;
            console.log(userYearEntered);

            var userMonthEntered = document.getElementById('userMonth').value;
            console.log(userMonthEntered);

            var userDayEntered = document.getElementById('userDay').value;
            console.log(userDayEntered);
        }

        /*create countdown timer using substraction*/
        function updateCountdowntime() {
            const currentTime = new Date();
            const diff = userDate - currentTime;
            console.log(diff);

            /* we've been given the difference in milliseconds, so some division is needed */
            const d = Math.floor(diff / 1000 / 60 / 60 / 24);
            const h = Math.floor(diff / 1000 / 60 / 60) % 24;
            const m = Math.floor(diff / 1000 / 60) % 60;
            const s = Math.floor(diff / 1000) % 60;

            /* send values back into HTML document */

            document.getElementById('days').innerHTML = d;
            document.getElementById('hours').innerHTML = h;
            document.getElementById('minutes').innerHTML = m;
            document.getElementById('seconds').innerHTML = s;

            document.getElementById('userOccasion').innerHTML = userOccasion;
        }

        setInterval(updateCountdowntime, 1000);



       * {
            box-sizing: border-box;
        }

        body {
            background-color: rgb(44, 48, 48);
            font-family: sans-serif;
            color: rgb(239, 239, 239);
            font-size: 3em;
            font-weight: 300;
            height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
        }

        div {
            margin-top: 1vh;
        }

        label {
            font-size: 0.4em;
        }

<div>
        <label for="userYear">year</label>
        <input id="userYear" type="number" value="" placeholder="e.g. 2021">

        <label for="userMonth">month</label>
        <input id="userMonth" type="number" value="" placeholder="e.g. 8">

        <label for="userDay">day</label>
        <input id="userDay" type="number" value="" placeholder="17">

        <button onclick="enterSpecialDate()">Enter</button>

    </div>

    <div>

        <p>there are</p>

        <div class="time">
            <span id="days"></span>
            <span>days</span>
        </div>

        <div class="time">
            <span id="hours"></span>
            <span>hours</span>
        </div>

        <div class="time">
            <span id="minutes"></span>
            <span>minutes</span>
        </div>

        <div class="time">
            <span id="seconds"></span>
            <span>seconds</span>
        </div>

        <p>until <span id="userOccasion"></span></p>

    </div>

5 Answers

Here's a solution using a date input, which is more semantic, accessible and more comfortable to use for the end user.

It's using inline styles to switch between the form and the countdown, but the same could be achieved using classList.toggle() and a class for showing or hiding the specific view.

You should also implement some form of error handling (e.g. right now it simply does nothing when clicking the button while not having set a date, and it also supports dates in the past, resulting in negative numbers).

A note on setInterval(): It's not reliable/exact enough and may result in seconds being skipped or changing too quickly. For more background about this and a reliable solution I recommend the video "JavaScript counters the hard way - HTTP 203 " on YouTube. The solution is also available as a reusable code snippet in this gist.

It should now be rather simple for you to implement the additional input for the occasion text.

let userDate = null;
const userOccasion = 'I need to present this project';
const userDateInput = document.getElementById('user-date');
const formView = document.getElementById('form-view');
const counterView = document.getElementById('counter-view');

function enterSpecialDate() {
  userDate = userDateInput.valueAsDate;
  if (userDate) {
    // fire the function once, so we start with filled in numbers right away
    updateCountdowntime();
    // see the note on setInterval() in the answer
    setInterval(updateCountdowntime, 1000);
    // switch between the form and the counter view
    formView.style.display = 'none';
    counterView.style.display = 'block';
  }
}

/*create countdown timer using substraction*/
function updateCountdowntime() {
  const currentTime = new Date();
  const diff = userDate - currentTime;

  /* we've been given the difference in milliseconds, so some division is needed */
  const d = Math.floor(diff / 1000 / 60 / 60 / 24);
  const h = Math.floor(diff / 1000 / 60 / 60) % 24;
  const m = Math.floor(diff / 1000 / 60) % 60;
  const s = Math.floor(diff / 1000) % 60;

  /* send values back into HTML document */

  document.getElementById('days').innerHTML = d;
  document.getElementById('hours').innerHTML = h;
  document.getElementById('minutes').innerHTML = m;
  document.getElementById('seconds').innerHTML = s;

  document.getElementById('userOccasion').innerHTML = userOccasion;
}
* {
  box-sizing: border-box;
}

body {
  background-color: rgb(44, 48, 48);
  font-family: sans-serif;
  color: rgb(239, 239, 239);
  font-size: 2em;
  font-weight: 300;
  height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

div {
  margin-top: 1vh;
}
<div id="form-view">
  <input type="date" id="user-date">
  <button onclick="enterSpecialDate()">Enter</button>
</div>

<div id="counter-view" style="display: none;">

  <p>there are</p>

  <div class="time">
    <span id="days"></span>
    <span>days</span>
  </div>

  <div class="time">
    <span id="hours"></span>
    <span>hours</span>
  </div>

  <div class="time">
    <span id="minutes"></span>
    <span>minutes</span>
  </div>

  <div class="time">
    <span id="seconds"></span>
    <span>seconds</span>
  </div>

  <p>until <span id="userOccasion"></span></p>

</div>

You should be able to do this with a couple of simple prompts or text input fields.

For example:

Ask the user to put in a month, then a day and then a year. You save these inputs as separate variables. Then you use the const newYearTime but instead of using the hardcoded date you use the variables as date.

Now you have const newYearTime = new Date('january' ,1,current year etc...)

With the prompts you could do:

let year = number(prompt: enter year)
let day = number(prompt: enter day)
let month = prompt: enter month

And then you just change the const newYearTime to

Const newYearTime = new Date(month, day, year)

My code isn't correct i know. I am not at my pc so i don't have my editor to write it like it should be but i think you get what I mean.

I am pretty new to javascript too but i try to help if i think i know how to do it

Fraku's answer seems to do what you stated. To add on to his answer, you also wanted to use LocalStorage.

So, you can store the Special Date the user entered into the LocalStorage. So you don't need to ask the user everytime the user enters the page.

Below is an example on how to store data into LocalStorage. dtUserDate is the special date the user entered.

window.localStorage.setItem("Some Name", JSON.stringify( { "SpecialDate" : dtUserDate } ));

So I recreated your code in my editor. And as I see it now the problem you are having is that it doesn't update the html when the user has pressed enter (or clicked on it).

Did you check your console when testing it? Because I opened the console the first time I tried it and immediatly found the problem:

Uncaught ReferenceError: userYearEntered is not defined

With this you should be able to find the answer to your problem by yourself. I will give you a little hint: When the page is first loaded the var userYearEntered doesn't have a value. This breaks your code from the very beginning. Think about how you could change this. There are multiple solutions for this problem.

Furthermore I saw you wanted to hide the inputs as soon as enter has been pressed or clicked. This can be done easily with just adding a hidden property on the parent div of the inputs. As long as the onclick hasn't happened its false. If the onclick has happened you change it to true.

You could also parse the user's date string using only one variable and the .substring JS method. Would be a little harder to read but if storage is a factor you could do that. For example, using a placeholder with the input asking for MM/DD/YYYY you could use:

userDate.substring(0, 2); = month

userDate.substring(3, 5); = day

userDate.substring(6, userDate.length); = year

and to get the date:

var newYearTime = new Date(userDate.substring(6, userDate.length), (userDate.substring(0, 2) - 1), userDate.substring(3, 5));
Related