javascriptimportqualtrics

Importing questions into Qulatrics with embedded javascript


I am trying to find a straightforward solution to this problem. I understand that there are three ways to automate the creation of a Qualtrics survey with a txt file: either using the Simple format TXT file, the Advanced format TXT file, or using a QSF file, which is basically a serialized json object.

In order to automatically include the same javascript code in a massive set of questions (and avoid copy-pasting it manually), I wanted to create an importable file with the questions. However, none of the TXT file formats seems to allow including javascript.

It seems that the only option left would be to import a QSF file. Put if truth be told, given there is no API provided by Qualtrics to help understand this format, it's been hell of a nightmare to try to automatically build a QSF almost from scratch. So far I've been trying to make sense of an exported file, but I'm starting to consider that it's just not worth the effort.

Any ideas on how I could better solve this problem? To give you an idea of the magnitude, what I'm talking about is around 250 different questions with the same javascript code.

Thank you so much in advance for any insight I may receive.

EDIT:

I was asked for some sample javascript code, so here it is:

Qualtrics.SurveyEngine.addOnload(
    function()
    {
        document.getElementById('SkinContent').style.backgroundColor = "Lightblue";
    }
);

Solution

  • It took me quite a while to do this, but I finally managed to find a solution (please note my javascript code is quite complex, interacting with embedded metadata and so, unlike the example I put above, so @T. Gibbons' solution didn't work for me).

    I followed these steps to solve the problem:

    1. Create a "prototype" survey with a few sample items.
    2. Export this survey as a QSF file.
    3. Read the QSF file as a JSON object.
    4. Identify the properties that relate to the items. In my case, I used R and the package rjson, so the important properties of the resulting list object questionnaire were questionnaire$SurveyElements[[6]]$SecondaryAttribute (contains the number of items), questionnaire$SurveyElements[[1]]$Payload[[1]]$BlockElements (list of elements that form a block, in order), and the elements in questionnaire$SurveyElements, from element 8 on (sometimes it can be from element 7 on, I think it depends on whether the trash is empty or not) which are the definitions of the items themselves.
    5. Create items from the sample ones present in the exported suvey, and add them to the questionnaire object, modifying those properties.
    6. Serialize the object into the JSON format, and save it as a QSF file.
    7. Import the QSF file as a new survey in Qualtrics.
    8. Use the block with the new items at convenience (e.g. I copied the block to the library and then imported it into my master project).

    Here is a simple code that can do the operations needed, in R:

    library(rjson)
    library(tidyverse)
    library(magrittr)
    
    PROTOTYPE.FILE <- "Prototype.qsf"
    JAVASCRIPT.FILE <- "Item_javascript_code.txt"
    
    # Computes the number of questions in the survey (returns a 'character', as stored in the QSF file)
    get.item.count <- function(questionnaire)
        questionnaire$SurveyElements %>% length() %>% subtract(7)
    
    # Sets the property "nº of questions" in the questionnaire JSON object
    set.num.items <- function(questionnaire, num.items = questionnaire %>% get.item.count) {
        
        questionnaire$SurveyElements[[6]]$SecondaryAttribute <- num.items %>% as.character
        
        return(questionnaire)
    }
    
    create.item <- function(item.num, stem, choices, javascript = NULL, html.text = FALSE) {
        
        item <- list(
            SurveyID = "SV_0rLrTOSkjnIWa2x",
            Element = "SQ",
            PrimaryAttribute = paste0("QID", item.num),
            SecondaryAttribute = stem,
            TertiaryAttribute = NULL,
            Payload = list(
                QuestionText = stem,
                DataExportTag = paste0("Q", item.num),
                QuestionType = "MC",
                Selector = "SAVR",
                SubSelector = "TX",
                Configuration = list(
                    QuestionDescriptionOption = "UseText"
                ),
                QuestionDescription = stem,
                Choices = list(),
                ChoiceOrder = choices %>% seq_along,
                Validation = list(
                    Settings = list(
                        ForceResponse = "OFF", ForceResponseType = "ON", Type = "None"
                    )
                ),
                Language = list(),
                QuestionID = paste0("QID", item.num)
            )
        )
        
        for(choice in choices) {
            item$Payload$Choices <- item$Payload$Choices %>% append(list(list(Display = choice)))
        }
        names(item$Payload$Choices) <- item$Payload$Choices %>% seq_along %>% as.character
        
        if(javascript %>% is.null %>% not) {
            item$Payload$QuestionJS = javascript
            item$Payload$PrivateData = FALSE
        }
        
        return(item)
    }
    
    add.item <- function(questionnaire, stem, choices, javascript = NULL, html.text = FALSE) {
        
        item.num <- questionnaire %>% get.item.count +1
        
        questionnaire$SurveyElements %<>% append(
            list(
                create.item(questionnaire %>% get.item.count +1, stem, choices, javascript)
            )
        )
        
        questionnaire$SurveyElements[[1]]$Payload[[1]]$BlockElements %<>% append(
            list(
                list(
                    Type = "Question",
                    QuestionID = paste0("QID", item.num)
                )
            )
        )
        
        return(questionnaire)
    }
    
    questionnaire <- fromJSON(file = PROTOTYPE.FILE)
    
    questionnaire$SurveyElements <- questionnaire$SurveyElements[1:7] # Drop items in the list
    questionnaire$SurveyElements[[1]]$Payload[[1]]$BlockElements <- NULL # Empty item list in the block
    
    for(question in 1:10) {
        
        questionnaire %<>% add.item(
            "Question stem here",
            c("Choice 1", "Choice 2", "etc..."),
            ## Javascript code here
        )
    }
    
    questionnaire %<>% set.num.items()
    
    questionnaire %>% toJSON() %>% writeLines(con = "Output_prototype.qsf")
    

    This can be much more sophisticated, including different types of questions, timers, page breaks, etc., but for the question at hand I think it's quite enough with this.