Подтвердить что ты не робот

Кнопка Reset input в блестящем приложении

Я хотел бы реализовать кнопку ввода Reset в моем блестящем приложении.

Вот пример с двумя входами, в которых я использую функции обновления, чтобы вернуть значения к значениям по умолчанию:

library(shiny)

runApp(list(

  ui = pageWithSidebar(

    headerPanel("'Reset inputs' button example"),

    sidebarPanel(
      numericInput("mynumber", "Enter a number", 20),
      textInput("mytext", "Enter a text", "test"),
      tags$hr(),
      actionButton("reset_input", "Reset inputs")
    ),

    mainPanel(
      h4("Summary"),
      verbatimTextOutput("summary")
    )

  ),

  server = function(input, output, session) {

    output$summary <- renderText({
      return(paste(input$mytext, input$mynumber))
    })

    observe({
      input$reset_input
      updateNumericInput(session, "mynumber", value = 20)
      updateTextInput(session, "mytext", value = "test")
    })
  }

))

Что я хотел бы знать, есть ли функция, которая возвращает все значения по умолчанию? Это было бы полезно в случае нескольких входов.

Кроме того, я не уверен, что мое использование функции наблюдения, чтобы определить, когда была нажата кнопка действия, является "правильным способом" обработки кнопок действий?

4b9b3361

Ответ 1

В shiny не существует такой функции, но здесь есть способ сделать это, не имея необходимости в основном определять ваши входы дважды. Фокус в том, чтобы использовать uiOutput и обернуть входы, которые вы хотите использовать reset, в div, чей идентификатор изменяется на что-то новое при каждом нажатии кнопки reset.

library(shiny)

runApp(list(

  ui = pageWithSidebar(

    headerPanel("'Reset inputs' button example"),

    sidebarPanel(
      uiOutput('resetable_input'),
      tags$hr(),
      actionButton("reset_input", "Reset inputs")
    ),

    mainPanel(
      h4("Summary"),
      verbatimTextOutput("summary")
    )

  ),

  server = function(input, output, session) {

    output$summary <- renderText({
      return(paste(input$mytext, input$mynumber))
    })

    output$resetable_input <- renderUI({
        times <- input$reset_input
        div(id=letters[(times %% length(letters)) + 1],
            numericInput("mynumber", "Enter a number", 20),
            textInput("mytext", "Enter a text", "test"))
    })

  }
))

Ответ 2

Прежде всего, ваше использование наблюдателя является правильным, но есть еще один способ, который немного приятнее. Вместо

observe({
  input$reset_input
  updateNumericInput(session, "mynumber", value = 20)
  updateTextInput(session, "mytext", value = "test")
})

Вы можете изменить его на

observeEvent(input$reset_input, {
  updateNumericInput(session, "mynumber", value = 20)
  updateTextInput(session, "mytext", value = "test")
})

Также обратите внимание, что вам не нужно явно "возвращать" из функции renderText, последний оператор будет автоматически использоваться.


Относительно основного вопроса: решение Мэтью здорово, но есть также способ добиться того, чего вы хотите, без необходимости переместить весь свой пользовательский интерфейс на сервер. Я считаю, что лучше использовать свой пользовательский интерфейс в файле пользовательского интерфейса только потому, что разделение структуры и логики в целом является хорошей идеей.

Полное выражение об отказе от ответственности: мое решение включает использование пакета, который я написал. В моем пакете shinyjs есть функция reset, которая позволяет вернуть reset вход или часть HTML в исходное значение. Вот как настроить исходный код на желаемое поведение таким образом, чтобы он масштабировался до любого количества входов без необходимости добавлять код. Все, что мне нужно было сделать, это добавить вызов в useShinyjs() в пользовательском интерфейсе, добавить в форму атрибут "id" и вызвать reset(id) в форме.

library(shiny)

runApp(list(

  ui = pageWithSidebar(

    headerPanel("'Reset inputs' button example"),

    sidebarPanel(
      shinyjs::useShinyjs(),
      id = "side-panel",
      numericInput("mynumber", "Enter a number", 20),
      textInput("mytext", "Enter a text", "test"),
      tags$hr(),
      actionButton("reset_input", "Reset inputs")
    ),

    mainPanel(
      h4("Summary"),
      verbatimTextOutput("summary")
    )

  ),

  server = function(input, output, session) {

    output$summary <- renderText({
      return(paste(input$mytext, input$mynumber))
    })

    observeEvent(input$reset_input, {
      shinyjs::reset("side-panel")
    })
  }

))

Ответ 3

Вот еще один вариант, который работает как для статических, так и для динамических входов и не включает полностью реверсивные входы.

Он использует:

reactiveValuesToList, чтобы получить все начальные входные значения и (необязательно) любые динамические входные значения, которые затем инициализируются.

session$sendInputMessage для обновления значений для общих входов. Функции updateXyzInput вызывают это под капотом, как session$sendInputMessage(inputId, list(value = x, ...).

Каждый вход Shiny использует value для своего входного сообщения, и почти все будут обновляться с их входным значением as-is. Только два входа, которые я нашел, нуждаются в специальном корпусе - checkboxGroupInput, чтобы не отправлять NULL, когда ничего не проверено, и dateRangeInput, чтобы преобразовать его c(start, end) в list(start = start, end = end).

Вслепую reset ALL не может быть хорошей идеей (даже вкладки будут reset), но это можно легко адаптировать к reset фильтруемому набору входов.

library(shiny)

ui <- pageWithSidebar(
  headerPanel("'Reset inputs' button example"),

  sidebarPanel(
    numericInput("mynumber", "Enter a number", 20),
    textInput("mytext", "Enter text", "test"),
    textAreaInput("mytextarea", "Enter text", "test"),
    passwordInput("mypassword", "Enter a password", "password"),
    checkboxInput("mycheckbox", "Check"),
    checkboxGroupInput("mycheckboxgroup", "Choose a number", choices = c(1, 2, 3)),
    radioButtons("myradio", "Select a number", c(1, 2, 3)),
    sliderInput("myslider", "Select a number", 1, 5, c(1,2)),
    uiOutput("myselUI"),
    uiOutput("mydateUI"),
    tags$hr(),
    actionButton("reset_input", "Reset inputs")
  ),

  mainPanel(
    h4("Summary"),
    verbatimTextOutput("summary")
  )
)

server <- function(input, output, session) {

  initialInputs <- isolate(reactiveValuesToList(input))

  observe({
    # OPTIONAL - save initial values of dynamic inputs
    inputValues <- reactiveValuesToList(input)
    initialInputs <<- utils::modifyList(inputValues, initialInputs)
  })

  observeEvent(input$reset_input, {
    for (id in names(initialInputs)) {
      value <- initialInputs[[id]]
      # For empty checkboxGroupInputs
      if (is.null(value)) value <- ""
      session$sendInputMessage(id, list(value = value))
    }
  })

  output$myselUI <- renderUI({
    selectInput("mysel", "Select a number", c(1, 2, 3))
  })

  output$mydateUI <- renderUI({
    dateInput("mydate", "Enter a date")
  })

  output$summary <- renderText({
    return(paste(input$mytext, input$mynumber))
  })
}

shinyApp(ui, server)