Как добавить итоги в DT::datatable?

Я пытаюсь добавить итоги в нижний колонтитул таблицы данных. Используя код из разных источников, я написал следующее приложение с помощью Shiny. Проблема в том, что когда я запускаю его, появляется следующее сообщение:

"Обработка ..."

и остается там навсегда.

Я предполагаю, что это код JS(), но не могу его отладить.

library(shiny)
library(DT)
library(htmltools)

ui <- fluidPage(


  fluidRow(
    column(9, DT::dataTableOutput('withtotal'))
  )

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

  # server-side processing
  mtcars2 = mtcars[, 1:8]
  #sketch <- htmltools::withTags(table(tableHeader(mtcars2), tableFooter(mtcars2)))

  sketch = htmltools::withTags(table(tableFooter(c("",0,0,0,0,0,0,0))))

 opts <- list( footerCallback = JS("function ( row, data, start, end, display ) {",
     "var api = this.api();",
     "var intVal = function ( i ) {",
      "return typeof i === 'string' ?",
       "i.replace(/[\\$,]/g, '')*1 :",
         "typeof i === 'number' ?",
         "i : 0;",
     "};",
     "if (api.column(COLNUMBER).data().length){",
       "var total = api",
       ".column( COLNUMBER )",
       ".data()",
       ".reduce( function (a, b) {",
         "return intVal(a) + intVal(b);",
       "} ) }",
     "else{ total = 0};",
     "if (api.column(COLNUMBER).data().length){",
       "var pageTotal = api",
       ".column( COLNUMBER, { page: 'current'} )",
       ".data()",
       ".reduce( function (a, b) {",
        " return intVal(a) + intVal(b);",
       "} ) }",
    "else{ pageTotal = 0};",
     "$( api.column(COLNUMBER).footer() ).html(",
       "'$'+pageTotal",
     ");",
   "}"))


  output$withtotal = DT::renderDataTable(DT::datatable(mtcars2,container = sketch, options = opts))      


}

options(shiny.error = browser)
# Run the application 
shinyApp(ui = ui, server = server)

person MPaydar    schedule 21.03.2017    source источник
comment
Вы просматривали эту ссылку?   -  person SBista    schedule 29.03.2017
comment
Спасибо всем, что не прокомментировали это сообщение stackoverflow.com/questions/42933859, я выиграл награду Tumbleweed :) Не уверен, что этот вопрос слишком умный или слишком тупой!?   -  person MPaydar    schedule 11.04.2017


Ответы (3)


Это версия без использования Shiny. Я использовал тот же JavaScript, что и @gscott выше, но это для отдельной таблицы. Я использовал это в документе RMarkdown. Ключом к этому, с которым я боролся, является аргумент container, который добавляет нижний колонтитул к таблице.

library(htmlwidgets)
library(DT)
library(htmltools)

sketch <- htmltools::withTags(table(
  tableHeader(colnames(mtcars)), 
  tableFooter(c(0,0,0,0,0,0,0,0,0,0,0,0))
))

jsCode <- "function(row, data, start, end, display) {
  var api = this.api(), data;
  total = api.column(7, {page: 'current'}).data().reduce( function(a, b) { return a + 
b}, 0);
  total2 = api.column(6, {page: 'current'}).data().reduce( function(a, b) { return a 
+ b}, 0);
  total3 = api.column(2, {page: 'current'}).data().reduce( function(a, b) { return a 
+ b}, 0);
  $( api.column(7).footer() ).html('Total: ' + total.toFixed(2));
  $( api.column(6).footer() ).html('Total: ' + total2.toFixed(2));
  $( api.column(2).footer() ).html('Total: ' + total3.toFixed(2))
  }"

DT::datatable(mtcars, container = sketch, options=list(scrollY=300, scrollX=TRUE, scroller=TRUE, footerCallback = JS(jsCode)))
person Dan Carpenter    schedule 27.11.2018

Похоже, вы используете тот же пример программы, который я использовал в суммах обратного вызова нижнего колонтитула Shiny DataTables, поэтому мое решение проблемы обратного вызова нижнего колонтитула приведено ниже. . Это самое простое, что я нашел для манипулирования столбцом за столбцом.

library(shiny)
library(DT)

ui <- fluidPage(

  title = 'Select Table Rows',

  hr(),

  h1('A Server-side Table'),

  fluidRow(
    column(9, DT::dataTableOutput('x3'))
  )

)


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

  # server-side processing

  mtcars2 = mtcars[, 1:8]

  sketch <- htmltools::withTags(table(
                  class = "display",
                  style = "bootstrap",
                  tableHeader(colnames(mtcars2)),
                  tableFooter(colnames(mtcars2))
          ))

  output$x3 = DT::renderDataTable(DT::datatable(mtcars2,
                                                container = sketch,
                                                extensions = 'Buttons',
                                                options = list(
                                                  scrollX = TRUE,
                                                  scrollY = TRUE,
                                                  pageLength = 10,
                                                  order = list(list(1, 'asc')),
                                                  dom = 'Blrtip',
                                                  buttons = c('copy', 'csv', 'excel', 'pdf', 'print'),
                                                  footerCallback = JS(
       "function( tfoot, data, start, end, display ) {",
       "var api = this.api(), data;",
        "total = api.column( 1, { page: 'current'} ).data().reduce( function ( a, b ) {return a + b;} )",
        "total1 = api.column( 2, { page: 'current'} ).data().reduce( function ( a, b ) {return a + b;} )",
       "total2 = api.column( 3, { page: 'current'} ).data().reduce( function ( a, b ) {return a + b;} )",
        "total3 = api.column( 4, { page: 'current'} ).data().reduce( function ( a, b ) {return a + b;} )",
       "total4 = api.column( 5, { page: 'current'} ).data().reduce( function ( a, b ) {return a + b;} )",
        "total5 = api.column( 6, { page: 'current'} ).data().reduce( function ( a, b ) {return a + b;} )",
       "total6 = api.column( 7, { page: 'current'} ).data().reduce( function ( a, b ) {return a + b;} )",
        "total7 = api.column( 8, { page: 'current'} ).data().reduce( function ( a, b ) {return a + b;} )",
        "$( api.column( 1 ).footer() ).html(total.toFixed(2));
        $( api.column( 2 ).footer() ).html(total1.toFixed(2));
        $( api.column( 3 ).footer() ).html(total2.toFixed(2));
        $( api.column( 4 ).footer() ).html(total3.toFixed(2));
        $( api.column( 5 ).footer() ).html(total4.toFixed(2));
        $( api.column( 6 ).footer() ).html(total5.toFixed(2));
        $( api.column( 7 ).footer() ).html(total6.toFixed(2));
        $( api.column( 8 ).footer() ).html(total7.toFixed(2));",
        "}"
        ))
      ))
}

shinyApp(ui = ui, server = server)
person sgoley    schedule 04.05.2017

Мне удалось решить ту же проблему с ответами выше, и ниже приведена моя реализация для уменьшения количества повторяющихся кодов JavaScript.

Я просмотрел столбцы, используя columns().eq(0).each(), затем агрегировал данные и добавил результат в нижний колонтитул.

library(shiny)
library(DT)

ui <- fluidPage(
        title = 'Select Table Rows', hr(), h1('A Server-side Table'),
        fluidRow(
                column(9, DT::dataTableOutput('x3'))
        )
)

server <- function(input, output, session) {
        mtcars2 = mtcars[, 1:8]
        sketch <- htmltools::withTags(table(
                class = "display", style = "bootstrap",
                tableHeader(colnames(mtcars2)),
                tableFooter(colnames(mtcars2))
        ))

        output$x3 = DT::renderDataTable(DT::datatable(mtcars2,
                container = sketch,
                extensions = 'Buttons',
                options = list(
                        scrollX = TRUE, scrollY = TRUE,
                        pageLength = 10, order = list(list(1, 'asc')),
                        dom = 'Blrtip', buttons = c('copy', 'csv', 'excel', 'pdf', 'print'),
                        footerCallback = JS(
                                "function( tfoot, data, start, end, display ) {",
                                        "var api = this.api(), data;",
                                        "api.columns().eq(0).each( function(index) {",
                                                "var col = api.column(index);",
                                                "if(index == 0) return $(api.column(index).footer()).html('Total')",
                                                "var data = col.data();",
                                                "total = data.reduce( function(a, b) { return a + b }, 0 );",
                                                "$( api.column(index).footer() ).html(total.toFixed(2));",
                                        "})",
                              "}"
                      ))
        ))
}
person Alex Ho    schedule 18.06.2019