0

I have the following piece of code in a shiny app. My goal is to generate the choices for the "cutFamily2" selectInput widget based on what the user chose for the "machine2" selectInput.

If I use corte2() instead of eval(paste0("corte",2)) on the observerEvent the app runs properly. The problem is that I want to use the paste0() because the integer "2" in eval(paste0("corte",2)) will be an argument of a function (function(data,n)) so I can easily generate corte1, corte2 and so on.

When I run it using eval(paste0("corte",2)) I am getting the "error in $: $ operator is invalid for atomic vectors" and the app won't even run. I tried to use enframe() to convert it to a tibble, then the app runs, but I get a "Unknown or uninitialised column: CutFamily" error and the SelectInput choices will be empty. I also tried [[ instead, but nothing.

Any ideas on how to solve the problem?

library(shiny)
library(shinydashboard)
library(feather)
library(tibble)
library(tidyverse)

Cortes = as_tibble(read_feather("Cortes.feather"))

ui <- dashboardPage(
    
    dashboardHeader(title="Setup"),
    
    dashboardSidebar(
        sidebarMenu(
            menuItem("Procedimento",tabName = "task_wizard",icon = icon("th"))
        )
    ),
    
    dashboardBody(
        tabItems(
            tabItem(tabName = "task_wizard",
                    selectInput(paste0("machine",2),"Selecione o tipo de máquina: ",choices = unique(Cortes$Machine)),
                    selectInput(paste0("cutFamily",2),"Selecione a área de trabalho: ",choices = NULL)
            )
        )
    )
)

server <- function(input, output) {

    assign(paste0("corte",2),reactive({
        filter(Cortes,Machine == input[[eval(paste0("machine",2))]])
    }))
    observeEvent(eval(paste0("corte",2)),{
        choices <- unique(eval(paste0("corte",2))$CutFamily)
        updateSelectInput(inputId = paste0("cutFamily",2),choices = choices)
    })
}

shinyApp(ui = ui, server = server)

and here is the Cortes tibble

> Cortes
# A tibble: 4 x 3
  Machine CutFamily           CutFeature  
  <chr>   <chr>               <chr>       
1 Torno   Torneamento Externo Faceamento  
2 Torno   Torneamento Externo Torneamento 
3 Torno   Torneamento Externo Chanframento
4 Torno   Torneamento Externo Canal radial

tks

  • 1
    Maybe use data.table? You can build text expressions on the LHS of assignment operations. This question really needs to be [edit]-ed to include {MCVE]. (Without an example I cannot follow your logic.) I think it might be a case of "cannot read your intent from erroneous code". – IRTFM Jun 15 '21 at 01:19
  • Tks @IRTFM. I tried to create a MCVE. See if it helps, pls. Coding is something new to me, so sorry if it is not the way it suppose to be. – Joaquim A Pinto Jun 15 '21 at 02:26
  • 1
    If you are new to coding, you should be avoiding things like `eval()` and `assign()`. They are not very R-like. Rather than creating separate variables with numbers in their name, keep related reactive elements in a reactive list: `reactiveVals()`. You can then index into this list using strings and not bothering with `eval()`. – MrFlick Jun 15 '21 at 03:35
  • My answer [here](https://stackoverflow.com/questions/67416620/how-can-i-create-reactive-datasets-dynamically-via-a-loop-in-the-server-section/67422105#67422105) demonstrates how you can populate and update the choices in one input widget based on the value selected in another. – Limey Jun 15 '21 at 09:34
  • tks @MrFlick, I will try it. @Limey, one reason I tried to avoid dynamically generated UI was because I wanted to use ``onclick`` on some inputs and I wasn't being able to, but I can just drop the onclick. Also I want the user to be able to create "n" tasks and when he chooses to create a 2nd task he will have available to him exactly the same inputs he had for the 1st task and I thought I would have a problem with repeated input names and I want to populate a data frame with those input values. That is why I thought of adding the "n" at the end. Can I avoid that with your proposition? tks – Joaquim A Pinto Jun 15 '21 at 11:04

1 Answers1

1

You can try this code -

library(shiny)

ui <- dashboardPage(
  
  dashboardHeader(title="Setup"),
  
  dashboardSidebar(
    sidebarMenu(
      menuItem("Procedimento",tabName = "task_wizard",icon = icon("th"))
    )
  ),
  
  dashboardBody(
    tabItems(
      tabItem(tabName = "task_wizard",
              selectInput(paste0("machine",2),"Selecione o tipo de máquina: ",choices = unique(Cortes$Machine)),
              selectInput(paste0("cutFamily",2),"Selecione a área de trabalho: ",choices = NULL)
      )
    )
  )
)

server <- function(input, output) {
  
  observe({
    choices <- unique(filter(Cortes,Machine == input[[paste0("machine",2)]])$CutFamily)
    updateSelectInput(inputId = paste0("cutFamily",2),choices = choices)
  })
}

shinyApp(ui = ui, server = server)
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • I get an error saying that I cannot access reactive value 'machine2' outside of a reactive consumer. The assign was to avoid "Error in <-: target of assignment expands to non-language object" – Joaquim A Pinto Jun 15 '21 at 13:25
  • Hmmm...Can you make your post reproducible by providing data and code to reproduce the problem so that we get the same error as you. – Ronak Shah Jun 15 '21 at 14:05
  • I think if you just use ``Cortes = tibble(Machine=c("Lathe","Lathe","CNC","CNC"),CutFamily=c("A","B","C","D"))`` you um reproduce it. I also just realize that ``eval(paste0("corte",2)`` workd just on the ``assign`` part, but not on the ``observerEvent``. For that I can get it to work only using ``corte2()``. – Joaquim A Pinto Jun 15 '21 at 14:39