简体   繁体   English

R Shiny JS跳转到最后一页与新行中的自动生成值冲突

[英]R Shiny JS jump to last page conflicting with auto generate value in new row

I have a Shiny app that allows the user to enter their project details to the database.我有一个Shiny的应用程序,允许用户将他们的项目详细信息输入数据库。 This is achieved by the Add Project Details Button that adds an empty row to the table.这是通过向表中添加空行的“ Add Project Details按钮来实现的。 When the add button is clicked the app auto generates the next reference number (under column Reference.Number) in the new row based on the previous one.单击添加按钮时,应用程序会根据前一个在新行中自动生成下一个参考号(在 Reference.Number 列下)。

Another function of the Add button is also to make the app jump to the last page of the table rather than having the user click on the last page number under the table. Add按钮的另一个作用也是让应用跳转到表格的最后一页,而不是让用户点击表格下的最后一个页码。

The app almost works fine because when I click the Add button, the app does temporarily go the last page, but as soon as the auto generate value is calculated, the app goes back to the first page of the table.该应用程序几乎可以正常工作,因为当我单击“ Add ”按钮时,该应用程序确实会暂时转到最后一页,但是一旦计算出自动生成值,该应用程序就会返回到表格的第一页。

What could be causing this conflict and how can this be fixed?什么可能导致这种冲突,如何解决?

Sample data ( df ):样本数据( df ):

df <- structure(list(Reference.Number = c("33331", "33332", "33333", 
                                          "33334", "33335"), 
                     Request.Date = c("1/6/2022", "1/6/2022", "1/19/2022", 
                                                                              "1/20/2021", "1/24/2022"), 
                     Requestor.Name = c("Comm Dist 3 by Kitty", "Comm Dist 3 by Kitty", "Updated maps for David", "    Stone Cold", "Updated SOE 60 inch wall map"),
                     Requestor.Dept.Div = c("C 3 Staff",    "C 3 Staff", "Unincorp & Comm", "Mt.Rushmore AME Church Ft. Billy",                                         "SOE"), 
                     Requestor.Phone = c("", "", "", "", ""), 
                     Contact.Person = c("Tommy",                             "Tommy", "Bob", "Bob", "Joe"),
                     Contact.Phone = c("1111",                               "2222", "3333", "ext 1111", "3434"),
                     Deadline = c("1/20/2022",         "1/20/2022", "1/22/2022", "", "1/24/2022"),
                     Project.Description = c("45x36 portrait map ",          "45x36 portrait map  ",   "24x24 Unincorporated areas", "Percent Females Aged 25 - 55  Below Poverty Level By Zip Code",                "SOE Wall Map 60x60 p"), 
                     Project.File.Location = c("", 
                                                  "", "C:\\ABC\\Tommy\\work|Map-Projects\\BD Unincororated\\#14785 Unincorporated 24x24.pdf", 
                                                  "C:\\ABC\\Demographics\\Demographic_Request\\FemalesAge10-18BelowPoveryLevel\\FemalesAge10-18BelowPoveryLevel.aprx", 
                                                  "C:\\ABC\\Tommy\\work|Map-Projects\\BD Unincororated\\#14786 V P 60x60.pdf" 

Code:代码:

library(shiny)
library(shinythemes)
library(DT)
library(tidyverse)

# Define UI for application 
ui =   navbarPage(tags$style("table, .table {color: unset;} .dataTable th, .datatables input {color: white}"),
                  title = div("GIS Team Projects"),
                  theme = shinytheme("cyborg"),
                  tabPanel("GIS Projects",
                           icon = icon("info"),
                           div(p(h1("Instructions:"),style="text-align: justify;")),
                           p("1. The user can add their project details.", style="color:black"),
                           uiOutput("all"),
                  sidebarLayout(
                    sidebarPanel(
                      actionButton("addData", "Add Project Details"),
                      ),
                    mainPanel(
                      downloadButton("download1","Download data as csv"),                
                      DTOutput("contents"),
                      tags$script(HTML("
           Shiny.addCustomMessageHandler('messageJumpToLast', function(message) {
               // select the target table via its container ID and class:
               var target = $('#contents .dataTable');
               // display last page:
               target.dataTable().api().page('last').draw(false);
           });
           "))),
                    )
                    )
)

# Define server logic required 
server <- function(input, output) {
  
  myData = reactiveVal(df)
  
  # Create an 'empty' tibble 
  user_table =  
    df %>% 
    slice(1) 
  
  user_table[1,]<-NA
  
  # Display data as is
  output$contents =
    renderDT(myData(),
             server = FALSE,
             editable = TRUE,
             options = list(lengthChange = TRUE),
             rownames = FALSE)
  
  # Store a proxy of contents 
  proxy = dataTableProxy(outputId = "contents")
  
  # Each time addData is pressed, add user_table to proxy
  observeEvent(eventExpr = input$addData, {
    myData(myData() %>% bind_rows(user_table %>% 
  mutate(Reference.Number=as.character(max(as.numeric(myData()$Reference.Number), na.rm = T)+1))))
  session$sendCustomMessage('messageJumpToLast', 'some payload here, if needed') # Don't know if this should be added or not!
  })
  
}

# Run the application 
shinyApp(ui = ui, server = server)

I didn't try with your app because it gives me headache.我没有尝试使用您的应用程序,因为它让我头疼。 Here is a minimal example:这是一个最小的例子:

library(shiny)
library(DT)

ui <- basicPage(
  br(),
  actionButton("addData", "Add Project Details", class = "btn-primary"),
  br(), br(),
  fluidRow(
    column(
      width = 12, 
      DTOutput("mytable")
    )
  )
)

callback <- c( # with this callback, the app does not jump to the last page if
  '$("#addData").on("click", function(){', # the added row goes to a new page
  '  table.page("last").draw("page");',
  '});'
)
callback <- c( # so we use this callback which includes a small delay (200ms)
  '$("#addData").on("click", function(){',
  '  setTimeout(function(){table.page("last").draw("page");}, 200);',
  '});'
)

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

  Dat <- reactiveVal(iris)
  
  #mytable
  output[["mytable"]] <- renderDT({
    datatable(
      isolate(Dat()),
      rownames = FALSE,
      editable = list(target = "cell"),
      callback = JS(callback)
    )
  }, server = FALSE)
  
  proxy <- dataTableProxy("mytable")
  
  #bind clicks
  observeEvent(input[["addData"]], {
    newRow <- data.frame(
      "Sepal.Length" = runif(1, 5, 7),
      "Sepal.Width"  = runif(1, 2, 4),
      "Petal.Length" = runif(1, 3, 5),
      "Petal.Width"  = runif(1, 0, 2),
      "Species"      = "setosa" 
    )
    Dat(rbind(Dat(), newRow)) # just to keep track of the changes
    addRow(proxy, newRow, resetPaging = FALSE)
  }) 
  
  # remove btn
  observeEvent(input[["mytable_edit"]], {
    info <- input[["mytable_edit"]]
    Dat(editData(Dat(), info, proxy))
  })
  
}

shinyApp(ui, server)

@Stéphane Laurent deserves all credit for this. @Stéphane Laurent 值得称赞。 Essentially I just used the original posters code and updated it with the answer from Stéphane Laurent.本质上,我只是使用了原始海报代码,并用 Stéphane Laurent 的答案对其进行了更新。 There are certain things like the observeEvent() that don't work as originally posted without the user of the addRow() .在没有 addRow() 的用户的情况下,有些东西,比如observeEvent() addRow()像最初发布的那样工作。 Anyways, this should work.无论如何,这应该工作。 Best of luck祝你好运

df <- data.frame(structure(list(Reference.Number = c("33331", "33332", "33333", 
                                                     "33334", "33335"), 
                                Request.Date = c("1/6/2022", "1/6/2022", "1/19/2022", 
                                                 "1/20/2021", "1/24/2022"), 
                                Requestor.Name = c("Comm Dist 3 by Kitty", "Comm Dist 3 by Kitty", "Updated maps for David", "    Stone Cold", "Updated SOE 60 inch wall map"),
                                Requestor.Dept.Div = c("C 3 Staff",    "C 3 Staff", "Unincorp & Comm", "Mt.Rushmore AME Church Ft. Billy",                                         "SOE"), 
                                Requestor.Phone = c("", "", "", "", ""), 
                                Contact.Person = c("Tommy",                             "Tommy", "Bob", "Bob", "Joe"),
                                Contact.Phone = c("1111",                               "2222", "3333", "ext 1111", "3434"),
                                Deadline = c("1/20/2022",         "1/20/2022", "1/22/2022", "", "1/24/2022"),
                                Project.Description = c("45x36 portrait map ",          "45x36 portrait map  ",   "24x24 Unincorporated areas", "Percent Females Aged 25 - 55  Below Poverty Level By Zip Code",                "SOE Wall Map 60x60 p"), 
                                Project.File.Location = c("", 
                                                          "", "C:\\ABC\\Tommy\\work|Map-Projects\\BD Unincororated\\#14785 Unincorporated 24x24.pdf", 
                                                          "C:\\ABC\\Demographics\\Demographic_Request\\FemalesAge10-18BelowPoveryLevel\\FemalesAge10-18BelowPoveryLevel.aprx", 
                                                          "C:\\ABC\\Tommy\\work|Map-Projects\\BD Unincororated\\#14786 V P 60x60.pdf" 
                                ))))
#Made data into dataframe, slice for me doesn't work with the list


library(shiny)
# library(shinythemes #I don't think this is important to the question and I don't have shinythemes
library(DT)
library(tidyverse)

callback <- c( # with this callback, the app does not jump to the last page if
  '$("#addData").on("click", function(){', # the added row goes to a new page
  '  table.page("last").draw("page");',
  '});'
)
callback <- c( # so we use this callback which includes a small delay (200ms)
  '$("#addData").on("click", function(){',
  '  setTimeout(function(){table.page("last").draw("page");}, 200);',
  '});'
)

# Define UI for application 
ui =   navbarPage(tags$style("table, .table {color: unset;} .dataTable th, .datatables input {color: white}"),
                  title = div("GIS Team Projects"),
                  # theme = shinytheme("cyborg"), #I don't think this is important to the question
                  tabPanel("GIS Projects",
                           icon = icon("info"),
                           div(p(h1("Instructions:"),style="text-align: justify;")),
                           p("1. The user can add their project details.", style="color:black"),
                           uiOutput("all"),
                           sidebarLayout(
                             sidebarPanel(
                               actionButton("addData", "Add Project Details"),
                             ),
                             mainPanel(
                               downloadButton("download1","Download data as csv"),                
                               DTOutput("contents"),
                               tags$script(HTML("
           Shiny.addCustomMessageHandler('messageJumpToLast', function(message) {
               // select the target table via its container ID and class:
               var target = $('#contents .dataTable');
               // display last page:
               target.dataTable().api().page('last').draw(false);
           });
           "))
                             ),
                           )
                  )
)

# Define server logic required 
server <- function(input, output) {
  
  myData = reactiveVal(df)
  
  # Create an 'empty' tibble 
  user_table =  
    df %>% 
    slice(1) 
  
  user_table[1,]<-NA
  
  # Display data as is
  output$contents =
    renderDT({
      datatable(isolate(myData()), #Isolate is needed for Stéphane Laurent's answer
                # server = FALSE, #Moved to below
                editable = TRUE,
                options = list(lengthChange = TRUE),
                rownames = FALSE,
                callback = JS(callback)
      )}, server = FALSE
    )
  
  # Store a proxy of contents 
  proxy = dataTableProxy(outputId = "contents")
  
  # Each time addData is pressed, add user_table to proxy
  observeEvent(eventExpr = input$addData, {
    #Original way of adding data doesn't work with Stéphane Laurent's answer, so I updated using their format
    # myData(myData() %>% bind_rows(user_table %>% 
    #                                 mutate(Reference.Number=as.character(max(as.numeric(myData()$Reference.Number), na.rm = T)+1))))
    newRow<-user_table %>% #replaced the original info with the answer from Stéphane Laurent
      mutate(Reference.Number=as.character(max(as.numeric(as.character(myData()$Reference.Number)), na.rm = T)+1))
    myData(rbind(myData(), newRow)) # just to keep track of the changes
    addRow(proxy, newRow, resetPaging = FALSE)
  })
  
  observeEvent(input[["contents_edit"]], {
    info <- input[["contents_edit"]]
    myData(editData(myData(), info, proxy))
  })
  
}

# Run the application 
shinyApp(ui = ui, server = server)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM