Vedha Viyash
Vedha Viyash

Reputation: 728

How to make changes reflect in many places when input is changed without ObserveEvent() in shiny

I have an input variable input$shop_id. Which is used to get data in server function using:

 observeEvent(input$shop_id,{id<<-input$shop_id})
`Data=dbGetQuery(connection_name,paste0("SELECT * FROM tab_name WHERE id_shop=",id"))`

That Data is further used to create dynamic UI using selectInput()

output$dependant=renderUI({
      selectInput("choice","Choose the Data you want to view",names(Data))
    })

I can't come up with the logic of the arrangement of these functions. I cannot get it to work. I have created a sample data and similar sample code for someone to try on:

library(shiny)
library(ggplot2)
ui=fluidPage(
  column(6,uiOutput("shop_select")),
  column(6,uiOutput("cust_select")),
  column(6,uiOutput("select3")),
  column(12,offset=6,uiOutput("plot"))
)
server = function(input, output) {
  #sample data
  shopdata=data.frame(id=c(1,2,3,4,5,6,7,8,9,10),name=c("a","b","c","d","e","f","g","h","i","j")) 
  cdata=data.frame(id=c(123,465,6798,346,12341,45764,2358,67,457,5687,4562,23,12124,3453,12112),
                   name=c("sadf","porhg","wetgfjg","hwfhjh","yuigkug","syuif","rtyg","dygfjg","rturjh","kuser","zzsdfadf","jgjwer","jywe","jwehfhjh","kuwerg"),
                   shop=c(1,2,1,2,4,6,2,8,9,10,3,1,2,5,7),
                   bill_total=c(12341,123443,456433,234522,45645,23445,3456246,23522,22345,23345,23454,345734,23242,232456,345456),
                   crating=c(4,4.3,5,1.2,3.2,4,3.3,2.4,3.8,3,3.2,3.3,1.4,2.8,4.1))
    output$shop_select=renderUI({
    selectInput("shop_id","Shop ID",shopdata$id)
  })
    output$cust_select=renderUI({
      selectInput("cust_id","Customer ID",cdata$id,multiple = T)
    })
    output$select3=renderUI({
      a=input$shop_id
      selectInput("choice","Choose the Data you want to view",names(cdata))
    })
    output$plot=renderUI({
      renderPlot({
        require(input$choice)
        plotOutput(
      ggplot(cdata,aes(x=cust_id,y=input$choice))
    )})})
}
shinyApp(ui=ui,server=server)

I know I am not clear on the question. Fixing the code which I posted is more than enough to clear my doubt. Basically, I just need to know what is the logic when we have to use while using a renderUI() which is dependent on another renderUI()

Upvotes: 1

Views: 90

Answers (2)

Nate
Nate

Reputation: 10671

If you want to set up a series of subsetting operations and then call renderUI()s on each subset, you will need to take advantage of Shiny's reactive({}) expressions.

Reactive expressions are code chunks that produce variables and their magic is that they "watch" for any changes to their input data. So in your case one you select a shop_id in the first UI element, the reactive expression detects that and updates itself, automatically!

Here is an example showing the updating, just select different shop_id's and watch the available cust_ids change on the fly.

library(shiny)
library(ggplot2)
library(tidyverse)
ui=fluidPage(
    column(6,uiOutput("shop_select")),
    column(6,uiOutput("cust_select")),
    column(6,uiOutput("select3")),
    column(12,offset=6,tableOutput("plot"))
)
server = function(input, output) {
    #sample data
    shopdata=data.frame(id=c(1,2,3,4,5,6,7,8,9,10),name=c("a","b","c","d","e","f","g","h","i","j")) 
    cdata=data.frame(id=c(123,465,6798,346,12341,45764,2358,67,457,5687,4562,23,12124,3453,12112),
                     name=c("sadf","porhg","wetgfjg","hwfhjh","yuigkug","syuif","rtyg","dygfjg","rturjh","kuser","zzsdfadf","jgjwer","jywe","jwehfhjh","kuwerg"),
                     shop=c(1,2,1,2,4,6,2,8,9,10,3,1,2,5,7),
                     bill_total=c(12341,123443,456433,234522,45645,23445,3456246,23522,22345,23345,23454,345734,23242,232456,345456),
                     crating=c(4,4.3,5,1.2,3.2,4,3.3,2.4,3.8,3,3.2,3.3,1.4,2.8,4.1))


    output$shop_select=renderUI({
        selectInput("shop_id","Shop ID",shopdata$id)
    })

    cdata_reactive <- reactive({
        req(input$shop_id)
        filter(cdata, shop == input$shop_id)
    })

    output$cust_select=renderUI({
        selectInput("cust_id","Customer ID",cdata_reactive()$id, multiple = T)
    })
    output$select3=renderUI({
        selectInput("choice","Choose the Data you want to view",names(cdata_reactive()))
    })
    output$plot <- renderTable({
        filter(cdata_reactive(), id %in% input$cust_id) %>%
                                   .[input$choice]
                                     })
}
shinyApp(ui=ui,server=server)

Upvotes: 1

divibisan
divibisan

Reputation: 12155

  1. A renderUI generates UI elements. Therefore it can only contain ui functions. You need to use it to generate the plotOutput and then use renderPlot separately to add content.
  2. The names you assign in the aes call are the names of variables in the data frame you provided. Therefore x should be id not the values of input$cust_id (which must be called as input$cust_id, since it refers to an input object.
  3. input$choice returns a string, not an object, so you can't use it normally in aes (recall that if this was a normal dataframe your aes would be aes(x=id, y=choice) not aes(x='id', y='choice'). Therefore, you need to use aes_ with the as.name function to convert those strings into proper variable names.
  4. What I think you want to do with input$cust_id is filter cdata to only include rows with the chosen id values. dplyr::filter is the best way to do that.
  5. Finally, you're missing a geom_* in your ggplot call which is needed to actually render your data.

If you replace your output$plot <- ... call with the below code it should work the way I think you want it to:

output$plot=renderUI({
        plotOutput('plotout')
        })

output$plotout <- renderPlot({
    ggplot(dplyr::filter(cdata, id %in% input$cust_id),
           aes_(x=as.name('id'),y=as.name(input$choice))) +
        geom_point()
})

As for the question in your title, you only need to use observeEvent if you want to limit the code in the expression to only run when a specific trigger occurs. Any reactive expression (reactive, observe, render_ etc.) will become invalidated and update itself if any reactive value (either a reactiveValues object or an input$...) changes. If you have an input$ or a reactive value in a render_ block, it will update if they change -- no observeEvent needed.

Upvotes: 1

Related Questions