4
votes

ui code:

===

library(shiny)

  shinyUI(

    # Use a fluid Bootstrap layout
    fluidPage(    


      # Generate a row with a sidebar
      sidebarLayout(      


        # Define the sidebar with one input
        sidebarPanel(
          sliderInput("capacity", "Current Capacity:", 
                      min=0, max=100, value=10),
          c(list(
            textInput("service", "Service Component Name", ""),
            actionButton("addbtn", "Add Component"))),
            #lapply(seq(10), function(i) uiOutput(paste0("ui", i)))

            br(),
            br(), 
            br(),
            br(),
            br(),
          actionButton("calcbtn", "Calculate Projection")




        ),



        # Create a spot for the barplot
        mainPanel(
          textInput("inputWork","Volume", width="200px"),
          textInput("inputGrowth","Growth Rate", width="100px"),
          lapply(seq(10), function(i) uiOutput(paste0("ui", i)))
          #tags$p("Web"),
          #verbatimTextOutput("input_type_text")

        )

      )
    )
  )

server code:

   server <- function(input, output) 
{
  observeEvent(input$addbtn, {
    n <- isolate(input$addbtn)
    if (n == 0) return()

    # create n-th pair of text input and output
    output[[paste0("ui", n)]] <- renderUI(
      list(textInput(paste0("textin", n), isolate(input$service)),
           textOutput(paste0("textout", n))))

    # display something in the output
    output[[paste0("textout", n)]] <- renderText({
      work<-as.numeric(input$inputWork)
      growth<-as.numeric(input$inputGrowth)
      print(growth)


     #paste("projection", (100+growth)*as.numeric(input[[paste0("textin", n)]]))
    })
  })
  observeEvent(input$calcbtn, {
    n <- isolate(input$calcbtn)
    if (n == 0) return()

    output[[paste0("textout", n)]] <- renderText({
      work<-as.numeric(input$inputWork)
      growth<-as.numeric(input$inputGrowth)
      project<-growth+as.numeric(input$service)

      print(growth)
      print(project)

      paste("projection", ((1+growth/100)*as.numeric(input[[paste0("textin", n)]])))
    })
  })
}

This is what I am trying to do. This code will have an initial text box and submit button. User put a text in the first input text, clicks the submitbutton, a new text generated in the main panel. A user can do this multiple times to create multiple textInput boxes in the main panel.

I also have a static another inputText box labeled Workload on top of the main panel.

So, this is what I am trying to do:

  1. User will insert data in workload textIntut (it needs to numeric).
  2. User will insert data into other dynamically generated textInput boxes (all need to be numeric).
  3. I will get the values from workload and all the other textboxes, do some calculations and projections and display data next to each dynamically generated textInput boxes, it would be great if I could insert textboxes next to the ones generate to display my output.

For example, I have data in my workload, I have generated Web_server, App_server textInput boxes. I will take the data from workload and devided that by the data in web_server, and display it next to the web_server textInput box (show the data in a textbox), do the same for the app_server textInput box.

Any ideas how I could do this in shiny? This is the image what I am trying to accomplish. Given the Workload Growth Rate taken from the user and other inputs from the User Input section, I will have to calculate and populate the respective textboxes.

2
Assuming that calcbtn is defined somewhere in the UI, what is the expected behavior when you click it? Does this update all textOutputs dynamically created, or only one of them?Kota Mori
That behavior is expected from your code. It updates the textOutput one by one. Also, I guess from the code, that the textOutput won't be updated any more even if you change the textInput and click the calcbtn again. Now, what is your expected behavior when the calcbtn is clicked?Kota Mori
When asking a question, you should not copy and paste ui.R and server.R separately. With them people have to make a folder, and make two files just to try your code. Instead, prepare a set of codes that one can simply copy onto his or her editor and run it.Kota Mori
Unfortunately, no. It seems you are updating your question after receiving answers. You should not do that because If you change the question, this thread becomes useless to other people who see this later. If your original question is solved, just accept and make a new thread if necessary.Kota Mori
In addition, when asking a question, try to make a minimal reproducible example. Your current question sounds like you are asking people to identify a bug in your code. Instead, just describe what you want to do, and how you got stuck. Then people can help you more.Kota Mori

2 Answers

2
votes

The code below implements:

  1. Add text input (and output) when a button is clicked (up to 10).
  2. Each text output displays some message using input information.

Note:

  • Text outputs appear below, not next to, the input. This is more about design issue. I am not very familiar with HTML or CSS, sorry.
  • This does no computation at all. It is your task to add more components and change the contents of renderText as you wish.
  • I used textOutput for displaying computation outcomes, but your intent may be using textInput. In general, you should use textOutput for showing something, although it is possible to use input object as if output.
  • I used textInput, but if the input should be always numbers, you may instead use numericInput, as one of the comments suggest.

Have fun.

library(shiny)

ui <- c(list(
  textInput("service", "Service Component Name", ""),
  actionButton("addbtn", "add")),
  lapply(seq(10), function(i) uiOutput(paste0("ui", i)))
)


server <- function(input, output) 
{
  observeEvent(input$addbtn, {
    n <- input$addbtn
    if (n == 0) return()
    if (n > 10) return()

    # create n-th pair of text input and output
    output[[paste0("ui", n)]] <- renderUI(
      list(textInput(paste0("textin", n), isolate(input$service)),
           textOutput(paste0("textout", n))))

    # display something in the output
    output[[paste0("textout", n)]] <- renderText({
      paste("you wrote", input[[paste0("textin", n)]])
    })
  })
}

runApp(list(ui = ui, server = server))
1
votes

A few tips for implementing your wish are:

  • renderText is checking for changes in its components and is executed when the value of a component is revised. This is why, with input$textin1, the update occurs right after something is typed in the text input.
  • isolate prevents a component to trigger the execution. With isolate(input$textin1), the revising the text input won't make update the textOutput.
  • For a button to trigger the execution of renderText you can simply add the button within the renderText. Internally, when a button is clicked, its value increments. Hence, it is a value revision for a component that the function is checking, the execution occurs.
  • Finally, you need to do this for all textin1, textin2, ...

The following code implements this. Check the difference with the previous answer.

library(shiny)

ui <- c(list(
  textInput("service", "Service Component Name", ""),
  actionButton("addbtn", "add"), 
  actionButton("calcbtn", "calc")),
  lapply(seq(10), function(i) uiOutput(paste0("ui", i)))
)


server <- function(input, output) 
{
  observeEvent(input$addbtn, {
    n <- input$addbtn
    if (n == 0) return()
    if (n > 10) return()

    # create n-th pair of text input and output
    output[[paste0("ui", n)]] <- renderUI(
      list(textInput(paste0("textin", n), isolate(input$service)),
           textOutput(paste0("textout", n))))

    # display something in the output
    output[[paste0("textout", n)]] <- renderText({
      input$calcbtn
      paste("you wrote", isolate(input[[paste0("textin", n)]]))
    })
  })
}

runApp(list(ui = ui, server = server))