Qualtrics display logic interferes with javascript .hide() - javascript

I have a side-by-side question in Qualtrics with 30 rows. Each of the first 20 rows has display logic such that they only appear when something is entered in text boxes in prior questions. Each of the last 10 rows has display logic such that at least 10 rows show up in the entire question, i.e. row 21 only shows up if none of the first 20 are displayed, row 22 shows up if only one of the first 20 are displayed... row 30 shows up if 9 of the first rows are displayed, and none of them appear if at least 10 of the first rows are displayed.
The first column of the question is a checkbox, and I'm using the following Javascript to hide the checkboxes for the last 10 rows:
Qualtrics.SurveyEngine.addOnload(function()
{
var qid = this.questionId;
var p = $(qid);
p.down('label[for="QR~'+qid+'#1~21~1"]').hide();
p.down('label[for="QR~'+qid+'#1~22~1"]').hide();
p.down('label[for="QR~'+qid+'#1~23~1"]').hide();
p.down('label[for="QR~'+qid+'#1~24~1"]').hide();
p.down('label[for="QR~'+qid+'#1~25~1"]').hide();
p.down('label[for="QR~'+qid+'#1~26~1"]').hide();
p.down('label[for="QR~'+qid+'#1~27~1"]').hide();
p.down('label[for="QR~'+qid+'#1~28~1"]').hide();
p.down('label[for="QR~'+qid+'#1~29~1"]').hide();
p.down('label[for="QR~'+qid+'#1~30~1"]').hide();
});
It works fine if none of the previous rows are displayed:
But bombs if even one of the previous rows is displayed:
I poked around with Inspect Element on the preview to see if the tags changed somehow, but couldn't find anything unexpected as far as changing IDs. When checking the element for the checkbox on row 23 when none of the first 20 rows appear:
<input id="QR~QID4#1~23~1" name="QR~QID4#1~23~1" value="Selected"
data-runtime-checked="runtime.Children.1.Choices.23.Answers.1.Selected"
aria-labelledby="question1QID4 question1QID4-answer1QID4 choice23QID4"
class="QWatchTimer" type="checkbox">
<label for="QR~QID4#1~23~1" class="q-checkbox" data-runtime-class
-q-checked="runtime.Children.1.Choices.23.Answers.1.Selected"
style="display: none;"></label>
As expected, the label code is grayed out. When one of the first 20 rows appears, it's much the same, but style="display: none;" does not appear at the end:
<input id="QR~QID4#1~23~1" name="QR~QID4#1~23~1" value="Selected"
data-runtime-checked="runtime.Children.1.Choices.23.Answers.1.Selected"
aria-labelledby="question1QID4 question1QID4-answer1QID4 choice23QID4"
class="QWatchTimer" type="checkbox">
<label for="QR~QID4#1~23~1" class="q-checkbox" data-runtime-class
-q-checked="runtime.Children.1.Choices.23.Answers.1.Selected"></label>
I'm at a loss for how activation of display logic would interfere with the Javascript.

After a few hours of percolating, I remembered that if a display logic hides an item with Javascript, that script won't run. I hadn't realized that it's not just on a line-by line basis - looks like if one element controlled by one line of code gets hidden, the whole block of code gets invalidated.
I was able to solve it with a loop that dynamically considered only the rows that would be displayed:
Qualtrics.SurveyEngine.addOnload(function()
{
//Remove checkboxes for last ten options
var qid = this.questionId;
var p = $(qid);
var count = Qualtrics.SurveyEngine.getEmbeddedData('count');
var min = 21+count;
for (var i = min; i < 31; i++) {
p.down('label[for="QR~'+qid+'#1~'+i+'~1"]').hide();
}
});
At least in my case, the count variable was used to determine how many of the last 10 rows to display. Once I built that into the parameters for the loop, nothing would be invalidated by the display logic. (Check here for the process on that if interested.)
Lesson learned: I should've been using a loop to begin with - modifying the parameters is an easy step after that.

Related

How to count all blank cells in a column with Google Sheet Script Code and showing results in message box

Can someone please help?
I have a Google Sheet and as soon as I open the file I need to show a pop-up message displaying the total of blank cells in column M. I do not need to write the value in the sheet. I simply need the script code to do the calculation and show the quantity of empty cells in the message box. Also, I need the code to start counting from M3 and as far as the last row containing data in column M (it needs to find that last row automatically).
I've tried the following, but obviously is not working, it's far from working:
function alertMessage() {
var Formula = "=COUNTBLANK(M3:M)";
var result = SpreadsheetApp.getUi().alert("Empty cells total:" &Formula);
if(result === SpreadsheetApp.getUi().Button.OK) {
}
}
Thank you so much.

Advanced table filtre using js

I am a newcomer and I need some help with a js code.
I want to create a tabel filter like https://www.w3schools.com/howto/howto_js_filter_table.asp .
The script works almost perfect.
On the first 3 columns the filter work perfect, what I want more is that on the last 2 columns when you search for a dimension or code I want to display only the matched value, not all of product values.
To explain the table a bit:
Is an 5 columns table, where some of the first 3 columns have rowspan attribute because is same product but with different dimensions and codes.
If I search on dimension input the value "70" the script output all the products where is found the value 70 with all dimensions, but i want to display only the value requested and hide other values that does not meet the request ( currently it displays 170 as well as 210 values, but I need to display only the 170 values.)
I put the link for the code here: https://jsfiddle.net/mitza_dragan/vg9e0fkr/3/
Part of my js code below:
if(inp.id === "my" + cell.className) {
// Daca se gaseste valoarea din input in valoare din celula,
// seteaza seteaza true (s-a gasit macar o valoare in tot randul)
if(matchedCellText.indexOf(inp.value.toLowerCase()) > -1) {
matched = true;
// Daca s-a gasit macar un match, sari peste restul celulelor
// din randul actual
break;
}
}
For the complet view of the app follow the link above.
Thanks.
Welcome to StackOverflow :)
Thanks for sharing a working JS fiddle. I tried working on the fiddle and came up with a solution, can you check this fiddle and let me know whether it works out for you as per your requirements?
I'll explain the approach followed:
First of all, as the last two columns are a little bit different, you'll have to treat them separately. So, in case the search fields of the last two columns are not empty, we will not break out of all the loops and hide the entire row, instead we will loop through until all the cells are checked and then hide the miniRow or the entire row.
We can check whether mydimensiune or mycod inputs are empty of not by the following line of code :
const isDimensiuneOrCodSearchInput = nonEmptySearchInputs.findIndex( (input) => {
return (input.id == "mydimensiune" || input.id == "mycod")
});
If isDimensiuneOrCodSearchInput is -1 then both the 4th and 5th column search fields are empty and we need not worry about showing/ hiding any miniRow. This is where your code is working perfectly fine for the first three columns.
If isDimensiuneOrCodSearchInput is not -1, then either of the 4th or 5th column search fields are not empty and we need to check whether we should show/ hide the miniRow based on the cell value match.
Inside the miniRows for loop, a new variable has been introduced called as isHideMiniRow which would determine whether the current miniRow should be hidden or not.
Inside the cells for loop, if the cell value doesn't match with the input value, an if block has been added
if( cell.className == "dimensiune" || cell.className == "cod" ) {
isHideMiniRow = true;
}
This block sets the isHideMiniRow to true and in the miniRow for loop we check for this variable and hide the miniRow if none of the search fields match.
Also, we'll have to again show the miniRows when backspace is pressed, so the following lines of code has been added to do that :
const tableRows = document.querySelectorAll("tbody.table-row>tr");
tableRows.forEach(tableRow => tableRow.style.display = "table-row");
I've tried my best to describe the changes done to the code. Let me know if you want further clarity in the above approach.

How to find average of specific values in Form submissions?

Here's an example image before I start explaining:
Let's say I have these entries from a Form (A2 to D6). Let's also say I want to find the average of ONLY the values that were submitted with "Tier 1" and "Type 2" in the same row. How would I approach writing a script that could do that?
I can elaborate more if needed. Any help is appreciated :)
Here is some algorithm plus code in jquery
1) Get all the rows in your table. You will have an array of all the table rows.
var rows = $('#tblID > tbody > tr')
2) Now loop through your array of rows with a for loop. Lots of example are available on the web. Here is one way
for (i=0;i<rows.length;i++){
var row =rows[i];
}
3) For each row inspect the column you are interested in. If they match then get the column with the number and add it to your sum and increment how many you will be averaging on. Here is snippit of how you get a column in plain js
var column = row.cells[3];
Keep in mind that the column is node, not the text in that node yet, so you will need a jquery call to get the text likes so
var stuff = $(column).text();

Deleting dynamically created rows in Knockout.js

I'm using knockout.js 2.3.0 and I have a table with dynamically added rows and select lists in each of these rows. Upon changing a date input, the select lists populate with different content. Because different dates will populate the lists with different content, I want to remove any previously added rows because the content may not be accurate.
The issue I'm having is that not all of the rows are being removed. Ex: If I have more than 4 rows, there will always be 2 remaining. The only time all rows are cleared is when there is only 1 row to start with.
Here's the subscribed function for deleting the rows
self.date.subscribe(function() {
//I also tried setting the loop length to a very long number but the same results happened each time
for (i = 0; i < self.customers().length; i++){
self.customers.remove(self.customers()[i]);
}
//now populate the select list and add an empty row - commented out for testing to make sure rows are being deleted
//setCustomerList(self.date());
//self.customers.push(new AddCustomer(self.customerList[0]));
});
I was just testing to see what would happen, and the only way I've gotten all of the rows to remove is by adding multiple for loops which obviously isn't desirable.
Is there a simpler way to remove all dynamically added rows?
If you want to remove all the items in an observable array, use the removeAll method:
self.customers.removeAll();
If you really want to use a loop, you could do so by continuously removing the last (or first) item until there are none left:
while (self.customers().length) {
self.customers.pop();
}
I think you need to reverse the for loop and remove the items from the bottom up. the problem with your code is that the each time an item is removed the length of the array changes.
self.date.subscribe(function() {
var customerLength = self.customers().length
for (i = customerLength ; i >= 0; i = i - 1){
self.customers.remove(self.customers()[i]);
}
});

using jquery to display words consecutively

I have a page that has 2 columns of words, 20 total, that are of a certain class (dim) and each a unique id. The ‘dim’ class defines the words as hidden. I have the following jQuery code running when I press a button:
$().ready(function()
{
var x = 20; // will be dynamic later :-)
$("#btn1").click(function()
{
for(i=1 ; i <= x ; i++)
{
//alert(i);
$(".dim").removeClass("hilite");
// this 'turns off' all the words
$("#wrd-"+i).addClass("hilite");
// this turns on the i'th word
}
});
});
When I uncomment the alert line I’m able to see that each word becomes visible and then hides again, just like it’s supposed to. The only problem is that it happens too fast. I want a way to make each loop wait a given number of nanoseconds. I’ve tried the setTimeout method but I can’t get it to do anything. Any idea how to slow this down? I’ve tried using .show and .hide but all the effects seem to happen at once.
My goal is to have the first word in column 1 display for 2 seconds. Then it goes away and word 1 in column 2 displays for 2 seconds. Then word 2 column 1, then word 2 column 2 and so on.
Thanks
You shouldn't need IDs like #wrd3 to step through the list of elements.
I haven't tailored the DOM selection for you, but this code will show and hide each item in a set, with a pause between. The interval in .fadeIn means the item will be showing for that about of time before the .fadeOut() function starts.
var things = $('.foo');
var index = 0;
things.hide();
var showHide = function() {
things.eq(index).fadeIn(2000,function(){
$(this).fadeOut(2000);
});
index++;
setTimeout(showHide,3000);
};
showHide();
Of course, you can change the fades to .show() and .hide(), or whatever other animation you want.

Categories

Resources