【问题标题】:Keep UI Text Input after adding or removing Inputs添加或删除输入后保留 UI 文本输入
【发布时间】:2017-09-02 14:40:00
【问题描述】:

我正在构建一个小型 UI,用户将在其中输入 splitLayout 文本行,该文本行构建一个语句(此问题不需要)来解决难题。

但是,如果用户决定他/她需要附加或更少行来解决难题,我想添加或删除新的输入行不要删除剩余的输入行。

*灰色是占位符。

我怎样才能最好地达到我想要的结果:

请在下面找到我的修剪代码。感谢您的意见。

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)

【问题讨论】:

标签: r dynamic shiny textinput


【解决方案1】:

看起来有人已经使用uiOutput+renderUI 给了你答案,所以我要走另一条路:使用insertUIremoveUI

我没有为“问题数量”提供数字输入,而是将其替换为“添加问题”按钮和“删除问题”按钮。我有一个变量来跟踪有多少问题。每次按下“添加问题”,我们都会添加一行。当按下“删除问题”时,我们删除最后一行。

代码如下:

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)

编辑

OP 请求一种根据问题编号检索用户输入的方法。为此:

  1. 将以下内容添加到 UI

    numericInput("question_num", "Show question number", 1),
    textOutput("question")
    
  2. 将以下内容添加到服务器

    get_question <- function(q) {
      paste(
        input[[paste0("Who", q)]],
        ":",
        input[[paste0("Q", q)]]
      )
    }
    
    output$question <- renderText({
      get_question(input$question_num)
    })
    

【讨论】:

  • Dean,这正是我所需要的,谢谢,但由于我是 InsertUI 和 removeUI 的新手,你介意还提供调用用户输入值的方法吗?用一个简单的函数说(谁,Q)?
  • @EvanFriedland 在我的回答中添加了 EDIT
  • 在“19 小时”内你将获得赏金 :) 谢谢你的帮助。有没有一种简单的方法可以将所有 Who# 输入和 Q# 输入称为 2 个单独的列表?
  • 其实我相信这完全是一个单独的问题,我会自己做更多的搜索。谢谢院长。
【解决方案2】:

你可以将它存储在一个反应​​值中:

  global <- reactiveValues(ask = c(), logic = c())

  observe({
    Questions <- as.integer(input$Questions)
    lapply(1:Questions, function(i) {
      inputVal <- input[[paste0("Who", i)]]
      if(!is.null(inputVal)){
        global$logic[i] <- inputVal
      }
      inputValQ <- input[[paste0("Q", i)]]
      if(!is.null(inputValQ)){
        global$ask[i] <- inputValQ
      }
    })
  })

这将为您生成以下代码示例: 作为副作用,如果输入被删除然后重新获取,这些值也会被存储。

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) {
  global <- reactiveValues(ask = c(), logic = c())

  observe({
    Questions <- as.integer(input$Questions)
    lapply(1:Questions, function(i) {
      inputVal <- input[[paste0("Who", i)]]
      if(!is.null(inputVal)){
        global$ask[i] <- inputVal
      }
      inputValQ <- input[[paste0("Q", i)]]
      if(!is.null(inputValQ)){
        global$logic[i] <- inputValQ
      }
    })
  })
  ####### 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", value = global$ask[i])
    })
  })
  ########
  output$textQuestions2 <- renderUI({
    Questions <- as.integer(input$Questions)
    lapply(1:Questions, function(i) {
      textInput(inputId = paste0("Q", i) , label = paste0("Logic:"), value = global$logic[i],
                placeholder = "A == 1 & (B != 2 | C == 3)")
    })
  })
  ######
}

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

【讨论】:

  • BigD,感谢您的回复。我正在检查您的代码,但无法将 global$ask 和 $logic 与我想要的 uiOutput 连接起来。我还必须在 lapply 中交换名称,因为 global$logic 应该来自“Q”,而 global$ask 应该来自“Who”。感谢您向我指出 reactiveValues,因为它确实朝着我需要的答案方向发展。
  • 哦,是的,我在符号中混淆了一些东西,我更正了。但是,除了变量名之外,功能中是否缺少某些东西?当我运行代码时,值不会被重置,而是按需要保持 - 当你运行代码时你看到了什么?
  • 道歉**它确实存在,但在删除行后,是否可以重置不再在 ui 上查看的 textInputs?
  • 好问题:这就是我所说的“副作用”。我稍后会调查,这是肯定的。考虑重写闪亮的函数 renderUI 也会很有趣,这样你就不需要为小功能编写大代码块了;)
  • 我喜欢你的想法——我会在下飞机后回顾并编辑想想 renderDynamicUI 函数。干杯
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-15
  • 1970-01-01
  • 2014-01-28
  • 1970-01-01
  • 2020-03-15
  • 1970-01-01
相关资源
最近更新 更多