4

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.

user1471980
  • 10,127
  • 48
  • 136
  • 235
  • If the data you said is a single number, you should use `numericInput`. Otherwise, you'll need to do some verification and conversion in the server code (convert from string to numbers) – Xiongbing Jin Mar 23 '16 at 17:36
  • Two questions. (1) Do you know the maximum number of input boxes dynamically created? Or do you need to accept as many as the user wants? (2) Can you show an example UI of how you want to display the calculation results? Will that be textOutput associated textInput? – Kota Mori Mar 23 '16 at 23:58
  • 1) No maximum number of text boxes, it could be as many as user inputs. 2)yes, textOutput associated with textInput. Can they be side by side? – user1471980 Mar 24 '16 at 03:22
  • @KotaMori, I've added an image, are you able to see the image? – user1471980 Mar 24 '16 at 14:07
  • Sure. Do you really need to allow unlimited number of text boxes? Would 10, 50, or 100 be enough for your purpose? I am asking this because allowing unlimited number of text boxes would require more programming effort, as far as I can think of. If your goal is fulfilled with some large but limited number, I would recommend this option. – Kota Mori Mar 24 '16 at 14:58
  • @KotaMori, max would be 10. – user1471980 Mar 24 '16 at 16:37
  • I don't find `calcbtn` in the UI. `addbtn` is missing too. – Kota Mori Mar 29 '16 at 07:13
  • 1
    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 Mar 29 '16 at 07:17
  • @KotaMori, calcbtn is defined in the ui. When I click it, it updates textOutput one at a time. Let's say, I have 5 txtInputs in the ui dynamically generated, I have to click calcbtn, 5 times to have all of the outputs. I've just update the ui part with the latest. – user1471980 Mar 29 '16 at 12:45
  • 1
    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 Mar 29 '16 at 13:07
  • @KotaMori, when I click the calcbtn, all the txtOutput boxes should be updated at the same time. Is this doable? – user1471980 Mar 29 '16 at 13:10
  • 1
    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 Mar 30 '16 at 00:09
  • @KotaMori, when I click on addbtn when inputWork and inputGrowth text boxes empty, I get this error:missing value where TRUE/FALSE needed". Need to be able to add the textInput boxes then fill in inputWork and inputGrowth to calculate the output. – user1471980 Mar 30 '16 at 13:35
  • So, did my answer work as expected? – Kota Mori Mar 31 '16 at 00:08
  • @KotaMori, I really appreciate your help. It works but still some tweaks I have to do. For example, if inputWork and/or inputWork is empty and I click addbtn, I get this error on the ui: "Error: missing value where TRUE/FALSE needed" – user1471980 Mar 31 '16 at 12:49
  • @KotaMori, would you have time to chat today for a little? – user1471980 Mar 31 '16 at 13:12
  • 1
    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 Mar 31 '16 at 14:33
  • 1
    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 Mar 31 '16 at 14:38
  • @KotaMori,Thanks again, sorry for all these questions. You've been extremely helpful. – user1471980 Mar 31 '16 at 15:07
  • @KotaMori, I've created another question with your recommendations. http://stackoverflow.com/questions/36342321/how-do-you-insert-inputslider-bux-dynamically-inot-shiny-application any ideas? – user1471980 Mar 31 '16 at 20:29

2 Answers2

2

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))
Kota Mori
  • 6,510
  • 1
  • 21
  • 25
  • sorry, I forgot to mention. Output needs to be generated by a command button. Once all input in place, user needs to be able to press a submitbutton and output boxes will populate. Would you be able to modify this, and I take it from there. Thanks again!!! – user1471980 Mar 24 '16 at 18:43
  • Also a button to clear all fields without refreshing the page? – user1471980 Mar 24 '16 at 18:47
  • [Here](http://stackoverflow.com/questions/24265980/reset-inputs-button-in-shiny-app) is a way to clear all fields – Zediiiii Mar 24 '16 at 20:15
  • You can do that too. Add a button and rewrite `renderText` part. It's your task! Hint: `isolate` or `observeEvent`. – Kota Mori Mar 24 '16 at 23:27
  • @user1471980 you can use the `reset()` function from the `shinyjs` package to clear inputs. – DeanAttali Mar 27 '16 at 23:31
  • @KotaMori, how do you capture the value inside the textInput which is created dynamically? I need to capture this value to multiply with another textInput – user1471980 Mar 28 '16 at 17:57
  • @KotaMori, sorry for all of these messages. I've modified the original post with what you've recommended. I've added the calcbtn, when I click on the button, in one click all the projections boxes populate. Right now, I have to click on calcbtn multiple times to get the output. Any ideas? – user1471980 Mar 28 '16 at 20:04
1

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))
Kota Mori
  • 6,510
  • 1
  • 21
  • 25