Recursively modifying sublists of a nested list while preserving its structure

I have a nested list called inputs:

library(htmltools)
library(shiny)

inputs = tagList(
  selectInput('first', 'FIRST', letters), 
  checkboxInput('second', 'SECOND')
)

str(inputs, max.level = 1)
List of 2
 $ :List of 3
  ..- attr(*, "class")= chr "shiny.tag"
  ..- attr(*, "html_dependencies")=List of 1
 $ :List of 3
  ..- attr(*, "class")= chr "shiny.tag"
 - attr(*, "class")= chr [1:2] "shiny.tag.list" "list"

All sublists of class shiny.tag have elements 'name', 'attribs' and 'children'. What I would like to do is apply some function to all such sublists for whom name == 'label' (see inputs[[1]][["children"]][[1]] for an example) but preserve the original structure of the inputs list while doing so.

To do this, I defined a recursive function hideLabel:

hideLabel <- function(tags) {
  
  lapply(tags, function(x) {

    if(inherits(x, 'shiny.tag')) {
      if(x$name == 'label') {
        tagAppendAttributes(x, style = 'display:none;')
      } else {
        hideLabel(x$children)
      }
      
    } else {
      return(x)
    }
  })
} 

Here is the output of applying hideLabel to the inputs list:

res = hideLabel(inputs)

str(res, max.level = 1)
List of 2
 $ :List of 2
 $ :List of 1

As shown above, hideLabel does not return a list of the same structure as the original list inputs (compare the output of str in the first code chunk with the output of str in the third chunk above). I was wondering if someone could help me understand why the function is doing this and how it could be modified? I have tried rewriting it several times to no avail.

I got it to work after thinking about what the function was returning at each stage. Here is the updated function:

hideLabel <- function(x) {
  
  children = x$children
  
  x$children = lapply(children, function(y) {
    
    if(inherits(y, 'shiny.tag')) {

      if(y$name == 'label') tagAppendAttributes(y, style = 'display:none;') else hil(y)      

    } else return(y)
    
  })
  
  return(x)  
}

This preserves the structure of the original list:

inputs_new = lapply(inputs, hideLabel)

str(inputs_new, max.level = 1)
List of 2
 $ :List of 3
  ..- attr(*, "class")= chr "shiny.tag"
  ..- attr(*, "html_dependencies")=List of 1
 $ :List of 3
  ..- attr(*, "class")= chr "shiny.tag"

NOTE: The class of the overall list changes though from shiny.tag.list to just list. Would anyone know how to prevent this from happening? I know I could use do.call(tagList, inputs_new) to manually add the shiny.tag.list class back on but that seems hacky.

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.