Increasing numbers in a datatable with observeEvent


#1

Hello to all! My shiny app allows you to create a table after entering the input values. every time I press the action button, a row is generated. I would also like every time I press the action button the value of "item" increments of one, so that it is corresponding to the number of rows created. How can I correctly use "observeEvent" and "reactiveBinding" or "reactiveValue"?
Thank you

This is my code:

library(shiny)   


ui <- fluidPage(
 
             sidebarLayout( 
               
               
               sidebarPanel(width=3, 
    
  
  textInput('NewID', HTML('<h5><b>Enter Name</b></h5>')), 
 
  
  br(),
  
  fluidRow(
    column(2,  HTML('<h5><b>A</b></h5>')),
    column(4, numericInput("NewVal3", label = NULL, value = NULL)),
    column(2, HTML('<h5><b>B</b></h5>')), 
    column(4, numericInput("NewVal4", label = NULL, value = NULL))
  ),
  fluidRow(
    column(2, HTML('<h5><b>C</b></h5>')),
    column(4, numericInput("NewVal5", label = NULL, value = NULL)),
    column(2,  HTML('<h5><b>D</b></h5>')), 
    column(4, numericInput("NewVal6", label = NULL, value = NULL))
  ),
  fluidRow(
    column(2, HTML('<h5><b>E</b></h5>')),
    column(4, numericInput("NewVal7", label = NULL, value = NULL)),
    column(2,  HTML('<h5><b>G</b></h5>')), 
    column(4, numericInput("NewVal8", label = NULL, value = NULL))
  ),
  
  br(),
  
  # action button Update Table
  actionButton("goButton", "Update Table",icon("cloud-upload"), 
               style="width: 100%; height: 60px; color: white; background-color: #337ab7; border-color: #2e6da4"),
  
  br()
  
  
               ),
  
  
  # mainPanel for displaying outputs 
  mainPanel(
    
    tabsetPanel(
      id = 'dataset02',
     
      tabPanel("Edit Table",
               br(),
               dataTableOutput("table3"))
      
      
    ))))
  
  
  
  # Define server logic to read selected file ----
  server <- function(input, output, session) {
  
  
  
  mydata3 = data.frame(Name=letters[NULL], Item=sample(NULL),Piece=sample(NULL), A=sample(NULL), B=sample(NULL), 
                       C=sample(NULL), D=sample(NULL), E=sample(NULL), G=sample(NULL))
  
  output$table3 <- renderDataTable( df3())
  df3 <- eventReactive(input$goButton, {
    if(input$NewID!=""  
       && !is.null(input$NewVal3) && !is.null(input$NewVal4) && !is.null(input$NewVal5) 
       && !is.null(input$NewVal6) && !is.null(input$NewVal7) && !is.null(input$NewVal8)
       && input$goButton>0)
     
    {
      
      
      i <- 0
      makeReactiveBinding('i')
      observeEvent(input$goButton,{
        i <<- i+1
      })
      
      
      
      newrow = data.frame(
        Name = input$NewID,
        Item = i,           ####!!!!  INCREASING NUMBERS  !!!!
        Piece = 1,                      
        A = input$NewVal3,
        B = input$NewVal4,
        C = input$NewVal5,
        D = input$NewVal6,
        E = input$NewVal7,
        G = input$NewVal8,
        
        LOG_G = (if(input$NewVal8!=0)  {LOG_G =round(log10(input$NewVal8), digits=2)}
                   else{LOG_G = -30}))  
      mydata3 <<- rbind(mydata3, newrow)
    }
    mydata3
  }, ignoreNULL = FALSE)
  
  
  
  }

# Create Shiny app ----
shinyApp(ui, server)


#2

The simplest way to do this, using your existing code (with only a few minor changes), is to move your i assignment and its observeEvent call outside of the eventReactive block. It is recommended practice to not use reactive and observe functions within one another.

Some other minor changes:

  1. I started i at 1 b/c it was skipping from 0 to 2 if I didn't.
  2. I added a req function to the observeEvent statement so that the item count does not increase when all of the required fields (all of them, as far as I could tell) are not filled in.
  3. I changed the default value (the value argument) for your textInput to NULL so that it was easier to include in the req statement.

As a note, you could easily use an if statement similar to what you have in your eventReactive call to make sure that the inputs are not NULL values, but the req function does that for you with less typing, so it is a time saver!

Here is the full code with my changes:

library(shiny)   


ui <- fluidPage(
  
  sidebarLayout( 
    
    
    sidebarPanel(width=3, 
                 
                 
                 textInput('NewID', HTML('<h5><b>Enter Name</b></h5>'),
                           value = NULL), 
                 
                 
                 br(),
                 
                 fluidRow(
                   column(2,  HTML('<h5><b>A</b></h5>')),
                   column(4, numericInput("NewVal3", label = NULL, value = NULL)),
                   column(2, HTML('<h5><b>B</b></h5>')), 
                   column(4, numericInput("NewVal4", label = NULL, value = NULL))
                 ),
                 fluidRow(
                   column(2, HTML('<h5><b>C</b></h5>')),
                   column(4, numericInput("NewVal5", label = NULL, value = NULL)),
                   column(2,  HTML('<h5><b>D</b></h5>')), 
                   column(4, numericInput("NewVal6", label = NULL, value = NULL))
                 ),
                 fluidRow(
                   column(2, HTML('<h5><b>E</b></h5>')),
                   column(4, numericInput("NewVal7", label = NULL, value = NULL)),
                   column(2,  HTML('<h5><b>G</b></h5>')), 
                   column(4, numericInput("NewVal8", label = NULL, value = NULL))
                 ),
                 
                 br(),
                 
                 # action button Update Table
                 actionButton("goButton", "Update Table",icon("cloud-upload"), 
                              style="width: 100%; height: 60px; color: white; background-color: #337ab7; border-color: #2e6da4"),
                 
                 br()
                 
                 
    ),
    
    
    # mainPanel for displaying outputs 
    mainPanel(
      
      tabsetPanel(
        id = 'dataset02',
        
        tabPanel("Edit Table",
                 br(),
                 dataTableOutput("table3"))
        
        
      ))))



# Define server logic to read selected file ----
server <- function(input, output, session) {
  
  
  
  mydata3 = data.frame(Name=letters[NULL], Item=sample(NULL),Piece=sample(NULL), A=sample(NULL), B=sample(NULL), 
                       C=sample(NULL), D=sample(NULL), E=sample(NULL), G=sample(NULL))
  
  output$table3 <- renderDataTable( df3())
  
  i <- 1
  makeReactiveBinding('i')
  observeEvent(input$goButton,{
    req(input$NewVal3, input$NewVal4, input$NewVal5,
        input$NewVal6, input$NewVal7, input$NewVal8,
        input$NewID)
    i <<- i+1
  })
  
  df3 <- eventReactive(input$goButton, {
    if(input$NewID!=""  
       && !is.null(input$NewVal3) && !is.null(input$NewVal4) && !is.null(input$NewVal5) 
       && !is.null(input$NewVal6) && !is.null(input$NewVal7) && !is.null(input$NewVal8)
       && input$goButton>0)
      
    {
      
      
      

      
      
      newrow = data.frame(
        Name = input$NewID,
        Item = i,           ####!!!!  INCREASING NUMBERS  !!!!
        Piece = 1,                      
        A = input$NewVal3,
        B = input$NewVal4,
        C = input$NewVal5,
        D = input$NewVal6,
        E = input$NewVal7,
        G = input$NewVal8,
        
        LOG_G = (if(input$NewVal8!=0)  {LOG_G =round(log10(input$NewVal8), digits=2)}
                 else{LOG_G = -30}))  
      mydata3 <<- rbind(mydata3, newrow)
    }
    mydata3
  }, ignoreNULL = FALSE)
  
  
  
}

# Create Shiny app ----
shinyApp(ui, server)

#3

@tbradley Thank you so much for the perfect explanation and for the code!