Как добавить / удалить поля ввода динамически с помощью кнопки в блестящей
Я пытался найти решение, как добавить и удалить поля ввода с помощью кнопки в блестящей. У меня нет исходного кода, так как я не достиг такого большого прогресса, но этот пример jQuery ( http://www.mkyong.com/jquery/how-to-add-remove-textbox-dynamically-with-jquery/) дает хорошее представление о том, чего я пытаюсь достичь. Это возможно в Блестящем или я должен использовать блестящий, чтобы сделать это? Заранее спасибо!
3 ответа
РЕДАКТИРОВАТЬ: я прочитал пример jQuery немного больше, и добавил фрагмент кода, делая то, что я думаю, что вы искали.
Я не знаю, jQuery, поэтому я не мог многое сделать из примера ссылки. Я угадал, что вы хотели, но я думаю, что ключевая идея заключается в использовании renderUI
а также uiOutput
даже если мое предложение здесь не соответствует действительности.
Чтобы переключить элемент пользовательского интерфейса:
Если вы специально не хотите использовать shinyjs
Вы могли бы сделать что-то вроде этого:
library(shiny)
ui <- shinyUI(fluidPage(
actionButton("btn", "Toggle Textbox"),
textOutput("btn_val"),
uiOutput("textbox_ui")
))
server <- shinyServer(function(input, output, session) {
output$btn_val <- renderPrint(print(input$btn))
textboxToggle <- reactive({
if (input$btn %% 2 == 1) {
textInput("textin", "Write something:", value = "Hello World!")
}
})
output$textbox_ui <- renderUI({ textboxToggle() })
})
shinyApp(ui, server)
Чтобы добавить и удалить элементы:
Прочитав немного примера jQuery, я думаю, что это похоже на то, что вы искали:
library(shiny)
ui <- shinyUI(fluidPage(
sidebarPanel(
actionButton("add_btn", "Add Textbox"),
actionButton("rm_btn", "Remove Textbox"),
textOutput("counter")
),
mainPanel(uiOutput("textbox_ui"))
))
server <- shinyServer(function(input, output, session) {
# Track the number of input boxes to render
counter <- reactiveValues(n = 0)
observeEvent(input$add_btn, {counter$n <- counter$n + 1})
observeEvent(input$rm_btn, {
if (counter$n > 0) counter$n <- counter$n - 1
})
output$counter <- renderPrint(print(counter$n))
textboxes <- reactive({
n <- counter$n
if (n > 0) {
lapply(seq_len(n), function(i) {
textInput(inputId = paste0("textin", i),
label = paste0("Textbox", i), value = "Hello World!")
})
}
})
output$textbox_ui <- renderUI({ textboxes() })
})
shinyApp(ui, server)
Проблема с этим подходом состоит в том, что каждый раз, когда вы нажимаете кнопку добавления или удаления, все поля ввода перерисовываются. Это означает, что любой вклад, который вы могли иметь для них, исчезает.
Я думаю, что вы могли бы обойти это, также сохраняя текущие значения ввода полей ввода в reactiveValues
объекта и установки значений из объекта в качестве начальных значений повторно отображаемых полей ввода с помощью value
вариант в textInput
, Я оставлю реализацию этого пока что.
Спасибо @Mikko Marttila за ответ. Я смог использовать это для своих целей. Кроме того, обращаясь к проблеме повторного рендеринга всех полей ввода, я нашел решение, работающее на этом ответе. Вы можете сохранить все пользовательские данные, используяreactiveValuesToList()
, затем вызовите реактивный список, чтобы установить каждое значение для соответствующего ввода пользователя в lapply()
заявление.
library(shiny)
ui <- shinyUI(fluidPage(
sidebarPanel(
actionButton("add_btn", "Add Textbox"),
actionButton("rm_btn", "Remove Textbox"),
textOutput("counter")
),
mainPanel(uiOutput("textbox_ui"))
))
server <- shinyServer(function(input, output, session) {
# Track the number of input boxes to render
counter <- reactiveValues(n = 0)
# Track all user inputs
AllInputs <- reactive({
x <- reactiveValuesToList(input)
})
observeEvent(input$add_btn, {counter$n <- counter$n + 1})
observeEvent(input$rm_btn, {
if (counter$n > 0) counter$n <- counter$n - 1
})
output$counter <- renderPrint(print(counter$n))
textboxes <- reactive({
n <- counter$n
if (n > 0) {
isolate({
lapply(seq_len(n), function(i) {
textInput(inputId = paste0("textin", i),
label = paste0("Textbox", i),
value = AllInputs()[[paste0("textin", i)]])
})
})
}
})
output$textbox_ui <- renderUI({ textboxes() })
})
shinyApp(ui, server)
РЕДАКТИРОВАТЬ: я завернулlapply()
заявление в isolate()
потому что это раздражает, когда поля повторно отрисовываются, когда вы пытаетесь ввести в поле
Вместо того, чтобы повторно отображать весь список входных данных, попробуйте следующее
Я отслеживаю все созданные файлы, удаляю последний созданный и повторно используюids
из удаленных. Я начинаю с начального поля (в этом нет реальной необходимости, но я предполагаю, что в реальном сценарии работы вы ожидаете, что по крайней мере 1 текстовое поле появится и увеличится после этого). Начать работу без начального поля просто.
Кроме того, я слежу за значениямиtextInput
ящики, которые в данный момент активны, в реактивном списке. Вам это точно понадобится
Наконец, я думаю, для двоихreactiveValues
У меня есть [inserted
иcounter
], один из них, возможно, лишний, но эй...
Надеюсь, поможет!
library(shiny)
ui <- fluidPage(
actionButton("insertBtn", "Insert"),
actionButton("deleteBtn", "Delete"),
h4("My boxes"),
# Initial box here to start with. Not needed but it is nice to have one :)
div(id = "box-1", textInput(inputId = "box-1", label = "box-1")),
div(id = "placeholder"),
h4('Box contents'),
verbatimTextOutput("my_inputs")
)
server <- function(input, output, session) {
## keep track of elements inserted and a counter of the elements
rv <- reactiveValues(
inserted = c("box-1"),
counter = 1
)
observeEvent(input$insertBtn, {
rv$counter <- rv$counter+1
serial <- rv$counter
id <- paste0('box-', serial)
rv$inserted <- c(rv$inserted, id)
insertUI(
selector = '#placeholder',
## wrap element in a div with id for ease of removal
ui = div(id = id,
textInput(inputId = id, label = paste0("box-", serial))
)
)
})
observeEvent(input$deleteBtn, {
req(rv$counter>0)
# removes the last one
id_to_remove <- rv$inserted[length(rv$inserted)]
removeUI(
## pass it in as JQuery selector
selector = paste0('#', id_to_remove)
)
rv$inserted <- rv$inserted[-length(rv$inserted)]
rv$counter <- rv$counter - 1
})
my_inputs <- reactive({
req(rv$inserted) # need to have some inputs
l <- reactiveValuesToList(input)
# regex of the union of all inputs. Note the starting input box-1
ids_regex <- paste(c("box-1", rv$inserted), collapse = "|")
l[grepl(ids_regex, names(l))]
})
output$my_inputs <- renderPrint({
my_inputs()
})
}
shinyApp(ui, server)
Большое спасибо