Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keep UI Text Input after adding or removing Inputs

I'm building a small UI where a user will enter into a splitLayout row of text that builds a statement (not needed for this question) to solve a puzzle.

First Input

However, if the user decides he/she needs an additional row or less rows to solve the puzzle I'd like adding or removing a new row of inputs to NOT delete the remaining input rows.

Second Input Attempt * the gray is a placeholder.

How can I best achieve my desired result of:

enter image description here

Please find my trimmed code below. Thanks for your input.

library(shiny)

# Define UI
ui <- fluidPage(
  # Application title
  titlePanel("Identify A, B and C"),
  sidebarLayout(
    sidebarPanel(width = 5,
                 helpText("Present a statement and receive a response: 1 is a Knight who always tells the truth, 2 is a Knave who always lies, and 3 is a Normal who can do either."),
                 # Number of Questions
                 numericInput(inputId = "Questions", label = "Number of Questions", 
                              value = 1, min = 1, max = 10, step = 1),
                 splitLayout(cellWidths = c("25%","70%"), 
                             style = "border: 1px solid silver;",
                             cellArgs = list(style = "padding: 3px"),
                             uiOutput("textQuestions"), uiOutput("textQuestions2"))
    ),
    mainPanel(
      # Right hand side output
    )
  )
)

# Define server logic 
server <- function(input, output) {
  ####### I don't want these to delete initially everytime??
  output$textQuestions <- renderUI({
    Questions <- as.integer(input$Questions)
    lapply(1:Questions, function(i) {
      textInput(inputId = paste0("Who", i), label = paste0(i, ". Ask:"), placeholder = "A")
    })
  })
  ########
  output$textQuestions2 <- renderUI({
    Questions <- as.integer(input$Questions)
    lapply(1:Questions, function(i) {
      textInput(inputId = paste0("Q", i) , label = paste0("Logic:"), 
                value = "", placeholder = "A == 1 & (B != 2 | C == 3)")
    })
  })
  ######
}

# Run the application 
shinyApp(ui = ui, server = server)
like image 601
Evan Friedland Avatar asked Apr 07 '17 09:04

Evan Friedland


1 Answers

It looks like someone already gave you an answer using uiOutput+renderUI, so I'm going to go the other route: using insertUI and removeUI.

Instead of having a numeric input for "number of questions", I replaced it with a button for "add question" and one for "remove question". I have a variable keeping track of how many questions there are. Every time "add question" is pressed, we add one row. When "remove question" is pressed, we remove the last row.

Here's the code:

library(shiny)

# Define UI
ui <- fluidPage(
  # Application title
  titlePanel("Identify A, B and C"),
  sidebarLayout(
    sidebarPanel(
      width = 5,
      helpText("Present a statement and receive a response: 1 is a Knight who always tells the truth, 2 is a Knave who always lies, and 3 is a Normal who can do either."),
      # Buttons to add/remove a question
      actionButton("add", "Add question"),
      actionButton("remove", "Remove question"),
      div(id = "questions",
          style = "border: 1px solid silver;")
    ),
    mainPanel(
      # Right hand side output
    )
  )
)

# Define server logic 
server <- function(input, output) {
  # Keep track of the number of questions
  values <- reactiveValues(num_questions = 0)

  # Add a question
  observeEvent(input$add, ignoreNULL = FALSE, {
    values$num_questions <- values$num_questions + 1
    num <- values$num_questions
    insertUI(
      selector = "#questions", where = "beforeEnd",
      splitLayout(
        cellWidths = c("25%","70%"), 
        cellArgs = list(style = "padding: 3px"),
        id = paste0("question", num),
        textInput(inputId = paste0("Who", num),
                  label = paste0(num, ". Ask:"),
                  placeholder = "A"),
        textInput(inputId = paste0("Q", num) ,
                  label = paste0("Logic:"),
                  placeholder = "A == 1 & (B != 2 | C == 3)")
      )
    )
  })

  # Remove a question
  observeEvent(input$remove, {
    num <- values$num_questions
    # Don't let the user remove the very first question
    if (num == 1) {
      return()
    }
    removeUI(selector = paste0("#question", num))
    values$num_questions <- values$num_questions - 1
  })


}

# Run the application 
shinyApp(ui = ui, server = server)

EDIT

OP requested a way to retrieve the user's input based on a question number. To do that:

  1. Add the following to the UI

    numericInput("question_num", "Show question number", 1),
    textOutput("question")
    
  2. Add the following to the server

    get_question <- function(q) {
      paste(
        input[[paste0("Who", q)]],
        ":",
        input[[paste0("Q", q)]]
      )
    }
    
    output$question <- renderText({
      get_question(input$question_num)
    })
    
like image 138
DeanAttali Avatar answered Nov 08 '22 18:11

DeanAttali