I'm having some issues in Qualtrics with certain functions that are easy enough in a single question, but become impossible when using a Matrix Table or a Side-by-Side.
1) Content validation for individual fields in the Matrix Table - currency in the Matrix table, you can only check validation for multiple fields and generate a single error.
2) Required Response for a field based on an entry in the previous field in that row of the Matrix Table
3) Recode Values of text entries in a Matrix Table - there doesn't seem to be a way to this in a Matrix Table. Again, it's very simple to do with a single question.
Basically, I'd like a user to be able to complete only a single row of the Matrix Table if they want, but for the rows they complete, I need to validate specific fields and require response for specific fields, and possibly re-code their text entries.
Is there an easy way to do this with Javascript instead?
Thanks...
My guess is that JavaScript will take care of it. I've had to write several scripts because the validation features in Qualtrics are limited, to say the least.
Depending on how your Qualtrics validations options are set up you'll probably have to use functions from Qualtrics' JavaScript. Below is the basic structure you would use. Not really knowing anything about your Qualtrics question ids, I used placeholders.
Update: I would recommend using the side-by-side question type.
Here's a
link to the question/survey
To get you started off, here is the code for the first student. You need to copy the same pattern for students 2-5. You can go so many ways with validation style (in-line messages, pop-ups) that I didn't even go there. The email validation you can choose in Qualtrics under content validation for the two email columns. You can also choose phone number validation as well. The validation here will just prevent a user from going to the next page until they meet all the criteria. You could explain the validation criteria in the body of the question.
The questions ids I used are listed first and correspond exactly to the placement of the items in the screen shot except for the Y/N question which is different for a side-by-side question and has the id QR~QID9#5~1~1 for yes and QR~QID9#5~1~2 for no. I don't know what your skills are regarding Firebug but you will need to find the ids that pertain to your specific questions and replace the ones below with them.
I would also recommend using Embedded Data variables to feed in the answers so that you have nice clean legible data in your download. From what I remember, the structure of Qualtrics matrix and side-by-side data are not very usable.
Hopefully, this makes sense to you. If not, ask. I know from personal experience how frustrating it is to find javascript support for Qualtrics.
Qualtrics.SurveyEngine.addOnload(function () {
/*Place Your Javascript Below This Line*/
//QR~QID9#1~1~1~TEXT - QR~QID9#2~1~1~TEXT - QR~QID9#3~1~1~TEXT - QR~QID9#4~1~1~TEXT - QR~QID9#5~1~1/QR~QID9#5~1~2 - QR~QID9#6~1~1~TEXT
//QR~QID9#1~2~1~TEXT - QR~QID9#2~2~1~TEXT - QR~QID9#3~2~1~TEXT - QR~QID9#4~2~1~TEXT - QR~QID9#5~2~1/QR~QID9#5~2~2 - QR~QID9#6~2~1~TEXT
//QR~QID9#1~3~1~TEXT - QR~QID9#2~3~1~TEXT - QR~QID9#3~3~1~TEXT - QR~QID9#4~3~1~TEXT - QR~QID9#5~3~1/QR~QID9#5~3~2 - QR~QID9#6~3~1~TEXT
//QR~QID9#1~4~1~TEXT - QR~QID9#2~4~1~TEXT - QR~QID9#3~4~1~TEXT - QR~QID9#4~4~1~TEXT - QR~QID9#5~4~1/QR~QID9#5~4~2 - QR~QID9#6~4~1~TEXT
//QR~QID9#1~5~1~TEXT - QR~QID9#2~5~1~TEXT - QR~QID9#3~5~1~TEXT - QR~QID9#4~5~1~TEXT - QR~QID9#5~5~1/QR~QID9#5~5~2 - QR~QID9#6~5~1~TEXT
var notvalidphbook1 = 0, notvalidphbook2 = 0, notvalidphbook3 = 0, notvalidphbook4 = 0, notvalidphbook5 = 0;
var phsbooks; //gets sum of notvalidphbook items
var bookrecode1, bookrecode2, bookrecode3, bookrecode4, bookrecode5;
var notvalidemail1 = 0, notvalidemail2 = 0, notvalidemail3 = 0, notvalidemail4 = 0, notvalidemail5 = 0;
var emails; //gets sum of notvalidemail items
var validates; //validation variable that decides if user proceeds or not
Qualtrics.SurveyPage.Question.prototype.validate = function (element) {
//Student name entered
var student1y = $('QR~QID9#1~1~1~TEXT').getValue();
var student2y = $('QR~QID9#1~2~1~TEXT').getValue();
var student3y = $('QR~QID9#1~3~1~TEXT').getValue();
var student4y = $('QR~QID9#1~4~1~TEXT').getValue();
var student5y = $('QR~QID9#1~5~1~TEXT').getValue();
//Student phone number
var student1phone = $('QR~QID9#2~1~1~TEXT').getValue();
var student2phone = $('QR~QID9#2~2~1~TEXT').getValue();
var student3phone = $('QR~QID9#2~3~1~TEXT').getValue();
var student4phone = $('QR~QID9#2~4~1~TEXT').getValue();
var student5phone = $('QR~QID9#2~5~1~TEXT').getValue();
//Emails match
var student1emailA = $('QR~QID9#3~1~1~TEXT').getValue();
var student1emailB = $('QR~QID9#4~1~1~TEXT').getValue();
var student2emailA = $('QR~QID9#3~2~1~TEXT').getValue();
var student2emailB = $('QR~QID9#4~2~1~TEXT').getValue();
var student3emailA = $('QR~QID9#3~3~1~TEXT').getValue();
var student3emailB = $('QR~QID9#4~3~1~TEXT').getValue();
var student4emailA = $('QR~QID9#3~4~1~TEXT').getValue();
var student4emailB = $('QR~QID9#4~4~1~TEXT').getValue();
var student5emailA = $('QR~QID9#3~5~1~TEXT').getValue();
var student6emailB = $('QR~QID9#4~5~1~TEXT').getValue();
//Student book needs
var student1booky = $('QR~QID9#5~1~1').getValue();
var student1bookn = $('QR~QID9#5~1~2').getValue();
var student2booky = $('QR~QID9#5~2~1').getValue();
var student2bookn = $('QR~QID9#5~2~2').getValue();
var student3booky = $('QR~QID9#5~3~1').getValue();
var student3bookn = $('QR~QID9#5~3~2').getValue();
var student4booky = $('QR~QID9#5~4~1').getValue();
var student4bookn = $('QR~QID9#5~4~2').getValue();
var student5booky = $('QR~QID9#5~5~1').getValue();
var student6bookn = $('QR~QID9#5~5~2').getValue();
//Student book name
var student1bookname = $('QR~QID9#6~1~1~TEXT').getValue();
var student2bookname = $('QR~QID9#6~2~1~TEXT').getValue();
var student3bookname = $('QR~QID9#6~3~1~TEXT').getValue();
var student4bookname = $('QR~QID9#6~4~1~TEXT').getValue();
var student5bookname = $('QR~QID9#6~5~1~TEXT').getValue();
if (student1y == '') {
//alert("no name provided, no other info needed");
//"no name provided, no other info needed"
} else if (student1y != '' && (student1phone == '' || (student1emailA == '' || student1emailB == '') || (student1booky == null && student1bookn == null))) {
//alert("you need to provide a phone number and enter the student's book needs");
notvalidphbook1 = 1;
}
else if (student1y != '' && (student1phone != '' && (student1emailA != '' && student1emailB != '') && (student1booky == null && student1bookn == null))) {
notvalidphbook1 = 0;
else {
//alert("thank you for providing a phone number and specifying book needs");
if (student1booky == 'QR~QID9#5~1~1') {
bookrecode1 = 'Y';
} else {
bookrecode1 = 'N';
}
}
if (student1emailA == '' && student1emailB == '') {
//alert("no email provided, no match needed");
//"no email provided, no match needed"
} else if (student1emailA != '' && student1emailA == student1emailB) {
//alert("the emails match");
//"the emails match"
notvalidemail1 = 0;
} else {
//alert("the emails don't match");
//"the emails don't match"
notvalidemail1 = 1;
}
Qualtrics.SurveyEngine.setEmbeddedData('Student1Name', student1y);
Qualtrics.SurveyEngine.setEmbeddedData('Student1Phone', student1phone);
Qualtrics.SurveyEngine.setEmbeddedData('Student1Email', student1emailA);
Qualtrics.SurveyEngine.setEmbeddedData('Student1Txt', bookrecode1);
Qualtrics.SurveyEngine.setEmbeddedData('Student1TxtName', student1bookname);
phsbooks = notvalidphbook1 + notvalidphbook2 + notvalidphbook3 + notvalidphbook4 + notvalidphbook5;
emails = notvalidemail1 + notvalidemail2 + notvalidemail3 + notvalidemail4 + notvalidemail5;
validates = phsbooks + emails;
if (validates == 0) { //validates only if the sum is equal to zero
return true; //this let's the user continue
} else {
return false; //this prevents the user from proceeding to the next page
}
}
});
Related
I got this problem. I created a drop down list for choosing the algorithm to work with. It works with the first option but not all of them. Could you please help me?
Thanks in advance
var form1 = document.getElementById('form1');
var form2 = document.getElementById('form2');
var form3 = document.getElementById('form3');
var formArray = [];
formArray.push(form1.innerHTML);
formArray.push(form2.innerHTML);
formArray.push(form3.innerHTML);
//select drop down list//
function changeToCal() {
dropDownList.selectedIndex--;
document.getElementById('form').innerHTML = formArray[dropDownList.selectedIndex];
}
//Calculate //
document.getElementById('form').addEventListener("submit",
function(event) {
var fieldy = document.getElementById('fieldy');
var fieldx = document.getElementById('fieldx');
var resultField = document.getElementById('resultField');
var x = parseFloat(fieldx.value);
var y = parseFloat(fieldy.value);
if(!fieldy.value || !fieldx.value) {
alert("Please enter numbers in the fields!");
} else if (dropDownList.selectedIndex = 1) {
var result = (y / 100) * x;
resultField.innerText = "Answer: " + result + "."
event.preventDefault();
} else if (dropDownList.selectedIndex = 2) {
var result = (100 / y) * x;
resultField.innerText = "Answer: " + result + "."
event.preventDefault();
} else if (dropDownList.selectedIndex = 3) {
var result = (y / x) * 100;
resultField.innerText = "Answer: " + result + " %."
event.preventDefault();
} else {
resultField.innerText = "Error"
event.preventDefault();
}
}
);
https://codepen.io/anon/pen/VMZNwQ
This line:
} else if (dropDownList.selectedIndex = 1) {
needs to use a comparison equals operator rather than an assignment equals operator:
} else if (dropDownList.selectedIndex === 1) {
The other if/else clauses are similarly incorrect.
I highly recommend using a decent IDE, it would highlight potential mistakes like this for you.
You will also need to change this:
dropDownList.selectedIndex--;
document.getElementById('form').innerHTML = formArray[dropDownList.selectedIndex];
to this:
document.getElementById('form').innerHTML = formArray[dropDownList.selectedIndex - 1];
The selectedIndex is live, if you change it using -- that will cause the selected value to be updated.
The way the result is output assumes there is an <h3> with the id resultField but only one of your forms has that id set.
Other miscellaneous suggestions include...
The id attributes need to be unique throughout the document. You currently have 3 hidden forms and you copy around the HTML, leading to 4 elements with each id (resultField, fieldx, fieldy). Whether document.getElementById grabs the right one is down to luck.
Rather than copying around the innerHTML of those forms you'd be better off simply showing and hiding the existing forms using CSS. Alternatively you could use just 1 form and update the relevant text to match the current algorithm.
Listening for the submit event of the form seems odd. Why not use a regular button and listen for the click event?
If you do decide to keep the 3 forms I would suggest registering separate button handlers for each one. The fact that so much of your code is inside a big if/else is a sign that you actually need multiple functions rather than a single function that has to figure out which mode it is in. The code they share could be factored out if appropriate.
I'm trying to set up an email alert system based on a project tracking sheet my team uses at work. I need it to send an email when a task's status is changed to "Done" in column K. I got the code to work on a test sheet, but when I copy it to the live sheet the getValue() code stops working? Since the email is sent based on if() statements, the script runs, but doesn't actually work. I'm not sure if it's a permissions issue since I am not the owner of the live sheet?
I hope that is descriptive enough -- I have taught myself javascript in order to get this working and it seems so close, but I am stuck!!
Here is a screenshot of what the project tracking sheet looks like.
function emailUpdate(e) {
var emailInfoRange = sheet.getRange("B:O");
var edit = e.range.getA1Notation(); // Gets edited cell location
var editColumn = edit.substring(0,1) // Gets column of edited cell
var editRow = edit.substring(1,3) // Gets row of edited cell
if(editColumn == "K") { // gets all relevent information needed for email
var taskTypeCell = emailInfoRange.getCell(editRow,1);
var taskType = taskTypeCell.getValue();
var requestedByCell = emailInfoRange.getCell(editRow,3);
var requestedBy = requestedByCell.getValue();
var emailRequestCell = emailInfoRange.getCell(editRow,4);
var emailRequest = emailRequestCell.getValue();
var projectIdCell = emailInfoRange.getCell(editRow,5);
var projectID = projectIdCell.getValue();
var taskDescriptionCell = emailInfoRange.getCell(editRow,6);
var taskDescription = taskDescriptionCell.getValue();
var claimedByCell = emailInfoRange.getCell(editRow,9);
var claimedBy = claimedByCell.getValue();
var taskStatusCell = emailInfoRange.getCell(editRow,10);
var taskStatus = taskStatusCell.getValue();
if(taskStatus == "Done") {
if(emailRequest == "Yes" || emailRequest == "yes") { // Determines if status is "Done", and email notification is "Yes" or "yes"
var emailAddress;
var getEmailAddress = function(personelArray) { // Defines function to search email address arrays for the one that belongs to requestedBy
for (var i = 0; i < personelArray.length; i++) {
if(requestedBy === personelArray[i]) {
emailAddress = personelArray[i+1];
} } }
// Searches through all email arrays to find the one belonging to requester
getEmailAddress(specialistsAndEmails)
getEmailAddress(coordinatorsAndEmails)
getEmailAddress(managersAndEmails)
// Sends email
MailApp.sendEmail(emailAddress,
"AUTOGEN: " + taskType + " for " + projectID + " " + taskDescription + " completed by " + claimedBy + ".", "This email has been automatically generated by an edit to the work available sheet. \n"
+ "PLEASE DO NOT REPLY");
} else (Logger.log("No email requested"))
} else (Logger.log("Status not changed to done"))
} else (Logger.log("Update not to status cell"))
}
I would make the following changes to help prevent issues with string manipulations. Which could be the cause for your issues with getValues().
function emailUpdate(e) {
var emailInfoRange = sheet.getRange("B:O");
var edit = e.range // Gets edited cell location
var editColumn = edit.getColumn() // Gets column of edited cell
var editRow = edit.getRow() // Gets row of edited cell
if(editColumn == 11) // Column K should correspond to column number 11, if i can count correctly.
{
/// Remainder of the code should be the same as above
}
}
So instead of converting the range to A1 notation, you should get column number and row number using getColumn and getRow() on the range object. This will prevent issues with text to number manipulation and could be the cause of your problems.
Ultimately I am prompting the user for a guess, which is then ultimately changed so regardless of what the user inputs it will always Capitalize the first letter and make the rest lowercase. (Im doing this so if the user types in a guess the string will either match or not match the values in an array.) I tried doing a for statement to use a loops counter (3 total guesses is what im looking for). But when I try to use a indexOf to check the array, I keep getting an "unexpected token" error on that line that contains the indexOf statement. So the question would be (1) what am i doing wrong in this line of code?
//declare variables
var sportsArray = new Array("Football", "Basketball", "Rollerblading", "Hiking", "Biking", "Swimming");
var name = prompt("Enter your name");
var loops = 0;
var score = 0;
var sGuess = prompt("enter your sport guess");
// uses substrings to ultimately capitalize the 1st letter, and make everything after it lowerCase.
var sFirstPart = sGuess.substr(0, 1);
var sFirstCap = sFirstPart.toUpperCase();
var sSecondPart = sGuess.substring(1, sGuess.length);
var sSecondLow = sSecondPart.toLowerCase();
var usableGuess = sFirstCap + sSecondLow;
while(loops < 4){
if(sportsArray.indexOf(usableGuess) = 0 {
document.write("nice guess");
loops++;
}else {
document.write("loser");
loops++;
}
}
This works for checking the whole array:
var sportsArray = new Array("Football", "Basketball", "Rollerblading", "Hiking", "Biking", "Swimming");
var name = prompt("Enter your name");
var loops = 0;
var score = 0;
var sGuess = prompt("enter your sport guess");
// uses substrings to ultimately capitalize the 1st letter, and make everything after it lowerCase.
var sFirstPart = sGuess.substr(0, 1);
var sFirstCap = sFirstPart.toUpperCase();
var sSecondPart = sGuess.substring(1, sGuess.length);
var sSecondLow = sSecondPart.toLowerCase();
var usableGuess = sFirstCap + sSecondLow;
while(loops < 4){
if(sportsArray.indexOf(usableGuess) > -1) {
document.write("nice guess");
loops++;
}else {
document.write("loser");
loops++;
}
}
You'd want to use indexOf(guess) > -1 to check if the guess is present at any index of the array. For checking just one index position it would be indexOf(guess) == 0.
sportsArray.indexOf(usableGuess) === 0) instead of sportsArray.indexOf(usableGuess) = 0
It's a good practice to check for equality with constant on the left side. It will throw an exception in most browsers:
var a = 3;
if (12 = a) { // throws ReferenceError: invalid assignment left-hand side in Firefox
//do something
}
Also: use tools that provide static code analysis. A jslint.com or jshint.com for js is a good choice. There are also IDE plugins explicitely for that (using either of those two and more), see Is there a working JSLint Eclipse plug-in?.
I'm a rookie scripter and what I'm trying to do is: create a registration form and a calculator. If you enter a password less than 5 symbols or a username less than 3 symbols you will not be able to continue. But even if I enter an username with more than 3 symbols and a password with more than 5 symbols it still displays the error message.
The code: http://pastebin.com/KqYbDJMw
var user = document.forms[0].username.value;
var pw = document.forms[0].password.value;
function triggerCalc(){
if (pw.length < 5 && user.length < 3){
alert("An error occured");
}
else {
alert("Thank you for registering to my website.");
var action = prompt("Welcome to my calculator. For addition press 1, for substraction press 2, for multiplication press 3, for division press 4 and for square root press 5:", "");
var firstNum = new Array();
var secondNum = new Array();
var result = new Array();
You want to fail if either of those conditions are true, so use || (or) instead of && (and)
if (pw.length < 5 && user.length < 3)
should be
if (pw.length < 5 || user.length < 3)
Also, you want to fetch the current values each time you do your check, so this
var user = document.forms[0].username.value;
var pw = document.forms[0].password.value;
should be inside your function. Ie
function triggerCalc(){
var user = document.forms[0].username.value;
var pw = document.forms[0].password.value;
The problem is you get :
var user = document.forms[0].username.value;
var pw = document.forms[0].password.value;
function triggerCalc(){...
on load. So it will always be blank. To get it at the time the user clicks 'continue..' move it inside the function like so:
function triggerCalc(){
var user = document.forms[0].username.value;
var pw = document.forms[0].password.value;
...
You are not too far off. The two main changes are you need to put your variable assignment inside of the function you are calling so it can get the values when the submit button is pressed.
Also you probably want to use an Or instead when validating the fields. Here is an example:
function triggerCalc(){
var user = document.forms[0].username.value;
var pw = document.forms[0].password.value;
if (pw.length < 5 || user.length < 3){
alert("An error occured");
}
If you're doing any kind of validation, there are some great jQuery libraries that make it look great and are easy to implement. You might want to to a quick google search.
I have two fields that I'd like to match. (already done the validation functions for field 1 and 2)
field01 has a client number Txxxxx xxxxx (can be T G or M)
field02 has the area code 416 / 905 / 647
I'd like to match T with 416, G with 905, and M with 647.
and show a relationship error if the rules were broken.
I made a separate function trying to compare the two.
function validatecompare(errMessages)
{
var clientID = document.pizza.field02;
var telenum = document.pizza.field03;
var client = clientID.value;
var phone = telenum.value;
var firstL = "";
var areaC = "";
firstL=client.substr(0,1);
areaC =phone.substr(0,3);
if ((firstL) !=areaC)
{
errMessages += "<li>Client Number and Telephone No. are not consistent with our set up rules.</li>\n";
}
return errMessages;
}
I know that's wrong, I just have no idea how to compare two fields from two separate functions. The error message will pop up regardless of what I do. Even if I violate the rules for field 1 and 2 the error message will pop up with those when it shouldn't.
If there is somewhere I can read up on how to do this would be excellent for future reference.
any help would be greatly appreciated, thanks.
You're literally comparing 416 and T. You need some kind of lookup table:
function validatecompare(errMessages) {
var clientID = document.pizza.field02;
var telenum = document.pizza.field03;
var client = clientID.value;
var phone = telenum.value;
var firstL = client.charAt(0);
var areaC = phone.substr(0, 3);
var areaCodes = {
'416': 'T',
'905': 'G',
'647': 'M'
};
if(firstL !== areaCodes[areaC]) {
errMessages += "<li>Client Number and Telephone No. are not consistent with our set up rules.</li>\n";
}
return errMessages;
}