2016-07-11 32 views
7

Tworzę aplikację Shiny, która wyświetla dane data.frame u góry ekranu i określone zmienne statystyki na dole. Użytkownik może nawigować po kolumnach data.frame, wchodząc w interakcję z obiektem DT::datatable.Zaktualizuj wiersz (y) Shiny DataTable przy zachowaniu pozycji

Po kliknięciu przez użytkownika zmiennej wyświetlane są szczegółowe informacje, które można edytować. Chciałbym, aby te informacje zostały zaktualizowane i odzwierciedlone w datatable. Mój problem polega na tym, że kiedy aktualizuję tabelę, jest ona renderowana i pokazywana od samego początku. Jak mogę zachować stronę i wybór wiersza datatable po wprowadzeniu zmian?

Oto minimalny przykład roboczy, który pokazuje zestaw danych mtcars w DT::datatable. Mam pewne elementy sterujące, które aktualizują pola. Zauważ, że datatable jest ponownie renderowany z powrotem na pierwszą stronę.

library(shiny) 

runApp(shinyApp(

    ui = fluidPage(
    title = "minimal-working-example", 
    fluidRow(
     column(3, inputPanel(
     selectInput("field", "Field", choices = names(mtcars)), 
     numericInput("value", "Value", 0), 
     actionButton("submit", "Submit") 
    )), 

     column(9, 
     DT::dataTableOutput("table") 
    ) 
    ) 
), 

    server = function(input, output) { 

    v <- reactiveValues(mtcars=mtcars) 

    observeEvent(input$submit, { 
     v$mtcars[input$field] <- input$value 
    }) 

    output$table <- DT::renderDataTable({ 
     DT::datatable(
     v$mtcars, 
     selection = "single", 
     options = list(pageLength = 5)) 
    }) 
    } 
)) 

Sesja Info:

Session info -------------------------- 
setting value      
version R version 3.3.0 (2016-05-03) 
system x86_64, mingw32    
ui  RStudio (0.99.902)   
language (EN)       
collate English_United States.1252 
tz  America/Chicago    
date  2016-07-11     

Packages ------------------------------- 
package  * version  date  source       
DT   0.1.45  2016-02-09 Github (rstudio/[email protected]) 
shiny  * 0.13.0.9000 2016-02-08 Github (rstudio/[email protected]) 
+1

Jest to trudne, ale wykonalne. Zasadniczo to, co musi się stać, to aktualna strona tabeli musi być zapisywana reaktywnie, co można zrobić za pomocą 'Shiny.onInputChange' w javascript. Następnie, gdy wyrenderujesz stół, oddzwonisz, aby otworzyć go na numer strony, który był wcześniej. Napiszę pełną odpowiedź, gdy dostanę szansę. – Carl

Odpowiedz

4

Można to zrobić od wewnątrz R bez uzyskiwania w strukturze datatable przez JS lub coś podobnego.

Korzystamy z różnych informacji o stanie tabel, które otrzymujemy z pakietu DT, aby renderować zaktualizowaną wersję datatable podobną do poprzedniej. Wszystko, czego używamy, jest opisane w this DT documentation.

Pozycja pierwsza: wybór. Możesz wstępnie wybierać wiersze, dodając selected = ... w argumencie selection z datatable. Można to połączyć ze zmienną input$table_rows_selected, aby zapisać poprzednio wybrany wiersz i wstępnie wybrać dokładny wiersz podczas ponownego renderowania.

Pozycja druga: Strona. Pakiet datatable ma opcję displayStart, która określa, który wiersz powinien być wyświetlany jako pierwszy podczas renderowania tabeli. Documentation here. Tak więc, jeśli masz 5 wierszy na stronę, displayStart = 9 uruchomi ekran na stronie 3. (Tablice JavaScript zaczynają się od 0, więc zawsze odejmuj 1.) Można to połączyć z input$table_rows_current, który jest wektorem aktualnie widocznych numerów wierszy. Jeśli przechowujemy pierwszy wpis (minus 1), wiemy, gdzie rozpocząć wyświetlanie.

Pełny przykład kodu poniżej:

library(shiny) 

runApp(shinyApp(

    ui = fluidPage(
    title = "minimal-working-example", 
    fluidRow(
     column(3, inputPanel(
     selectInput("field", "Field", choices = names(mtcars)), 
     numericInput("value", "Value", 0), 
     actionButton("submit", "Submit") 
    )), 

     column(9, 
     DT::dataTableOutput("table") 
    ) 
    ) 
), 

    server = function(input, output) { 

    v <- reactiveValues(mtcars=mtcars) 
    previousSelection <- NULL 
    previousPage <- NULL 

    observeEvent(input$submit, { 
     previousSelection <<- input$table_rows_selected 
     previousPage <<- input$table_rows_current[1] - 1 

     v$mtcars[input$field] <- input$value 
    }) 

    output$table <- DT::renderDataTable({ 
     DT::datatable(
     v$mtcars, 
     selection = list(mode = "single", target = "row", selected = previousSelection), 
     options = list(pageLength = 5, displayStart = previousPage)) 
    }) 
    } 
)) 
+0

Dzięki za szczegółową odpowiedź. Natknąłem się na funkcje interfejsu API DT, które podkreślasz w swoim rozwiązaniu. Mam zamiar nagrodzić cię nagrodą, ponieważ odpowiedziałeś na to pytanie, tak jak to postawiłem. Jednak przy wdrażaniu tego rozwiązania odkryłem, że łamie się on podczas sortowania stołu. Czy masz jakieś przemyślenia na temat tego, jak rozwiązać ten problem? – Zelazny7

+1

@ Zelazny7 Istnieje opcja 'datatable'' order', a możesz pobrać bieżącą kolejność tabel przez 'input $ table_state $ order' jeśli ustawisz opcję' datatable' 'stateSave = TRUE'. Ale zestaw jest uporządkowany po 'displayStart', więc spowoduje to fałszywy wybór strony. Chciałbym użyć zamawiania, aby (tymczasowo) zamówić zestaw danych i pobrać aktualną stronę, na której będzie wyświetlany numer wiersza 'previousPage' (numer wiersza po złożeniu zamówienia). Wtedy użyłbym tego (długość strony modułu) jako argumentu 'previousPage'. Plus reguła wyjątku, jeśli kolumna zamawiania jest tą, która została nadpisana. –