Problem with adapting timer code | XM Community
Skip to main content

Hello,
I am new to all programming and am having an issue with getting a value embedded in Qualtrics to display properly. I currently have a timer (based on code that gets copied and discussed here a lot) that, as far as I can tell, works properly but has a quirk of requiring the overall time to be stated twice. When the header is set-up to hold the timer, the total time has to be declared in the innerHTML of the element, and then later on in the code the actual timer is set-up and will update the innerHTML with the new timer value as it increments down. This means that the moment that text starts getting displayed, the header will read whatever you initially wrote when setting up the innerHTML, and then one second later once the timer’s interval is completed one time, that value gets overwritten with a value stored elsewhere (specifically the copied code stores it as a variable called timerSeconds). Since there is a 1 second delay before the timer starts, if I wanted a 60 second time limit, I would initially set the innerHTML for 60 seconds (written as 01:00 to match formatting) and have to set timerSeconds equal to 59.  When the page loads, 01:00 would be displayed for one second before the interval completes once and it gets replaced with 00:59 by using code to change the timerSeconds value into a readable format (00 minutes : 00 seconds). 
My survey uses multiple pages and needs the timer to remain consistent, so having this 1 second delay and two different values is a little outside of my skill level. I am using embedded data (called timeRemaining) to hold the total time limit of the survey, so instead of explicitly stating timerSeconds = a value, I use timerSeconds = parseInt("${e://Field/timeRemaining}"). This allows for multiple pages because when a page gets submitted, I can set the timeRemaining value based on how much time is left and when a new page loads, that saved value gets inserted in. 
The problem is that whenever a page is loaded, after one second the timer is accurately displayed, but that initial display when the header is set-up upon the page loading is not and also the timer doesn’t start working for an entire second. I tried inserting the embedded data value (called timeRemaining) directly into the first declaration of innerHTML, but that has two issues: it isn’t formatted properly in the 00:00 format so it is just a basic number, and it is still wrong for an extra second. If I move to a new page with 20 seconds left on the timer, for the first second the timer displays “20”, then switches to “00:20” once the first timer interval completes, and then from there counts down normally. This means each time a page is changed (the survey allows going back and forth between pages) an extra second gets added to the overall time limit. 
I apologize if any of my usage of terms is incorrect and I realize this is a very long post for what I suspect is a simple problem.
The code I add to the first question of the survey where the timer appears is:
Qualtrics.SurveyEngine.addOnload(function()
{
var headerCont = document.createElement("div"); 
   headerCont.className = "header-cont"; 
   headerCont.id = "header_container"; 
var header = document.createElement("div"); 
   header.className = "header" 
   header.id = "header_1"; 
var timer = document.createElement("div"); 
   timer.className = "timer"; 
   timer.id = "timer_1"; 
   timer.innerHTML = "Time Remaining: ${e://Field/timeRemaining}";
headerCont.appendChild(header); 
header.appendChild(timer); 
document.body.insertBefore(headerCont, document.body.firstChild);                

function startTimer(duration, display) { 
   var timer = duration, minutes, seconds; 
   var myTimer = setInterval(function() {             
       minutes = parseInt(timer / 60, 10) 
       seconds = parseInt(timer % 60, 10); 
       minutes = minutes < 10 ? "0" + minutes : minutes; 
       seconds = seconds < 10 ? "0" + seconds : seconds; 
       var text = ('innerText' in display)? 'innerText' : 'textContent';
       display       if (--timer < 0) {
           clearInterval(myTimer);
           timeOver();
       }
   }, 1000);
   Qualtrics.SurveyEngine.addOnPageSubmit(function() {
       Qualtrics.SurveyEngine.setEmbeddedData('timeRemaining',timer);
       clearInterval(myTimer);
   });
   Qualtrics.SurveyEngine.addOnUnload(function() {
       document.getElementById("header_container").remove();
   });
}

var timerSeconds = parseInt("${e://Field/timeRemaining}");
display = document.querySelector('#time'); 
startTimer(timerSeconds, display); 
var timeOver = function() {
   document.getElementById("timer_1").innerHTML = "Time is up.";
   x = 1;
   Qualtrics.SurveyEngine.setEmbeddedData('timeUp', 1);
   $('NextButton').click();
   }
});


The easy solution is to leave the initial time empty so it doesn't show anything for the first second.
The alternative is to put the time formatting in a separate function then call it to initialize the time and again within the setInterval function.


I believe I understand what you mean for the alternative solution but I don't really know enough about java and programming to do that. The code I'm using is mostly copied and I don't really understand how to make the time formatting into it's own function, or even where in the above code I would put that function. I get the basic concept but I've tried a few dozen different things since you replied and none of them have worked. Could you give me some tips as to what I would need to do to isolate the formatting as it's own function?
I appreciate the help, assuming this also resolves the timer being delayed by 1 second when a page loads this should be the last problem I need to solve for this survey.


Leave a Reply