Shiny 为动态生成的textInputs添加字符限制等输入约束的问题
问题根因
你写的输入限制逻辑没有生效,核心是2个问题:
- 注册动态输入监听的逻辑包裹在惰性reactive表达式中,Shiny的reactive默认只有被其他输出、observer主动调用时才会执行,当前代码里没有任何位置触发这个reactive的求值,所以所有
observeEvent监听都没有被实际注册,自然不会生效。 - 监听注册逻辑没有和动态输入的生成触发条件绑定,每次切换气缸数重新生成输入框后,不会同步注册对应新输入的监听规则。
修正后的完整代码
library(shiny) library(tidyverse) mtcars2<-mtcars %>% rownames_to_column(var = 'CarName') shinyApp( ui = fluidPage( div( id = "car info", helpText("Enter a unique ID number for each car with a given number of cylinders"), radioButtons('cyls', 'No. of cylinders', choices = unique(mtcars2$cyl)), actionButton('select','Select'), uiOutput('textbox_ui') ), ), server = function(input, output, session){ cyl_list <- eventReactive(input$select,{ mtcars2 %>% filter(cyl == input$cyls) }) # 动态生成输入框 textboxes<- reactive({ lapply(seq_len(nrow(cyl_list())), function(i){ textInput(inputId = cyl_list()[[i,'CarName']], label = cyl_list()[[i,'CarName']]) }) }) output$textbox_ui <- renderUI({textboxes()}) # 修正点:用observeEvent监听cyl_list变化,只要动态输入的数据源更新,就自动注册对应监听 observeEvent(cyl_list(), { lapply(cyl_list()[['CarName']], function(j){ # 加ignoreInit = TRUE 避免刚生成输入框时就触发校验 observeEvent(input[[j]], ignoreInit = TRUE, { cat(suppressWarnings(is.na(as.numeric(input[[j]]))),'\n') if(nchar(input[[j]])>6){ updateTextInput(session, j, value = '') showModal(modalDialog(title = 'Error!','Character limit exceeded. Inputted value outside expected range. Please try again.', easyClose = T)) } }) }) }) } )
核心修改说明
- 把原本包裹注册监听逻辑的普通reactive,替换为
observeEvent(cyl_list(), {...}):observe类的逻辑是主动触发的,只要监听的cyl_list(也就是动态输入的数据源)发生变化,就会自动执行内部的注册逻辑,给新生成的所有输入框加上校验规则。 - 给
observeEvent(input[[j]])添加了ignoreInit = TRUE参数,避免输入框刚生成、还没有用户输入的时候就触发校验逻辑。 - 删掉了冗余的
paste0(j)写法,j本身就是输入框的ID,不需要额外拼接。
内容的提问来源于stack exchange,提问作者Mutator
相关产品推荐
相关产品推荐

