Skip to contents

This example shows how to use the package ShinyItemBuilder for an assessment using Booklets.

library(ShinyItemBuilder)

For illustration purposes, the items which are included as demo01 in the package ShinyItemBuilder are used. After calling getDemoPool("demo01") the object item_pool contains information about 6 CBA ItemBuilder Tasks:

item_pool <- getDemoPool("demo01")
item_pool[,c("Project","Task")]
Project Task
1 SinglePageItems_00START.zip task0
2 SinglePageItems_01SC.zip task0
3 SinglePageItems_02MC.zip task0
4 SinglePageItems_03TXT.zip task0
5 SinglePageItems_04LIKERT.zip task0
6 SinglePageItems_05END.zip task0

The idea of using a Booklet Design is that each test-taker is assigned to a booklet \(j\) out of a all defined booklets \(J\). For simplicity, we illustrate this with \(J=2\) different booklets:

booklets <- data.frame(Booklet = c(1,1,1,2,2,2),
                       ItemIndex=c(2,3,6,4,5,6))

To define the booklets, we refer to the items from the item_pool, taking the row name as ItemIndex. Hence, the goal is to have two booklets, one with items 01SC, 02MC and 05END (Booklet \(j=1\)) and one with items 03TXT, 04LIKERT and 05END (Booklet \(j=2\)):

Booklet ItemIndex Project Task
1 2 SinglePageItems_01SC.zip task0
1 3 SinglePageItems_02MC.zip task0
1 6 SinglePageItems_05END.zip task0
2 4 SinglePageItems_03TXT.zip task0
2 5 SinglePageItems_04LIKERT.zip task0
2 6 SinglePageItems_05END.zip task0

To implement the booklet design, we need to overwrite the navigation function.

assessment_config <- getConfig(Verbose = T) 

After calling getConfig(), the object assessment_config already contains the (default) implementation of the navigation-function:

assessment_config$navigation
#> function (pool, session, direction = "NEXT") 
#> {
#>     current_item <- getValueForTestTaker(session, "current-item-in-pool", 
#>         default = 1, store = F)
#>     if (current_item == 0 && direction == "START") {
#>         current_item <- 1
#>     }
#>     else {
#>         if (direction == "NEXT") {
#>             if (current_item >= dim(assessment_env$pool)[1]) {
#>                 current_item <- -1
#>             }
#>             else {
#>                 current_item <- current_item + 1
#>             }
#>         }
#>         else if (direction == "PREVIOUS") {
#>             if (current_item > 0) {
#>                 current_item <- -1
#>             }
#>             else {
#>             }
#>         }
#>         else if (direction == "CANCEL") {
#>             current_item <- -2
#>         }
#>     }
#>     setValueForTestTaker(session, "current-item-in-pool", current_item)
#>     current_item
#> }
#> <bytecode: 0x558233b5eea8>
#> <environment: 0x558233b67e88>

This function can be overwritten by assigning a new function navigation = function(pool, session, direction="NEXT") with the same signature. In this new function, we first define the booklets. In the next step, we create a variable current_booklet that stores the booklet assigned to the current test-taker.

To achieve persistence, we use the function getValueForTestTaker(). The following arguments are used: The first argument is the object session (i.e., the session variable with which the function navigation was called). The second argument "current-booklet" is a self-chosen name for the booklet variable. The third argument is the default value which should be used if there is no entry with the name "current-booklet" for this session yet. Here we use the R function sample to randomly select a booklet. Finally, we pass TRUE for the store argument to save the selected booklet for this session and not re-set it on the next call.

The remaining part of the function is almost unchanged. The variable current_item refers to the row index of the current item in the item_pool. To initialize the current_item we use the first item defined for a particular booklet: current_item <- booklets[booklets$Booklet==current_booklet,"ItemIndex"][1]. To update the current_item we first find the row of the current item in the item_pool as current_item_index <- which(booklets[booklets$Booklet==current_booklet,"ItemIndex"]==current_item), update the current_item_index according to the requested navigation direction and then store the current_item using the booklet design:

assessment_config$navigation = function(pool, session, direction="NEXT"){

  booklets <- data.frame(Booklet = c(1,1,1,2,2,2),
                         ItemIndex=c(2,3,6,4,5,6))
  
  current_booklet <- getValueForTestTaker(session, "current-booklet", 
                        default=sample(unique(booklets$Booklet),1), store = T)
  
  current_item <- getValueForTestTaker(session, "current-item-in-pool", 
                                       default=0, 
                                       store = F)
  
  if (current_item==0  && direction=="START"){
    current_item <- booklets[booklets$Booklet==current_booklet,"ItemIndex"][1]
  }
  else
  {
    
    current_item_index <- which(booklets[booklets$Booklet==current_booklet,"ItemIndex"]==current_item)
    
    if (direction=="NEXT"){
      if (current_item_index >= length(booklets[booklets$Booklet==current_booklet,"ItemIndex"]))
      {
        current_item <- -1 # end the assessment
      }
      else
      {
        current_item_index <- current_item_index + 1 # move to the next item
        current_item <- booklets[booklets$Booklet==current_booklet,"ItemIndex"][current_item_index]
      }
    }
    else if (direction=="PREVIOUS"){
      if (current_item_index > 1){
        current_item_index <- current_item_index - 1 # move to the previous item
        current_item <- booklets[booklets$Booklet==current_booklet,"ItemIndex"][current_item_index]
      }
    }
    else if (direction=="CANCEL"){
      current_item <- -1 # end the assessment
    }
  }
  
  setValueForTestTaker(session, "current-item-in-pool",current_item)
  
  current_item
}

The value current_item <- -1 is used to identify that the assessment was finished for the current test-taker (either because all items of the selected booklet were administered or because the assessment was canceled).