Search code examples
rshinyrscript

In R shiny, how do I add functionality to the action button "Add"?


I am working on the R shiny app. I have created Tab1 and Tab2 in Shiny, and what I am attempting to do is make the datatable visible in "Tab2" once I fill in the below forms and hit the "Add" button.

Summary

When the user enters information on "SchoolId, UserId, class, result" in Tab1 and clicks the "Add" button, the Datatable in "Tab2" should appear.

Also, once the user presses the "Add" button, the fields "SchoolId," "UserId," and so on should be empty, ready for the user to fill in the data of the second row in "Tab2."

Issue:

I am sure that I am missing something here to build a server-level connection for the "Add" button, because I can't fill in the details for the second row in Tab2 because since "Add" button is not working.

Could someone help to fix this issue?

library(shiny)
library(shinyBS)
library(stringr)
library(Hmisc)
library(rhandsontable)
library(shinydashboard)
library(DT)
library(V8)

ui <- fluidPage(
  fluidRow(tabsetPanel(id='tabs'
                           , tabPanel("Tab1", uiOutput("tabP1"))
                           , tabPanel("Tab2", uiOutput("tabP2"))
    )
   
  )
)

server <- function(input, output, session) {
 output$tabP1 <- renderUI({
    tabPanel("Tap1"
             , div(id = "form"
                   , textInput("schoolId *", label="SchoolId" )
                   , selectInput("userId", label="UserId"
                                 , choices = list("UserA" = "UserA", "UserB" = "UserB",
                                                  
                                                  "UserC" = "UserC")
                                                  
                                                  , selected = "UserA")
                   
                   
                   , textInput("class", value = NA, label = "class")
                   
                   , selectInput("result", label="result"
                                 , choices = list("PASS" = "PASS", "FAIL" ="FAIL" ), selected = "")
                  
             )
             
             , actionButton("add", "Add")
    )
  })
  
 
  # -------------------- Tab2  ----------------------------------
  
  observeEvent(input$add,{
    req(input$schoolId,input$userId,input$class,input$result)
    tmp<-data.frame(SCHOOLID=input$schoolId, USERID=input$userId
                    , CLASS= input$class
                    , RESULT=input$result
                    
    )
    
    df <- rbind(df,tmp)
  })
  output$DT2 <- DT::renderDataTable({
    df
  })
  
  output$tabP2 <- renderUI({
    tabPanel("View"
             , DT::dataTableOutput("DT2")
             , hr()
             , hidden(downloadButton('downloadData', 'Download'))
             
    )
  })
  
}

shinyApp(ui, server)

Solution

  • You want to use something like reactive or reactiveValues for values that can be changed over and over. To hide the table until a button is clicked, use a conditionalPanel based on the output of the button (it reveals how many times it has been clicked).

    I have implemented these things in your code below:

    EDIT: Replying to your first comment as well

    library(shiny)
    library(stringr)
    library(shinydashboard)
    library(tidyverse)
    library(DT)
    
    ui <- fluidPage(
      fluidRow(tabsetPanel(id='tabs', 
                           tabPanel("Tab1",
                                    div(id = "form", 
                                        textInput("schoolId", label="SchoolId *" ),
                                        selectInput("userId", label="UserId", choices = c("UserA", "UserB", "UserC"),selected = "UserA"), 
                                        textInput("class", label = "class"), 
                                        selectInput("result", label="result", choices = c("PASS", "FAIL" ))
                                        ),
                                    actionButton("add", "Add")
                                    ), 
                           tabPanel("Tab2", 
                                    tabPanel("View", 
                                             conditionalPanel("input.add != 0", 
                                                              DTOutput("DT2"), hr(), downloadButton('downloadData', 'Download'))
                                             )
                                    )
                           )
               )
    )
    
    server <- function(input, output, session) {
      store <- reactiveValues()
      
      observeEvent(input$add,{
        new_entry <- data.frame(SCHOOLID=input$schoolId, USERID=input$userId
                                , CLASS= input$class
                                , RESULT=input$result)
        
        if("value" %in% names(store)){
          store$value<-bind_rows(store$value, new_entry)
        } else {
          store$value<-new_entry
        }
        # If you want to reset the field values after each entry use the following two lines
        for(textInputId in c("schoolId", "class")) updateTextInput(session, textInputId, value = "")
        updateSelectInput(session, "userId", selected = "UserA")
        updateSelectInput(session, "result", selected = "PASS")
      })
      output$DT2 <- renderDT({
        store$value
      })
      
    }
    
    shinyApp(ui, server)