Rshiny CRUD 应用程序:使用选择输入而不是文本输入时用户输入崩溃

Posted

技术标签:

【中文标题】Rshiny CRUD 应用程序:使用选择输入而不是文本输入时用户输入崩溃【英文标题】:Rshiny CRUD app: User Input crashes when using selectize input instead of text input 【发布时间】:2019-02-15 07:56:06 【问题描述】:

我正在开发一个接受用户输入并提交到表格的 CRUD 应用程序。

由于某种原因,当我使用下拉选择选项而不是文本输入时。当我使用文本输入时,它很好并且可以正常工作。 SelectizeInput,使应用程序崩溃,由于某种原因我找不到错误。我哪里错了?


这是我的代码:

 library(shiny)
library(shinyjs)
library(shinythemes)




######################### Get table metadata. For now, just the fields ##########################
######################## Further development: also define field types  ##########################
####################### and create inputs generically                 ###########################

######## TABLE 1: ADD NEW PERSON
GetTableMetadata <- function() 
  fields <- c(
    id = "Id",
    name = "Tribe/Task Name",
    category = "Category",
    task_num = "Task Order",
    client_facing = "Client Facing?",
    completion = "Task Completed?"
  )

  result <- list(fields = fields)
  return (result)



########################## CREATE, READ, UPDATE, DELETE #######################################
#### CRUD



# Find the next ID of a new record
GetNextId <- function() 
  if (exists("responses") && nrow(responses) > 0) 
    max(as.integer(rownames(responses))) + 1
   else 
    return (1)
  


#C
CreateData <- function(data) 
  data <- CastData(data)
  rownames(data) <- GetNextId()
  if (exists("responses")) 
    responses <<- rbind(responses, data)
   else 
    responses <<- data
  


#R
ReadData <- function() 
  if (exists("responses")) 
    responses
  




#U
UpdateData <- function(data) 
  data <- CastData(data)
  responses[row.names(responses) == row.names(data),] <<- data


#D
DeleteData <- function(data) 
  responses <<-
    responses[row.names(responses) != unname(data["id"]),]





#######################################################################################
# Cast from Inputs to a one-row data.frame

CastData <- function(data) 
  datar <- data.frame(
    name = data["name"],
    category = data["category"],
    task_num = as.integer(data["task_num"]),
    stringsAsFactors = FALSE,
    client_facing = as.logical(data["client_facing"]),
    completion = as.logical(data["completion"])
  )

  rownames(datar) <- data["id"]
  return (datar)





# Return an empty, new record
CreateDefaultRecord <- function() 
  mydefault <-
    CastData(list(
      id = "0",
      name = "", 
      category ="",
      task_num = 2,
      client_facing = FALSE,
      completion = FALSE

    ))
  return (mydefault)


# Fill the input fields with the values of the selected record in the table
UpdateInputs <- function(data, session) 
  updateTextInput(session, "id", value = unname(rownames(data)))
  updateTextInput(session, "name", value = unname(data["name"]))
  updateSelectizeInput(session, "category", value = unname(data["category"]))
  updateTextInput(session, "task_num", value = unname(rownames(data)))
  updateCheckboxInput(session, "client_facing", value = as.logical(data["client_facing"]))
  updateCheckboxInput(session, "completion", value = as.logical(data["completion"]))




#######################################################################################
#######################################################################################

ui <- fluidPage(
  #use shiny js to disable the ID field
  shinyjs::useShinyjs(),
  ##
  #data table
  DT::dataTableOutput("responses", width = 300),

  #input fields
  tags$hr(),
  shinyjs::disabled(textInput("id", "Id", "0")),
  textInput("name", "Tribe/Task Name", ""),
  selectizeInput("Category", label = "Category", choices = c(Choose = '', Tribal = 'Tribal', Individual = 'Individual', Other = 'Other'), FALSE),
  textInput("task_num", "Task Order", ""),
  checkboxInput("client_facing", "Client Facing?", FALSE),
  checkboxInput("completion", "Task Completed?", FALSE),



  #action buttons
  actionButton("submit", "Submit"),
  actionButton("new", "New"),
  actionButton("delete", "Delete")
)



server <- function(input, output, session) 
  # input fields are treated as a group
  formData <- reactive(
    sapply(names(GetTableMetadata()$fields), function(x)
      input[[x]])
  )

  # Click "Submit" button -> save data
  observeEvent(input$submit, 
    if (input$id != "0") 
      UpdateData(formData())
     else 
      CreateData(formData())
      UpdateInputs(CreateDefaultRecord(), session)
    
  , priority = 1)

  # Press "New" button -> display empty record
  observeEvent(input$new, 
    UpdateInputs(CreateDefaultRecord(), session)
  )

  # Press "Delete" button -> delete from data
  observeEvent(input$delete, 
    DeleteData(formData())
    UpdateInputs(CreateDefaultRecord(), session)
  , priority = 1)

  # Select row in table -> show details in inputs
  observeEvent(input$responses_rows_selected, 
    if (length(input$responses_rows_selected) > 0) 
      data <- ReadData()[input$responses_rows_selected,]
      UpdateInputs(data, session)
    

  )

  # display table
  output$responses <- DT::renderDataTable(
    #update after submit is clicked
    input$submit
    #update after delete is clicked
    input$delete
    ReadData()
  , server = FALSE, selection = "single",
  colnames = unname(GetTableMetadata()$fields)[-1])






# Shiny app with 3 fields that the user can submit data for
shinyApp(ui = ui, server = server)

【问题讨论】:

【参考方案1】:

selectizeinput() 上的 ID 错误。它应该是带有小“c”的“类别”。这是因为GetTableMetadata() 中的名称具有“类别”作为名称。 updateSelectizeInput() 也没有值作为参数。

如果这能解决您的问题,请告诉我。

library(shiny)
library(shinyjs)
library(shinythemes)




######################### Get table metadata. For now, just the fields ##########################
######################## Further development: also define field types  ##########################
####################### and create inputs generically                 ###########################

######## TABLE 1: ADD NEW PERSON
GetTableMetadata <- function() 
  fields <- c(
    id = "Id",
    name = "Tribe/Task Name",
    category = "Category",
    task_num = "Task Order",
    client_facing = "Client Facing?",
    completion = "Task Completed?"
  )

  result <- list(fields = fields)
  return (result)



########################## CREATE, READ, UPDATE, DELETE #######################################
#### CRUD



# Find the next ID of a new record
GetNextId <- function() 
  if (exists("responses") && nrow(responses) > 0) 
    max(as.integer(rownames(responses))) + 1
   else 
    return (1)
  


#C
CreateData <- function(data) 
  data <- CastData(data)
  rownames(data) <- GetNextId()
  if (exists("responses")) 
    responses <<- rbind(responses, data)
   else 
    responses <<- data
  


#R
ReadData <- function() 
  if (exists("responses")) 
    responses
  




#U
UpdateData <- function(data) 
  data <- CastData(data)
  responses[row.names(responses) == row.names(data),] <<- data


#D
DeleteData <- function(data) 
  responses <<-
    responses[row.names(responses) != unname(data["id"]),]





#######################################################################################
# Cast from Inputs to a one-row data.frame

CastData <- function(data) 
  datar <- data.frame(
    name = data["name"],
    category = data["category"],
    task_num = as.integer(data["task_num"]),
    stringsAsFactors = FALSE,
    client_facing = as.logical(data["client_facing"]),
    completion = as.logical(data["completion"])
  )

  rownames(datar) <- data["id"]
  return (datar)





# Return an empty, new record
CreateDefaultRecord <- function() 
  mydefault <-
    CastData(list(
      id = "0",
      name = "", 
      category ="",
      task_num = 2,
      client_facing = FALSE,
      completion = FALSE

    ))
  return (mydefault)


# Fill the input fields with the values of the selected record in the table
UpdateInputs <- function(data, session) 
  updateTextInput(session, "id", value = unname(rownames(data)))
  updateTextInput(session, "name", value = unname(data["name"]))
  updateSelectizeInput(session, "category")
  updateTextInput(session, "task_num", value = unname(rownames(data)))
  updateCheckboxInput(session, "client_facing", value = as.logical(data["client_facing"]))
  updateCheckboxInput(session, "completion", value = as.logical(data["completion"]))




#######################################################################################
#######################################################################################

ui <- fluidPage(
  #use shiny js to disable the ID field
  shinyjs::useShinyjs(),
  ##
  #data table
  DT::dataTableOutput("responses", width = 300),

  #input fields
  tags$hr(),
  shinyjs::disabled(textInput("id", "Id", "0")),
  textInput("name", "Tribe/Task Name", ""),
  selectizeInput("category", label = "Category", choices = c(Choose = '', Tribal = 'Tribal', Individual = 'Individual', Other = 'Other'), FALSE),
  textInput("task_num", "Task Order", ""),
  checkboxInput("client_facing", "Client Facing?", FALSE),
  checkboxInput("completion", "Task Completed?", FALSE),



  #action buttons
  actionButton("submit", "Submit"),
  actionButton("new", "New"),
  actionButton("delete", "Delete")
)



server <- function(input, output, session) 
  # input fields are treated as a group
  formData <- reactive(
    sapply(names(GetTableMetadata()$fields), function(x)
      input[[x]])
  )

  # Click "Submit" button -> save data
  observeEvent(input$submit, 
    if (input$id != "0") 
      UpdateData(formData())
     else 
      CreateData(formData())
      UpdateInputs(CreateDefaultRecord(), session)
    
  , priority = 1)

  # Press "New" button -> display empty record
  observeEvent(input$new, 
    UpdateInputs(CreateDefaultRecord(), session)
  )

  # Press "Delete" button -> delete from data
  observeEvent(input$delete, 
    DeleteData(formData())
    UpdateInputs(CreateDefaultRecord(), session)
  , priority = 1)

  # Select row in table -> show details in inputs
  observeEvent(input$responses_rows_selected, 
    if (length(input$responses_rows_selected) > 0) 
      data <- ReadData()[input$responses_rows_selected,]
      UpdateInputs(data, session)
    

  )

  # display table
  output$responses <- DT::renderDataTable(
    #update after submit is clicked
    input$submit
    #update after delete is clicked
    input$delete
    ReadData()
  , server = FALSE, selection = "single",
  colnames = unname(GetTableMetadata()$fields)[-1])






# Shiny app with 3 fields that the user can submit data for
shinyApp(ui = ui, server = server)

【讨论】:

以上是关于Rshiny CRUD 应用程序:使用选择输入而不是文本输入时用户输入崩溃的主要内容,如果未能解决你的问题,请参考以下文章

闪亮:更新输入而不触发反应?

R Shiny:向数据表添加新列

创建 CRUD 视图而不创建控制器

在 R Shiny 中实现 CRUD 工作流的最简洁方法是啥?

R Shiny:修改选择后保留/保留反应输入的值

根据文件选择保存和加载用户选择 - R Shiny