美文网首页
shiny 使用 reactable 实现信息增删改查

shiny 使用 reactable 实现信息增删改查

作者: watermark | 来源:发表于2021-10-23 17:06 被阅读0次

    效果预览:

    封面.png

    本文介绍了 shiny 如何实现信息的增删改查,并将数据持久化到 SQLite 数据库中。

    首先在 SQLite 数据库中新建表 users,表结构如下。设置 id 为主键并自动递增。

    字段 类型 是否允许空
    id INTEGER 主键非空,自动递增
    username TEXT
    age TEXT
    birthday TEXT
    address TEXT

    新增信息

    1. UI 设计
    新增信息UI设计.png
    1. 实现
      observeEvent(input$adduser, {
        showModal(modalDialog(
          title = "新建用户",
          size = "m",
          fluidPage(
            fluidRow(
              column(width = 12, textInput(inputId = "username", label = "姓名"))
            ),
            fluidRow(
              column(width = 12, textInput(inputId = "age", label = "年龄"))
            ),
            fluidRow(
              column(width = 12, dateInput(inputId = "birthday", label = "出生日期"))
            ),
            fluidRow(
              column(width = 12, textInput(inputId = "address", label = "地址"))
            )
          ),
          easyClose = FALSE,
          fade = FALSE,
          footer = tagList(
            actionButton(inputId = "useradd_confirm", label = "确认"),
            modalButton(label = "取消")
          )
        ))
      })
      
      observeEvent(input$useradd_confirm, {
        con <-  RSQLite::dbConnect(RSQLite::SQLite(), "./data/users.db")
        tryCatch({
          addusersql <- paste0("INSERT INTO users (username, age, birthday, address) VALUES ", "('", 
                               input$username, "', '", 
                               input$age, "', '", 
                               input$birthday, "', '", 
                               input$address, "')")
          RSQLite::dbExecute(con, addusersql)
          # refresh table instance
          user_data <<- user_base()
          
          output$user_table <- renderReactable({
            # reactable中文
            options(reactable.language = reactableLang(
              pageSizeOptions = "\u663e\u793a {rows}",
              pageInfo = "{rowStart} \u81f3 {rowEnd} \u9879\u7ed3\u679c,\u5171 {rows} \u9879",
              pagePrevious = "\u4e0a\u9875",
              pageNext = "\u4e0b\u9875"
            ))
            reactable(data = user_data[c("username", "age", "birthday", "address")],
                      bordered = TRUE,
                      striped = TRUE,
                      highlight = TRUE,
                      filterable = TRUE,
                      defaultPageSize = 5,
                      showPageSizeOptions = TRUE,
                      selection = "multiple",
                      onClick = "select",
                      defaultColDef = colDef(
                        align = "left",
                        minWidth = 50
                      ),
                      columns = list(
                        .selection = colDef(
                          width = 80,
                          style = list(cursor = "pointer"),
                          headerStyle = list(cursor = "pointer")
                        ),
                        address = colDef(minWidth = 140)  # overrides the default
                      )
            )
          })
          toastr_success(title = "保存成功", message = "")
          removeModal()
        },
        warning = function(w) {
          toastr_warning("保存失败", message = w)
        },
        error = function(e) {
          toastr_error("保存失败", message = e)
        },
        finally = {
          RSQLite::dbDisconnect(con)
        })
      })
    

    删除信息

    1. UI 设计
    • 允许同时删除多个 item;
    • 当未勾选任何信息时,删除按钮为禁用样式;
    删除信息UI设计.png
    1. 实现
      # 删除
      output$deleteuser <- renderUI({
        if (length(selected()) > 0) {
          actionButton(inputId = "deleteuser", label = "删除", icon = icon("trash-alt"), 
                       style = "background-color: #DC3545; 
                                color: #ffffff; 
                                border: none; 
                                margin-left: 15px; 
                                margin-bottom: 15px")
        } else {
          shinyjs::disabled(actionButton(inputId = "deleteuser", label = "删除", icon = icon("trash-alt"), 
                                         style = "background-color: #DC3545; 
                                                  color: #ffffff; 
                                                  border: none; 
                                                  margin-left: 15px; 
                                                  margin-bottom: 15px"))
        }
      })
      
      observeEvent(input$deleteuser, {
        showModal(modalDialog(
          title = "删除用户",
          size = "m",
          fluidPage(
            div("确定删除用户 ", 
                span(paste(user_data[selected(), "username"], collapse = ", "), 
                     style="padding: .2em .2em; 
                            margin:0; 
                            font-size:85%; 
                            background-color:rgb(175,184,193,20%); 
                            color:#DC3545; 
                            border-radius:2px;"), 
                " 吗 ?")
          ),
          easyClose = FALSE,
          fade = FALSE,
          footer = tagList(
            actionButton(inputId = "userdelete_confirm", label = "确认"),
            modalButton(label = "取消")
          )
        ))
      })
      
      observeEvent(input$userdelete_confirm, {
        con <-  RSQLite::dbConnect(RSQLite::SQLite(), "./data/users.db")
        tryCatch({
          deleteSql <- paste0("DELETE FROM users WHERE id=", "'", user_data[selected(), "id"], "'")
          for (sql in deleteSql) {
            RSQLite::dbExecute(con, sql)
          }
          # refresh table instance
          user_data <<- user_base()
          
          output$user_table <- renderReactable({
            options(reactable.language = reactableLang(
              pageSizeOptions = "\u663e\u793a {rows}",
              pageInfo = "{rowStart} \u81f3 {rowEnd} \u9879\u7ed3\u679c,\u5171 {rows} \u9879",
              pagePrevious = "\u4e0a\u9875",
              pageNext = "\u4e0b\u9875"
            ))
            reactable(data = user_data[c("username", "age", "birthday", "address")],
                      bordered = TRUE,
                      striped = TRUE,
                      highlight = TRUE,
                      filterable = TRUE,
                      defaultPageSize = 5,
                      showPageSizeOptions = TRUE,
                      selection = "multiple",
                      onClick = "select",
                      defaultColDef = colDef(
                        align = "left",
                        minWidth = 50
                      ),
                      columns = list(
                        .selection = colDef(
                          width = 80,
                          style = list(cursor = "pointer"),
                          headerStyle = list(cursor = "pointer")
                        ),
                        address = colDef(minWidth = 140)  # overrides the default
                      )
            )
          })
          toastr_success(title = "删除成功", message = "")
          removeModal()
        },
        warning = function(w) {
          toastr_warning(title = "删除失败", message = w)
        },
        error = function(e) {
          toastr_error(title = "删除失败", message = e)
        },
        finally = {
          RSQLite::dbDisconnect(con)
        })
      })
    }
    

    修改信息

    1. UI 设计
    • 复用新增信息的 UI
    • 未勾选任何 item勾选 item 数量 > 1 时,编辑按钮为禁用状态;
    1. 实现
      # 编辑
      output$edituser <- renderUI({
        # 只有选择一项时可以编辑
        if (length(selected()) == 1) {
          actionButton(inputId = "edituser", label = "编辑", icon = icon("edit"),
                       style = "background-color: #007BFF; 
                                color: #ffffff; 
                                border: none; 
                                margin-left: 15px; 
                                margin-bottom: 15px")
    
        } else {
          shinyjs::disabled(actionButton(inputId = "edituser", label = "编辑", icon = icon("edit"),
                                         style = "background-color: #007BFF; 
                                                  color: #ffffff; 
                                                  border: none; 
                                                  margin-left: 15px; 
                                                  margin-bottom: 15px"))
        }
      })
      
      observeEvent(input$edituser, {
        showModal(modalDialog(
          title = "修改信息",
          size = "m",
          fluidPage(
            fluidRow(
              column(width = 12, 
                     textInput(inputId = "username_new", label = "姓名", 
                               value = user_data[selected(), "username"]))
            ),
            fluidRow(
              column(width = 12, 
                     textInput(inputId = "age_new", label = "年龄", 
                               value = user_data[selected(), "age"]))
            ),
            fluidRow(
              column(width = 12, 
                     dateInput(inputId = "birthday_new", label = "出生日期", 
                               value = user_data[selected(), "birthday"]))
            ),
            fluidRow(
              column(width = 12, 
                     textInput(inputId = "address_new", label = "地址", 
                               value = user_data[selected(), "address"]))
            )
          ),
          easyClose = FALSE,
          fade = FALSE,
          footer = tagList(
            actionButton(inputId = "useredit_confirm", label = "确认"),
            modalButton(label = "取消")
          )
        ))
      })
      
      observeEvent(input$useredit_confirm, {
        # 更新用户信息
        con <-  RSQLite::dbConnect(RSQLite::SQLite(), "./data/users.db")
        tryCatch({
          edit_standard_user_sql <- paste0("UPDATE users set username=", "'", input$username_new, "'", 
                                           ", age=", "'", input$age_new, "'", 
                                           ", birthday=", "'", input$birthday_new, "'", 
                                           ", address=", "'", input$address_new, "'",
                                           " WHERE id=", "'", user_data[selected(), "id"], "'")
          RSQLite::dbExecute(con, edit_standard_user_sql)
          # refresh table instance
          user_data <<- user_base()
          
          output$user_table <- renderReactable({
            options(reactable.language = reactableLang(
              pageSizeOptions = "\u663e\u793a {rows}",
              pageInfo = "{rowStart} \u81f3 {rowEnd} \u9879\u7ed3\u679c,\u5171 {rows} \u9879",
              pagePrevious = "\u4e0a\u9875",
              pageNext = "\u4e0b\u9875"
            ))
            reactable(data = user_data[c("username", "age", "birthday", "address")],
                      bordered = TRUE,
                      striped = TRUE,
                      highlight = TRUE,
                      filterable = TRUE,
                      defaultPageSize = 5,
                      showPageSizeOptions = TRUE,
                      selection = "multiple",
                      onClick = "select",
                      defaultColDef = colDef(
                        align = "left",
                        minWidth = 50
                      ),
                      columns = list(
                        .selection = colDef(
                          width = 80,
                          style = list(cursor = "pointer"),
                          headerStyle = list(cursor = "pointer")
                        ),
                        address = colDef(minWidth = 140)  # overrides the default
                      )
            )
          })
          toastr_success(title = "修改成功", message = "")
          removeModal()
        },
        warning = function(w) {
          toastr_warning(title = "修改失败", message = w)
        },
        error = function(e) {
          toastr_error(title = "修改失败", message = e)
        },
        finally = {
          RSQLite::dbDisconnect(con)
        })
      })
    

    查找信息

    reactable 中设置 filterable = TRUE 即可实现信息过滤查找的效果;

    信息查找.gif

    源代码

    完整代码详见 https://github.com/redburning/reactable

    参考

    https://github.com/glin/reactable

    相关文章

      网友评论

          本文标题:shiny 使用 reactable 实现信息增删改查

          本文链接:https://www.haomeiwen.com/subject/henkaltx.html