List of List is not producing a list of lists


#1

Hi,

I am trying to produce a list of lists - a <- append(a,list(b)), instead of just a list of elements. The problem I am having is that instead of getting a list of lists, I get a list of lists of lists. Please see program and output below

#CODE

library(shiny)
library(shinyjs)
firstUI <- function(id) { uiOutput(NS(id, "first")) }

firstServer <- function(input, output, session){#, a) {
  ns = session$ns
  # returnedValue = NULL
  output$first <- renderUI({
    
    # selectInput(ns("select"), h4("Select"), paste0(isolate(a()), letters[1:4]))
    selectInput(ns("select"), h5(strong("Please select from the list")), choices = c("", "a", "b", "c", "d"), multiple=TRUE, selectize=TRUE)
    
  })
  # res <- reactive({
  #  if (length(input$select) > 1) {
  #   paste0(input$select)
  #} else {
  # ""
  #  }
  #  })
  returnedValue <- reactive({paste0(input$select)})
  return(returnedValue)
}


removeFirstUI <- function(id) {
  removeUI(selector = paste0('#', NS(id, "first")))
}

addRmBtnUI <- function(id) {
  ns <- NS(id)
  tags$div(
    actionButton(inputId = ns('insertParamBtn'), label = "Add"),
    actionButton(ns('removeParamBtn'), label = "Remove"),
    hr(),
    tags$div(id = ns('placeholder'))
  )
}

addRmBtnServer <- function(input, output, session, moduleToReplicate, ...) {
  ns = session$ns
  params <- reactiveValues(btn = 0, inputFiles = list())
  observeEvent(input$insertParamBtn, {
    params$btn <- params$btn + 1
    params$inputFiles[[params$btn]] <- callModule(moduleToReplicate$server, id = params$btn, ...)
    insertUI(
      selector = paste0('#', ns('placeholder')),
      ui = moduleToReplicate$ui(ns(params$btn))
    )
  })
  
  observeEvent(input$removeParamBtn, {
    moduleToReplicate$remover(ns(params$btn))
    params$btn <- params$btn - 1
  })
  
  return(params)
}
ui <- fluidPage(
  addRmBtnUI("addRm"),
verbatimTextOutput("text", placeholder = TRUE),
actionButton("saveBTN", "Press the save button to end"),
verbatimTextOutput("list"),
verbatimTextOutput("listOfLists")

)
server <- function(input, output, session){
  
  comp <- callModule(
    addRmBtnServer, id = "addRm",
    moduleToReplicate = list(
      ui = firstUI,
      server = firstServer,
      remover = removeFirstUI
    )
  )
 
  myValues <- reactiveValues()
  observe({
    if(comp$btn>0 && length(comp$inputFiles[[comp$btn]]())  > 1){
      myValues$fList <- c(isolate(myValues$fList), isolate(list(comp$inputFiles[[comp$btn]]())))
    }
  })
   
 output$listOfLists<-renderPrint({
     result <- receivelist(myValues$fList)
    shinyjs::show("saveBTN")
    paste(result$x, result$L)
   })
   
  
   receivelist <- function(myList){
    x <- list()
     #x <- extend(x, myList)
     x <- append(x, myList)
     L <- length(x)
     # print(paste(x, length(x)))
     list(x = x, L = L)
    
   }
}

shinyApp(ui = ui, server = server)

I was not able to paste the GUI so I am just pasting the text that appears in the GUI. As you can see every time a list is added to the previous list, the previous list is repeated before the new added list is displayed. What I would like to get is the 3 results below;
"c("a", "b") 3" "c("a", "b", "c") 3" "c("a", "b", "c", "d") 3"

In this block of code code, i defined the myValues$List - list(comp$inputFiles[comp$btn])) as a list because otherwise, I just get a list of elements. Could you please help me with this?

Thank you

  myValues <- reactiveValues()
  observe({
    if(comp$btn>0 && length(comp$inputFiles[[comp$btn]]())  > 1){
      myValues$fList <- c(isolate(myValues$fList), isolate(list(comp$inputFiles[[comp$btn]]())))
    }
  })

This is the output I am getting instead. How can I avoid the duplications?

#OUTPUT

Please select from the list
a
b
Please select from the list
a
b
c
Please select from the list
a
b
c
d

[1] "c(\"a\", \"b\") 6"               "c(\"a\", \"b\") 6"               "c(\"a\", \"b\", \"c\") 6"        "c(\"a\", \"b\") 6"              
[5] "c(\"a\", \"b\", \"c\") 6"        "c(\"a\", \"b\", \"c\", \"d\") 6"

List of lists output
#2

The problem I am seing is that every time I select one more item from the drop down of the inputBox, a new list gets created. What I would like to have is "c("a", "b", "c", "d") 1". The when the user presses the add button the input box with the drop down appears again so that I can make another selection. For example "c("a", "b") 1". The problem I am having is that I assume that a selected block is a list, but that is not the case, but every selection from the drop down menu is a list. What could I do to be able to get the entire block of selected items as a list?

Please select from the list
a
b
c
d

[1] "c("a", "b") 3" "c("a", "b", "c") 3" "c("a", "b", "c", "d") 3"


#3

I wrote the code expecting for it to do:
[1] "c("a", "b") 3" "c("a", "b", "c") 3" )
"c("a", "b", "c", "d") 3" instead of the result below.
[1] "c("a", "b") 6" "c("a", "b") 6" "c("a", "b", "c") 6" "c("a", "b") 6"
[5] "c("a", "b", "c") 6" "c("a", "b", "c", "d") 6"
In other words: if I select a, b and c through the selectInput dropdown, I would like to obtain "c("a", "b",c")1", Just one result because all the selected items belong to the same list, and not c("a", "b") 2", "c("a", "b", "c")2". I would like for all the selections to be part of the same list so that I can create lists of lists. The reason why I have an add and remove button is because every time the user presess the button, the selectINput drop down displays again. I would like to take the input of the second display also as a single list -make another combination of selected items. Every time the input is selected the function to append to the list is called to add the second combination of selected items to the previous one.


#4

This code…

observe({
    if(comp$btn > 0 && length(comp$inputFiles[[comp$btn]]())  > 1) {
      myValues$fList <- c(isolate(myValues$fList), isolate(list(comp$inputFiles[[comp$btn]]())))
    }
  })

…takes the existing myValues$fList and combines it with comp$inputFiles[[comp$btn]]() (wrapped in a list). The "previous" list is repeated because this line asks for the "new" list to be added on to the end of the existing list. If you want just the new value, then define myValues$fList as the current value of the object that holds the vector of selected files. The way reactivity works, every time the file selection is updated, the list will also update to reflect the latest selection.

But maybe this isn't what you're trying to accomplish? I'm having trouble understanding what your overall goal is, separate from the implementation. Do you mean that you want the user to be able to make a bunch of changes to their selection, but you just show the final list of selected items? Or do you want to capture each different selection they made along the way?

Put another way: how is what you want different from what this simple multi-select selectInput() does?

library(shiny)

ui <-  fluidPage(
  fluidRow(
    verbatimTextOutput('out'),
    selectInput('in', 'Options', state.name, multiple = TRUE, selectize = TRUE)
  )
)

server <- function(input, output, session) {
  output$out <- renderPrint(input$in)
}

shinyApp(ui = ui, server = server)

Also, in case it helps, here's a simple example of how c() acts on lists and lists of lists:

a <- list("One", "Two", 3, 4)
b <- list("Five", 6, "Seven")
c <- list(8, "Nine")

str(c(a, b))
#> List of 7
#>  $ : chr "One"
#>  $ : chr "Two"
#>  $ : num 3
#>  $ : num 4
#>  $ : chr "Five"
#>  $ : num 6
#>  $ : chr "Seven"

str(c(a, list(b)))
#> List of 5
#>  $ : chr "One"
#>  $ : chr "Two"
#>  $ : num 3
#>  $ : num 4
#>  $ :List of 3
#>   ..$ : chr "Five"
#>   ..$ : num 6
#>   ..$ : chr "Seven"

# This is like the code that runs
# inside your `observe()`
a <- c(a, list(b))
a <- c(a, list(c))

str(a)
#> List of 6
#>  $ : chr "One"
#>  $ : chr "Two"
#>  $ : num 3
#>  $ : num 4
#>  $ :List of 3
#>   ..$ : chr "Five"
#>   ..$ : num 6
#>   ..$ : chr "Seven"
#>  $ :List of 2
#>   ..$ : num 8
#>   ..$ : chr "Nine"

#5

Thank you for your reply. I have made a change to the program:

library(shiny)
library(shinyjs)
firstUI <- function(id) { uiOutput(NS(id, "first")) }

firstServer <- function(input, output, session){#, a) {
  ns = session$ns
  # returnedValue = NULL
  output$first <- renderUI({
    
    # selectInput(ns("select"), h4("Select"), paste0(isolate(a()), letters[1:4]))
    selectInput(ns("select"), h5(strong("Please select from the list")), choices = c("","a", "b", "c", "d"), multiple=TRUE) #, selectize=TRUE)
    
  })
  
  returnedValue <- reactive({paste0(input$select)})
  return(returnedValue)
}


removeFirstUI <- function(id) {
  removeUI(selector = paste0('#', NS(id, "first")))
}

addRmBtnUI <- function(id) {
  ns <- NS(id)
  tags$div(
    actionButton(inputId = ns('insertParamBtn'), label = "Add"),
    actionButton(ns('removeParamBtn'), label = "Remove"),
    hr(),
    tags$div(id = ns('placeholder'))
  )
}

addRmBtnServer <- function(input, output, session, moduleToReplicate, ...) {
  ns = session$ns
  params <- reactiveValues(btn = 0, inputFiles = list())
  observeEvent(input$insertParamBtn, {
    params$btn <- params$btn + 1
    params$inputFiles[[params$btn]] <- callModule(moduleToReplicate$server, id = params$btn, ...)
    insertUI(
      selector = paste0('#', ns('placeholder')),
      ui = moduleToReplicate$ui(ns(params$btn))
    )
  })
  
  observeEvent(input$removeParamBtn, {
    moduleToReplicate$remover(ns(params$btn))
    params$btn <- params$btn - 1
  })
  
  return(params)
}
ui <- fluidPage(
  addRmBtnUI("addRm"),
  verbatimTextOutput("text", placeholder = TRUE),
  verbatimTextOutput("list"),
  verbatimTextOutput("listOfLists")
  
)
server <- function(input, output, session){
  
  comp <- callModule(
    addRmBtnServer, id = "addRm",
    moduleToReplicate = list(
      ui = firstUI,
      server = firstServer,
      remover = removeFirstUI
    )
  )
  
  myValues <- reactiveValues()
  observe({
    if(comp$btn>0 && length(comp$inputFiles[[comp$btn]]())  > 1){
      myValues$fList <- c(isolate(list(comp$inputFiles[[comp$btn]]())))
      
    }
  })
  
  output$listOfLists<-renderPrint({
    myValues$fList
    result <- callMyList(myValues$fList)
    result <- sendMyList(result$x)
    result$myList
  })
  
}

callMyList <- function(myValues){
    x <- list()
    L = length(myValues)
    x <- append(x, myValues)
  list(x = x, L = L )
}

sendMyList <- function(myList){
  print(myList)
  
  list(myList = myList)
}

this is the output now. The drop down list from the selectInput function displays (a, b, c, d) every time I press the add button. The verticals (a, b) and (a,b, c) are the items selected from the drop down as they appear in the selectInput box after selection.

OTPUT1

Please select from the list
a
b

[[1]]
[1] "a" "b"

OUTPUT2

Please select from the list
a
b
Please select from the list
a
b
c

[[1]]
[1] "a" "b" "c"

and so on.

I was trying to make a list of the 2 lists to send the list of lists to a third function.
[[1]]
[1] "a" "b", [1] "a" "b" "c"

So since I cannot get the list of lists, what I am doing now is calling the third function every time I get one list. The function gets called many times; once per list selection and each list is processed individually.