Custom timer - progress to next block without waiting for response | XM Community
Solved

Custom timer - progress to next block without waiting for response


I have a block where each question is separated by a page break. Users are forced to answer each question before moving to the next one, and only have 2mins to complete as many questions as they can. I have a custom timer on the first question in the block from here: https://stackoverflow.com/questions/47317718/how-to-use-automatically-move-respondents-in-qualtrics-with-global-timer-for-blo

The timer works great, but once the timer is up the survey waits for a response on the current question. I want the survey to progress to the next block once the timer is up, regardless of whether the user has answered the current question.
icon

Best answer by TomG 4 August 2018, 15:09

View original

20 replies

Userlevel 7
Badge +27
If your questions have force response turned on then you can't move past the current page until the question is answered.

A solution could be to add a ' No answer' choice to all your questions and hide it with JavaScript. Then when the timer runs out, select the 'No answer' choice before clicking the Next button.
Hi Tom, thanks very much, that sounds like a good solution.

I'm completely new to JavaScript though, are you able to help me with the code please?
Userlevel 7
Badge +27
> @AliceT said:
> Hi Tom, thanks very much, that sounds like a good solution.
>
> I'm completely new to JavaScript though, are you able to help me with the code please?
@AliceT - I sent you a private message.
Hi @TomG ,

I have the exact same problem as @AliceT .
The timer works great, but once the timer is up the survey waits for a response on the current question because participants are forced to answer the questions in that block. I want the survey to progress to the next block once the timer is up, regardless of whether the user has answered the current question.
_____________________________________________________________________________
I used the following Java Script:
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: <span id='time'>00:10</span>";
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[text] = minutes + ":" + seconds;
if (--timer < 0) {
clearInterval(myTimer);
timeOver();
}
}, 1000);
}

var timerSeconds = 120,
display = document.querySelector('#time');
startTimer(timerSeconds, display);
var timeOver = function() {

document.getElementById("timer_1").innerHTML = "Your time has run out!";
Qualtrics.SurveyEngine.setEmbeddedData("blockTimeFlag", "1");
$('NextButton').click();}

});
_____________________________________________________________________________________________
But I can not figure out what I should change so that the participants progress to the next block once the timer is up.
It would be great if you could also help me figure this out.

Thank in advance!
Julia
Userlevel 7
Badge +27
@JuliaCologne,

Assuming you've added a "No answer" choice to your question, you need to hide it at the beginning of your script. If it is the last choice in a vertical MC, it would be:
```
var q = jQuery("#"+this.questionId);
q.find("li:last").hide();
```
Then in your timeOver function you need to select it:
```
q.find("li:last input").prop("checked",true);
```
Hi @TomG ,
thank you for your quick response!
I did not add a "No answer" choice to my question yet.
Is there a possibility to instead add something to my mentioned above javascript such as "If the time is out (if the time = 0:00) then directly show the question of the following next block" (without the possibility or forcing the participants to answer the question they are on once the timer ran out)?
Or is the only possible way to add "no answer" choices to all tasks the participants need to work on during the two minutes and hide it with the script mentioned by you above?
My "no answer" would then be the last choice in a horizontal MC.

Thank you so much in advance for your great support!
Userlevel 7
Badge +27
If you don't add a "No answer" choice, then you have to turn off force response. That simplifies it...you don't have to change your JS.

Either way, you should use display logic on the rest of the questions in the block to not show them if the time runs out. If you use "No answer" then you can display if the answer is NOT "No answer." If you don't force response, then you should set an embedded data variable in your timeOver function that you can then check in your display logic.
Great @TomG Thanks! :)
If I'll try the way with the "No answer" choice could you help me with the java code if my last choice in all questions that need to be solved during the 2 min timer (the "no answer" choice) is in a horizontal MC, as I am fairly new to javascript.
Userlevel 7
Badge +27
> @JuliaCologne said:
> Great @TomG Thanks! :)
> If I'll try the way with the "No answer" choice could you help me with the java code if my last choice in all questions that need to be solved during the 2 min timer (the "no answer" choice) is in a horizontal MC, as I am fairly new to javascript.
>

In script I provided, replace li:last with td.LabelContainer:last

Hey AliceT , were you able to find a solution to your question? I think I might need a timer that does the same thing as well.

Userlevel 1
Badge +1

TomG I encountered the same issue now (timer + force response) and wondered whether there is a "timeOver" inherent function that represent the real timing-question timer. In my case, I already have a last response of "I don't know" (not hidden) for each question, which I'd be happy to select by default whenever the timer is up, for each question that was not answered by the user.
Should I implement a new timer for this or is there any way to "listen" to the already existing timing question's timer?
Thanks in advance!

Userlevel 7
Badge +27

yinbar ,
I've never tried to 'listen' to a timing question's timer, so I don't know what is possible.

Userlevel 1
Badge +1

TomG I will check the suggested solutions then... thanks!

Userlevel 1
Badge +1

TomG thanks again for your help!
I tried to implement a custom timer based on this thread and other threads that I found. Currently my code is as follows:

Qualtrics.SurveyEngine.addOnload(function()
{
var that = this;
/*Place your JavaScript here to run when the page loads*/
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: 01:00"; 

header.appendChild(timer);
document.body.insertBefore(header, 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[text] = minutes + ":" + seconds;  
   if (--timer < 0) {  
clearInterval(myTimer);  
   timeOver();  
}  
}, 1000);  
}  
 var timerSeconds = 60,  
 display = document.querySelector('#time');  
 startTimer(timerSeconds, display);  
 var timeOver = function() {  
document.getElementById("timer_1").innerHTML = "Time is up.";  
that.clickNextButton();
 
//var q = jQuery('[name="QR~QID251~1"]')
// jQuery( "select[id='QR\\~QID2']" )
 
//q.find("li:last input").prop("checked",true);
 
//$('NextButton').click();
 
 

//x = 1;  
//var bgColor = setInterval(change, 1000);  
 }  

});

Qualtrics.SurveyEngine.addOnReady(function()
{
/*Place your JavaScript here to run when the page is fully displayed*/

});

Qualtrics.SurveyEngine.addOnUnload(function()
{
/*Place your JavaScript here to run when the page is unloaded*/
clearInterval(myTimer); 

});


I have two questions regarding this and I'd really appreciate your advice (I don't have a lot of experience with javascript coding)-
1) For some reason I still see the "Time is up" text even when the survey is auto-advanced to the next page. How should I turn this off?
2) The whole code is currently under the first, opennig question of the block. There are no page breaks in this block, and all the questions after this opening question have an "I don't know" option (it is the last choice in each question). Is there a way to get all the questions in the block and check the last option for each of them when the time is up? In all the examples that I found, I only found solutions referring to "this" question.
Thanks a lot!!!

Userlevel 7
Badge +27

1) For some reason I still see the "Time is up" text even when the survey is auto-advanced to the next page. How should I turn this off?

myTimer is undefined in the addOnUnload function. Move addOnUnload inside addOnload.
2) The whole code is currently under the first, opennig question of the block. There are no page breaks in this block, and all the questions after this opening question have an "I don't know" option (it is the last choice in each question). Is there a way to get all the questions in the block and check the last option for each of them when the time is up? In all the examples that I found, I only found solutions referring to "this" question.

"this" refers to the question object of the current question. You can find all the questions on the page then loop through them to find the last input of each. However, I think you only want to set the unanswered questions to "Don't know", which makes it a bit more complicated. Anyway to find and loop through all the questions:
jQuery(".QuestionOuter").each(function () {
//do something with each question, the question container is "this"
});

Userlevel 1
Badge +1

Thanks a lot! TomG
Is there any way to detect whether a question is not asnwered yet?

Userlevel 7
Badge +27

https://www.qualtrics.com/community/discussion/comment/28203#Comment_28203You can count the number of checked choices. If it is zero the question hasn't been answered.

Userlevel 1
Badge +1

https://www.qualtrics.com/community/discussion/comment/28205#Comment_28205Thanks! Great idea

Userlevel 1
Badge +1

TomG I have another follow up question regarding this issue -
Eventually I managed to handle this issue (I wrote the following code - it may be not the most efficient way to do this, but I'm not a javascript developer so that's what I managed to do...):
function checkDefaultChoiceForNonAnsweredQuestions() {
var questionsIDs = [];
var firstQues = 251;
var lastQues = 270;

for(let i = firstQues; i <= lastQues; i += 1){
questionsIDs.push(i);
}

questionsIDs.forEach(function(item, index, array) {
var strSelect = '[id$="QID'+ item.toString()+'"]';
var Ques = document.querySelector(strSelect);
var QuesID = Ques.id;

var choiceInputs = $$('#'+QuesID + ' .ChoiceStructure input');
var isAnswered = false;

choiceInputs.forEach(function(item2,index2,array2){
isAnswered = isAnswered || item2.checked;
})

console.log(item.toString());
console.log(isAnswered);

if (isAnswered == false){
choiceInputs[choiceInputs.length - 1].checked = true;
}
})

}

Everything works great and indeed - I did a "force response" for each question, and when the timer is over, all the unanswered questions get the default "I don't know" response and the survey is auto advanced to the next page.
My only problem now is that in case the participant tries to click on the "next" button before answering all the questions (and before the time is over of course), he gets the "Please answer this question" message (which is great), but then, a new timer is starting.... (see attached picture). I guess that the page is reloaded in this case and addOnLoad runs again...
Is there any creative way to start the timer only if there's no already-running-timer?
Thanks a lot!
timer.png

Userlevel 1
Badge +1

I ended up adding a global variable "timerOn" in the preceding block, and in my block I checked at the begining of addOnLoad whether this variable is true or false - only if it's false I started all the timer coding. I turn it to true when the timer starts, and back to false when time is over.

Leave a Reply