Record answer randomization in Qualtrics using javascript - javascript

I am making a survey in Qualtrics. This survey has a repeating question with six answer choices. The six choices are randomized (in the standard way, no javascript). The question is being repeated using loop&merge, which works great because it's the same question structure over and over (36 times), but I can use the field function to adjust the question and answers for every iteration.
However, one problem I am running into is that Qualtrics does not (as standard) support the recording of the randomization data in the results - i.e. how it has randomized the six answer choices in each iteration. When I use the 'Export Randomized Viewing Order data' function when downloading results, it only shows the answer order of the last time it asked the question. So it seems that this is a value that gets overwritten after each iteration.
So now I'm looking to record the answer order for each iteration through javascript. However, I haven't found a function that gives the order answer (after randomization). I have consulted the Qualtrics javascript API and found some functions that seem promising, such as getChoices (), but when I try this all I get back is the order of answers without randomization (i.e. just 1,2,3,4,5,6).
Does anyone know a way to record the randomized choice order for each iteration, using javascript or otherwise?

I found a different way to record the loop and merge randomization order.
Create an embedded data field in survey flow. Here we will record the randomization order. I will call the field rand_order.
Add a loop and merge field with a unique number to identify each loop (e.g. 1, 2, 3, 4, 5, ..., n).
Then add the next javascript to any page of the looped block.
//*Place Your Javascript Below This Line*/
var questionText = "${lm://Field/1}"; // "${lm://Field/1}" will actually evaluate to
//whatever is Field 1 in the current Loop & Merge loop.
// You can do this with embedded data too, as seen in the next line
var order = "${e://Field/rand_order}" + "|" + questionText; // gets the value of the embedded data
// field "rand_order", concatenates the current loop's identifier to it,
//and stores that as a variable
Qualtrics.SurveyEngine.setEmbeddedData('rand_order', order); // updates the
//embeddeddata field "rand_order" to be our order variable, which has the current loop's
//identifier attached, effectively constructing a string of numbers representing the order
You will get a column with the name "rand_order" filled with "1|5|23|2...|n". You can change the separator to make more compatible with whatever script you are using to manipulate data.

Qualtrics already records this information for you. It's just a matter of explicitly asking for it when you download your data. Number 5 on this page has more info, but I'll recount the important bits:
In the “Data & Analysis” tab, click “Export & Import” and then “Export Data”.
In the “Download Data Table” window click “More Options”.
Check the box for “Export viewing order data for randomized surveys”.

I think the thing here is to look at the order of choices in the DOM. Qualtrics provides the getChoiceContainer() method to get the div containing the choices. Here's a snippet I wrote and minimally tested:
//get the div containing the choices, then get all input child elements of that div
var choices = this.getChoiceContainer().getElementsByTagName("input");
//initialize an array for the IDs of the choices
var choiceIDs = []
//add the ID of each choice to the array
for (var i=0; i < choices.length; i++) {
choiceIDs.push(choices[i].id);
}
//get the current choice order from embedded data and add this loop to it.
//Add a | to distinguish between loops.
var choiceOrder = "${e://field/choiceorder}" + choiceIDs.toString() + "|";
//set the embedded data with the new value
Qualtrics.SurveyEngine.setEmbeddedData("choiceorder", choiceOrder);
A couple of notes/caveats:
I only tested this on a basic multiple choice question with radio buttons. It may need to be adjusted for different question types.
I also just got the IDs of the question choices. You could probably modify it pretty easily to get other information, like the label of the choice, or the numeric value it corresponds to.

Related

Google App Script to Append Value from one Cell to String of Numbers in another Cell

I’ve been trying to figure out how to write a script which will take the value from one cell and append it to the end of a string of numbers in another cell of that same row. The newly appended number needs to be separated by a comma from the previously appended value, and the whole string needs to be wrapped between brackets. EX. [2,3,3,4.5,2.5,2.1,1.3,0.4]. The script will need to loop through all of the rows containing data on a named sheet beginning with the third row.
The above image is obviously just an example containing only two rows of data. The actual spreadsheet will contain well over a thousand rows, so the operation must be done programmatically and will run weekly using a timed trigger.
To be as specific as I can, what I need help with is to first know if something like the appending is even possible in Google App Scripts. I've spent hours searching and I can't seem to find a way to append a new value (ex. cell A3) to the current string (ex. cell B3) without overwriting it completely.
In full disclosure; I'm a middle school teacher trying to put something together for my school.
To be as specific as I can, what I need help with is to first know if something like the appending is even possible in Google App Scripts.
Seeing the expected result, it's inserting rather than appending, as the string should be added before the last character (]). Anyway, yes, this is possible by using JavaScript string handling methods.
Use getValue() to the get the cell values, both the Current GPA and the GPA History.
One way is to use replace
Example using pure JavaScript:
var currentGPA = 3.5
var gpaHistory = '[2,3.1,2.4]';
gpaHistory = gpaHistory.replace(']',','+currentGPA+']');
console.info(gpaHistory)
Once you get the modified gpaHistory, use setValue(gpaHistory) to add this value to the spreadsheet.

insert two different msg.payload in a database

I want to do the query below into a function:
insert into table values (msg.payload.1, msg.payload.2);
this function has two input (2 different msg.payload)
so the code that I am trying to write is:
var m={
topic: "insert into info values ('"+msg.payload+"','"+msg.payload+"');"
};
return m;
it is adding two rows in the info table.
but want to add only one row with two different values.
any idea?
Thanks in advance
If I've understood properly you have 2 different nodes feeding data into this function and you want to use the values from these separate messages to build your insert statement.
This is not how Node-RED works, each message is handled totally separately from each other (hence why you see 2 rows added to the DB).
If you want to combine 2 separate messages you will need to make use of the context to keep state. You will also need a way to identify which message is which when it comes in, this is normally done by message topic, but it could be any unique feature.

ArrayCollection (Collection of forms) index collision in Symfony 2

I am using Symfony2 to build up my page.
When I try to update a collection of forms (like described in the cookbook entry "How to Embed a Collection of Forms"), i get a collision of the indexes of the frontend and the indexes of the ArrayCollection in the backend.
I've got the relation User <-> Address (OneToMany). A user wants to create/update/delete his addresses, therefore he can add / delete in the frontend with the help of the javascript part new address elements. He does the following:
(1) Adds new address (has index: 0)
(2) Adds new address (has index: 1) and instantly removes this address again
(3) Adds new address (has index: 2).
When he clicks on save button, the following code saves/updates the user (and its addresses):
$this->em->persist($user);
$this->em->flush();
New addresses for example are then correctly persisted to the database.
Now the user wants to update the address e.g. with index 0.
When he now clicks on the save button, it updates the adress with "index 0", but at the same time, it adds again the address with "index 2" to the database (object).
To better understand the problem, i've drawn a small illustration (handmade, sorry for my bad art skills):
Now , i've got two times the address with "index 1" within my object / database.
I know why this happens, it's because the first "index 1" address gets mapped to the ArrayCollection element "number 1", and the second gets mapped to "number 2 "(because of the frontend name "index 2").
You can say: "it just fills up the addresses, until it reaches the frontend index in the backend"..
But how can I fix this behaviour ?
Site note:
This behaviour occurs using ajax requests, because if you would reload the page after clicking "save button", it would reindex the addresses in the frontend correctly with the indexes in the backend.
My suggestion to handle that situation:
Reindexing the frontend indexes after clicking save with the server side
indexes. Is this a clear / the only solution for my problem?
Yes, this is problem of Symfony form collection and it has no easy solution imho. But I have to ask why don't you do exactly the same thing what page refresh does? You can refresh only html snippet with collection. HTML code for snippet can come from server-side. Back to your question - yes, reindexing is good solution until you do not want to try write custom collection type on your own.
symfony/symfony/issues/7828
There is similar problem with validating in collection - symfony/symfony/issues/7468.
Well I think default collection type and the tutorial in Symfony docs has the some drawbacks. Hope that's help.
I have come round this issue on the client side by modifying the Javascript/Jquery code given in the Symfony Documentation.
Instead of numbering the new elements by counting the sub-elements, I am looking at the last element's id and extracting its index with a regular expression.
When adding an element, I am incrementing the last index by 1. That way, I never use the same index.
Here is my code :
// Initializing default index at 0
var index = 0;
// Looking for collection fields in the form
var $findinput = $container.find(':input');
// If fields found then looking for last existing index
if ( $findinput.length > 0 ) {
// Reading id of last field
var myString = $findinput.last().attr('id')
// Setting regular expression to extract number from id containing letters, hyphens and underscores
var myRegex = /^[-_A-Za-z]+([0-9]+)[-_A-Za-z]*$/
// Executing regular expression on last collection field id
var test = myRegex.exec(myString);
// Extracting last index and incrementing by 1
if (test.length > 0) index = parseInt(test[1]) + 1;
}
I ran into this problem a couple of times during the past two years. Usually, following the Symfony tutorial How to Embed a Collection of Forms does the job just fine. You need to do a little bit javascript coding to add the "edit/update" functionality, but other than that - you should be just fine using this approach.
If, on the other hand, you have a really complex form which uses AJAX to validate/save/calculation/business logic/etc, I've found it's usually a better to store the final data into an array in the session. After submitting the form, inside the if($form->isValid()){...} block, you would have
$collection = new ArrayCollection($mySessionPlainArray);
$user->setAddress($collection);
I would like to warn you to be careful with the serialization of your data - you might get some awkward exceptions or misbehavior if you're using entities (see my question).
I'm sorry I can't provide more code, but the solution to this problem sometimes is quite complex.

Best way to randomly pull from an array?

I have a website that will give you a random fact from Wikipedia when you click a big red button. I have heard from a few people that they are getting certain facts repeatedly, even though there are over 200.
The big red button has onclick="giveafact()" which triggers this function:
function giveafact(){ //instead of relisting all array items here, add all the other arrays to this one
var factsList= foodFactsList.concat(musicFactsList,historyFactsList,popFactsList,sportsFactsList,technologyFactsList,televisionFactsList,miscFactsList);
randomFact = Math.floor(Math.random()*factsList.length);
document.getElementById("total").innerHTML=factsList.length;
document.getElementById("fact").innerHTML=factsList[randomFact];
updateShareLinks();
return false;
}
Basically, I have 8 different arrays of facts as you can see in var factsList above. This is so the user can filter by fact. By default, there is no filter so all lists are concatenated.
If it helps, the full .js file is here: http://thewikifix.com/scripts/script.js. These random "give a fact" functions start at about line 442, with the arrays above them. (Pardon the messy code, I know I mix jQuery and Javascript a lot.)
The site is http://thewikifix.com, if it helps anyone to look at all the code.
I'm just trying to see if there's a way to better randomize the facts than I currently have, maybe by adding a function that won't allow a fact to show up twice in a row, or something similar.
Any suggestions would be great!
Edit - Additional thoughts: Thanks for the answers so far. Is there a way to remove an item from an array once it has been picked via the Math.random function so it just wouldn't show up again at all (unless the page was refreshed)? If so, once all items were removed from the array is there a way to reset the array to its original state without the user having to refresh? Thanks.
"Random" and "varied" are, to some extent, conflicting. With 200 facts, and one selected randomly each time, it becomes more likely than not that you'll see a repeat after getting only a couple dozen or so (this is known as the "Birthday Problem").
A simple approach is to store a seed and an index on the client. The seed is set once, and the index is incremented after each fact access. To get a "random" fact, seed a PRNG with the seed, use the PRNG to shuffle the list of facts, then get the fact at the given index in the shuffled list. When you run out, pick a new seed and reset the index.
Here's what I would do:
n = 0 - Find a random fact
add that fact to a new array (arr)
display fact
n + 1 - Find a random fact
check arr using lodash for that facts existence
display or find a new fact, based on result of above
--OR--
you could take the arr and use lodash's _.shuffle() to mix them up and display them in order.
https://lodash.com/docs
I love using lodash for collection and array operations.

How to read from another row in javascript step of Pentaho?

I'm working on an ETL process with Pentaho Data Integration (Spoon, before Kettle).
In the Modified Javascript step of Pentaho you can set a start, end and transform script. In the transform script you can write code that it will be executed only for each row, and from here I don't know how to access to data of the previous row (if it's possible).
I need access to the previous row because all rows are ordered by product, store and date (respectively), and the goal is to get the quantity on hand from the previous row and add the quantity sell or received on the current row (this would be the same product, same store but different date). I also need accessing to the previous row to compare the product and store of the current row with the previous row, because if someone of them changes I must to restart the field quantity_on_hand (I do it with a field of all columns named initial_stock).
On pseudocode would be something like this (if I hadn't the restriction of that the code written on the step is executed only for each row):
while(all_rows_processed()){
current_row.quantity_on_hand = current_row.initial_stock;
while(id_product_current_row == id_product_previous_row && id_store_current_row == id_store_previous_row){
current_row.quantity_on_hand = previous_row.quantity_on_hand + current_row.stock_variation;
}
}
This question related couldn't help me.
Any ideas to solve my problem would be appreciated.
May I ask you to reconsider Group By step? It seems suitable for your scenario.
If you sort the stream accordingly to your combination date/store/article, you can calculate cumulative sum for sell/received quantity. This way you can have a running total of inventory variation that would be reset on a group basis.
Also give a look both at this blog post and at the forum post it quotes.
I doubt you need to go to JavaScript for this. Check out the Analytic query step. That will allow you to bring a value from the previous row into the current.
The JavaScript step gives you tremendous flexibility, but if you can do it with the regular transform steps, it will typically be much faster.
use Analytic Query. By Using this Step u can access the previous / next record. Actually, not only prev and next record that you can read, but you can read N Rows Fordward or N Rows Back Wards.
Check the following URL for clearer expalanation :
http://wiki.pentaho.com/display/EAI/Analytic+Query
http://www.nicholasgoodman.com/bt/blog/2009/01/30/the-death-of-prevrow-rowclone/
Thanks for all, I've got the solution to my problem.
I've combined all your suggestions and I've used the Analytic Query, Modified Javascript and Group by steps.
Although the question wasn't very well formulated, the problem I had was to calculate the stock level on each row (there was one row for each product, date and store combination).
First (obviously later than sort rows by product_id, store_id and date ascending), I used the Analytic Query step to group by product_id and store_id, because with this step I've got a new field previous_date to identify the first row of each group (previous_date=null on the row of the group where date was the oldest).
Then I needed to calculate the quantity_on_hand of each group [product,store] at first row (first date of each group because it's sorted by date) because the initial_stock is different for each group. This is because of (sum(quantity_received) - sum(quantity sold)) != quantity_on_hand.
Finally (and the key was here), I used the Group by step like #andtorg suggested and do it as the next image shows.
This link that #andtorg suggested was very useful. It includes even two .ktr example files.
Thank you so much for help!

Categories

Resources