Using values from slider in javascript DataTables calculations

隐身守侯 提交于 2021-02-11 14:39:45

问题


I've got a nested DataTable in my shiny app that is made from the data below. There are two sliders that I have which make up a percentage of 100. If one slider is 50 the other sider is 50. These two numbers from the two sliders help make up the Spot:30(%) and the Spot:15(%) columns of the child table.

There is another column, Mix(%), where the user is able to go in and edit the numbers. When the user edits this column the numbers in the Spot:30(%) and the Spot:15(%) columns are suppose to be updated accordingly.

The equations are:

Spot:30(%) = (Mix(%) * slider_value1)/100

Spot:15(%) = (Mix(%) * slider_value2)/100

Is there a way to use slider values from the Shiny app in the JS callback script to update the Spot:30(%) and the Spot:15(%) columns when the Mix(%) column is edited by the user??

I've attempted to try a solution like this one, example1, as well as trying to follow this, communicating with shiny via javascript, but can't seem to wrap my head around this.

Data

Parent
structure(list(Market = c("ABILENE-SWEETWATER", "ALBANY-SCHENECTADY-TROY, NY"
), `Gross CPP` = c("$0", "$0"), `Gross CPM` = c("$0", "$0"), 
    `Historical Composite Gross CPP` = c("$0", "$0"), `Historical Composite Gross CPM` = c("$0", 
    "$0")), .Names = c("Market", "Gross CPP", "Gross CPM", "Historical Composite Gross CPP", 
"Historical Composite Gross CPM"), row.names = c(NA, -2L), class = "data.frame")

Child
structure(list(Market = c("ABILENE-SWEETWATER", "ABILENE-SWEETWATER", 
"ABILENE-SWEETWATER", "ABILENE-SWEETWATER", "ABILENE-SWEETWATER", 
"ABILENE-SWEETWATER", "ABILENE-SWEETWATER", "ABILENE-SWEETWATER", 
"ABILENE-SWEETWATER", "ABILENE-SWEETWATER", "ALBANY-SCHENECTADY-TROY, NY", 
"ALBANY-SCHENECTADY-TROY, NY", "ALBANY-SCHENECTADY-TROY, NY", 
"ALBANY-SCHENECTADY-TROY, NY", "ALBANY-SCHENECTADY-TROY, NY", 
"ALBANY-SCHENECTADY-TROY, NY", "ALBANY-SCHENECTADY-TROY, NY", 
"ALBANY-SCHENECTADY-TROY, NY", "ALBANY-SCHENECTADY-TROY, NY", 
"ALBANY-SCHENECTADY-TROY, NY"), Daypart = c("Daytime", "Early Fringe", 
"Early Morning", "Early News", "Late Fringe", "Late News", "Prime Access", 
"Prime Time", "tv_2", "tv_cross_screen", "Daytime", "Early Fringe", 
"Early Morning", "Early News", "Late Fringe", "Late News", "Prime Access", 
"Prime Time", "tv_2", "tv_cross_screen"), `Mix (%)` = c(15, 10, 
15, 10, 5, 5, 10, 10, 0, 0, 15, 10, 15, 10, 5, 5, 10, 10, 0, 
0), `Spot:30 (%)` = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0), `Spot:15 (%)` = c(0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), `Gross CPP ($)` = c(18, 
18, 16, 23, 24, 40, 26, 44, 0, 0, 77, 71, 61, 78, 109, 145, 93, 
213, 0, 0), `Gross CPM ($)` = c(0, 0, 0, 0, 0, 0, 0, 0, 23, 13, 
0, 0, 0, 0, 0, 0, 0, 0, 23, 13), `Historical Override CPP ($)` = c(18, 
18, 16, 23, 24, 40, 26, 44, 0, 0, 77, 71, 61, 78, 109, 145, 93, 
213, 0, 0), `Historical Override CPM ($)` = c(0, 0, 0, 0, 0, 
0, 0, 0, 23, 13, 0, 0, 0, 0, 0, 0, 0, 0, 23, 13)), .Names = c("Market", 
"Daypart", "Mix (%)", "Spot:30 (%)", "Spot:15 (%)", "Gross CPP ($)", 
"Gross CPM ($)", "Historical Override CPP ($)", "Historical Override CPM ($)"
), class = "data.frame", row.names = c(NA, -20L))

EDIT

For some reason when I move the slider the Shiny Server observes the event and prints out the new slider value, but that new slider value doesn't get passed to the JS callback which in turn doesn't update the DataTable. The data table stays at the var slider = 50 and doesn't update.

Code

# The datatable callback
parentRows <- which(Dat[,1] != "")
callback_js = JS(
  "var tv_spots30 = 50;",
  "Shiny.addCustomMessageHandler('sliderValue1', function(value1){",
  "  tv_spots30 = value1;",
  "  $('#' + children[0]).DataTable().draw()",
  "  $('#' + children[1]).DataTable().draw();",
  "});",
  "var spots15 = 50;",
  "Shiny.addCustomMessageHandler('sliderValue2', function(value2){",
  "  spots15 = value2;",
  "  $('#' + children[0]).DataTable().draw();",
  "  $('#' + children[1]).DataTable().draw();",
  "});",
  "function onUpdate(updatedCell, updatedRow, oldValue) {};",
  sprintf("var parentRows = [%s];", toString(parentRows-1)),
  sprintf("var j0 = %d;", colIdx),
  "var nrows = table.rows().count();",
  "for(var i=0; i < nrows; ++i){",
  "  if(parentRows.indexOf(i) > -1){",
  "    table.cell(i,j0).nodes().to$().css({cursor: 'pointer'});",
  "  }else{",
  "    table.cell(i,j0).nodes().to$().removeClass('details-control');",
  "  }",
  "}",
  "",
  "// make the table header of the nested table",
  "var format = function(d, childId){",
  "  if(d != null){",
  "    var html = ",
  "      '<table class=\"display compact hover\" ' + ",
  "      'style=\"padding-left: 30px;\" id=\"' + childId + '\"><thead><tr>';",
  "    for(var key in d[d.length-1][0]){",
  "      html += '<th>' + key + '</th>';",
  "    }",
  "    html += '</tr></thead><tfoot><tr>'",
  "    for(var key in d[d.length-1][0]){",
  "      html += '<th></th>';",
  "    }",
  "    return html + '</tr></tfoot></table>';",
  "  } else {",
  "    return '';",
  "  }",
  "};",
  "",
  "// row callback to style the rows of the child tables",
  "var rowCallback = function(row, dat, displayNum, index){",
  "  if($(row).hasClass('odd')){",
  "    $(row).css('background-color', 'white');",
  "    $(row).hover(function(){",
  "      $(this).css('background-color', 'lightgreen');",
  "    }, function() {",
  "      $(this).css('background-color', 'white');",
  "    });",
  "  } else {",
  "    $(row).css('background-color', 'white');",
  "    $(row).hover(function(){",
  "      $(this).css('background-color', 'lightblue');",
  "    }, function() {",
  "      $(this).css('background-color', 'white');",
  "    });",
  "  }",
  "};",
  "",
  "// header callback to style the header of the child tables",
  "var headerCallback = function(thead, data, start, end, display){",
  "  $('th', thead).css({",
  "    'border-top': '3px solid green',",
  "    'color': 'black',",
  "    'background-color': 'white'",
  "  });",
  "};",
  "",
  "// make the datatable",
  "var format_datatable = function(d, childId, rowIdx){",
  "  // footer callback to display the totals",
  "  // and update the parent row",
  "  var footerCallback = function(tfoot, data, start, end, display){",
  "    $('th', tfoot).css('background-color', '#F5F2F2');",
  "    var api = this.api();",
  "    var col_mix = api.column(2).data();",
  "    for(let i = 0; i < col_mix.length; i++){",
  "      api.cell(i,3).data(parseFloat(col_mix[i])*tv_spots30/100);",
  "      api.cell(i,4).data(parseFloat(col_mix[i])*spots15/100);",
  "    }",
  "    api.columns().eq(0).each(function(index){",
  "      if(index == 0) return $(api.column(index).footer()).html('Mix Total');",
  "      var coldata = api.column(index).data();",
  "      var total = coldata",
  "          .reduce(function(a, b){return parseFloat(a) + parseFloat(b)}, 0);",
  "      if(index == 3 || index == 4 ||index == 5 || index == 6 || index==7 || index==8) {",
  "        $(api.column(index).footer()).html('');",
  "      } else {",
  "        $(api.column(index).footer()).html(total);",
  "      }",
  "      if(total == 100) {",
  "        $(api.column(index).footer()).css({'color': 'green'});",
  "      } else {",
  "        $(api.column(index).footer()).css({'color': 'red'});",
  "      }",
  "    })",
  "  // update the parent row",
  "    var col_share = api.column(2).data();",
  "    var col_CPP = api.column(5).data();",
  "    var col_CPM = api.column(6).data();",
  "    var col_Historical_CPP = api.column(7).data();",
  "    var col_Historical_CPM = api.column(8).data();",
  "    var CPP = 0, CPM = 0, Historical_CPP = 0, Historical_CPM = 0;",
  "    for(var i = 0; i < col_share.length; i++){",
  "      CPP += (parseFloat(col_share[i])*parseFloat(col_CPP[i]).toFixed(2));",
  "      CPM += (parseFloat(col_share[i])*parseFloat(col_CPM[i]).toFixed(2));",
  "      Historical_CPP += (parseFloat(col_share[i])*parseFloat(col_Historical_CPP[i]).toFixed(2));",
  "      Historical_CPM += (parseFloat(col_share[i])*parseFloat(col_Historical_CPM[i]).toFixed(2));",
  "    }",
  "    table.cell(rowIdx, j0+2).data((CPP/100).toFixed(2));",
  "    table.cell(rowIdx, j0+3).data((CPM/100).toFixed(2));",
  "    table.cell(rowIdx, j0+4).data((Historical_CPP/100).toFixed(2));",
  "    table.cell(rowIdx, j0+5).data((Historical_CPM/100).toFixed(2));",
  "  }",
  "  var dataset = [];",
  "  var n = d.length - 1;",
  "  for(var i = 0; i < d[n].length; i++){",
  "    var datarow = $.map(d[n][i], function (value, index) {",
  "      return [value];",
  "    });",
  "    dataset.push(datarow);",
  "  }",
  "  var id = 'table#' + childId;",
  "  if (Object.keys(d[n][0]).indexOf('_details') === -1) {",
  "    var subtable = $(id).DataTable({",
  "                 'data': dataset,",
  "                 'autoWidth': true,",
  "                 'deferRender': true,",
  "                 'info': false,",
  "                 'lengthChange': false,",
  "                 'ordering': d[n].length > 1,",
  "                 'order': [],",
  "                 'paging': true,",
  "                 'scrollX': false,",
  "                 'scrollY': false,",
  "                 'searching': false,",
  "                 'sortClasses': false,",
  "                 'pageLength': 50,",
  "                 'rowCallback': rowCallback,",
  "                 'headerCallback': headerCallback,",
  "                 'footerCallback': footerCallback,",
  "                 'columnDefs': [{targets: '_all', className: 'dt-center'}]",
  "               });",
  "  } else {",
  "    var subtable = $(id).DataTable({",
  "            'data': dataset,",
  "            'autoWidth': true,",
  "            'deferRender': true,",
  "            'info': false,",
  "            'lengthChange': false,",
  "            'ordering': d[n].length > 1,",
  "            'order': [],",
  "            'paging': true,",
  "            'scrollX': false,",
  "            'scrollY': false,",
  "            'searching': false,",
  "            'sortClasses': false,",
  "            'pageLength': 50,",
  "            'rowCallback': rowCallback,",
  "            'headerCallback': headerCallback,",
  "            'footerCallback': footerCallback,",
  "            'columnDefs': [",
  "              {targets: -1, visible: false},",
  "              {targets: 0, orderable: false, className: 'details-control'},",
  "              {targets: '_all', className: 'dt-center'}",
  "             ]",
  "          }).column(0).nodes().to$().css({cursor: 'pointer'});",
  "  }",
  "  subtable.MakeCellsEditable({",
  "    onUpdate: onUpdate,",
  "    inputCss: 'my-input-class',",
  "    columns: [2, 7, 8],",
  "    confirmationButton: {",
  "      confirmCss: 'my-confirm-class',",
  "      cancelCss: 'my-cancel-class'",
  "    }",
  "  });",
  "};",
  "",
  "// display the child table on click",
  "var children = [];", # array to store the id's of the already created child tables
  "table.on('click', 'td.details-control', function(){",
  "  var tbl = $(this).closest('table'),",
  "      tblId = tbl.attr('id'),",
  "      td = $(this),",
  "      row = $(tbl).DataTable().row(td.closest('tr')),",
  "      rowIdx = row.index();",
  "  if(row.child.isShown()){",
  "    row.child.hide();",
  "    td.html('&oplus;');",
  "  } else {",
  "    var childId = tblId + '-child-' + rowIdx;",
  "    if(children.indexOf(childId) === -1){", # this child table has not been created yet
  "      children.push(childId);",
  "      row.child(format(row.data(), childId)).show();",
  "      td.html('&CircleMinus;');",
  "      format_datatable(row.data(), childId, rowIdx);",
  "    }else{",
  "      row.child(true);",
  "      td.html('&CircleMinus;');",
  "    }",
  "  }",
  "});")

# Module to create the nested structure of the table
NestedData <- function(dat, children){
  stopifnot(length(children) == nrow(dat))
  g <- function(d){
    if(is.data.frame(d)){
      purrr::transpose(d)
    }else{
      purrr::transpose(NestedData(d[[1]], children = d$children))
    }
  }
  subdats <- lapply(children, g)
  oplus <- sapply(subdats, function(x) if(length(x)) "&oplus;" else "")
  cbind(" " = oplus, dat, "_details" = I(subdats), stringsAsFactors = FALSE)
}


# shiny
    # Bind the market level and mix breakout data together for the final table
    market_mix_table <- reactive({
      markets <- market_costings_gross_net()
      mix_breakout <- mix_breakout_digital_elements()
      # Make the dataframe
      # This must be met length(children) == nrow(dat)
      Dat <- NestedData(
        dat = markets,
        children = split(mix_breakout, mix_breakout$Market)
      )
      return(Dat)
    })

    # Render the table
    output$daypartTable <- DT::renderDataTable({
      Server = FALSE
      # Whether to show row names (set TRUE or FALSE)
      rowNames <- FALSE
      colIdx <- as.integer(rowNames)
      # The data
      Dat <- market_mix_table()
      # Table
      table <- DT::datatable(
        Dat,
        callback = callback_js,
        rownames = rowNames,
        escape = -colIdx-1,
        style = "bootstrap4",
          options = list(
            lengthMenu = list(
              c(-1, 10, 20),
              c("All", 10, 20)
            ),
            columnDefs = list(
              list(width = '30px'),
              list(width = '100px', targets = 1),
              list(visible = FALSE, targets = ncol(Dat)-1+colIdx),
              list(orderable = FALSE, className = 'details-control', targets = colIdx),
              list(className = "dt-center", targets = "_all")
            )
          )
        )
      # Some faancy Java magic
      path <- getwd()
      # Call the html tools deps (js & css files in this directory)
      dep <- htmltools::htmlDependency(
        "CellEdit", "1.0.19", path,
        script = "dataTables.cellEdit.js", stylesheet = "dataTables.cellEdit.css")
      table$dependencies <- c(table$dependencies, list(dep))
      # server = FALSE
      return(table)
    })

observeEvent(input[["tv_spots30"]], {
  print("30%")
  print(input[["tv_spots30"]])
  session$sendCustomMessage("sliderValue1", input[["tv_spots30"]])
})

observeEvent(input[["spots15"]], {
  print("15%")
  print(input[["spots15"]])
  session$sendCustomMessage("sliderValue2", input[["spots15"]])
})

# ui
          sliderInput("tv_spots30",
                      "Spots 30 (%):",
                      min = 0,
                      max = 100,
                      value = 50,
                      step = 5
          ),
          sliderInput("spots15",
                      "Spots 15 (%):",
                      min = 0,
                      max = 100,
                      value = 50,
                      step = 5
          ),

回答1:


Here is what I achieved.

At the beginning of the callback:

  "var slider = 50;",
  "Shiny.addCustomMessageHandler('sliderValue', function(value){",
  "  slider = value;",
  "  $('#' + children[0]).DataTable().draw();",
  "  $('#' + children[1]).DataTable().draw();",
  "});",

In server:

  observeEvent(input[["slider"]], {
    session$sendCustomMessage("sliderValue", input[["slider"]])
  })

And in the footer callback:

  "    var col_mix = api.column(2).data();",
  "    for(let i = 0; i < col_mix.length; i++){",
  "      api.cell(i,3).data(parseFloat(col_mix[i])*slider/100);",
  "      api.cell(i,4).data(parseFloat(col_mix[i])*(100-slider)/100);",
  "    }",

Full code:

library(DT)

df_children <- structure(
  list(
    Market = c("ABILENE-SWEETWATER", "ABILENE-SWEETWATER", "ABILENE-SWEETWATER", "ABILENE-SWEETWATER", "ABILENE-SWEETWATER", "ABILENE-SWEETWATER", "ABILENE-SWEETWATER", "ABILENE-SWEETWATER", "ABILENE-SWEETWATER", "ABILENE-SWEETWATER", "ALBANY-SCHENECTADY-TROY, NY", "ALBANY-SCHENECTADY-TROY, NY", "ALBANY-SCHENECTADY-TROY, NY", "ALBANY-SCHENECTADY-TROY, NY", "ALBANY-SCHENECTADY-TROY, NY", "ALBANY-SCHENECTADY-TROY, NY", "ALBANY-SCHENECTADY-TROY, NY", "ALBANY-SCHENECTADY-TROY, NY", "ALBANY-SCHENECTADY-TROY, NY", "ALBANY-SCHENECTADY-TROY, NY"), 
    Daypart = c("Daytime", "Early Fringe", "Early Morning", "Early News", "Late Fringe", "Late News", "Prime Access", "Prime Time", "tv_2", "tv_cross_screen", "Daytime", "Early Fringe", "Early Morning", "Early News", "Late Fringe", "Late News", "Prime Access", "Prime Time", "tv_2", "tv_cross_screen"), 
    `Mix (%)` = c(15, 10, 15, 10, 5, 5, 10, 10, 0, 0, 15, 10, 15, 10, 5, 5, 10, 10, 0, 0), 
    `Spot:30 (%)` = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 
    `Spot:15 (%)` = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 
    `Gross CPP ($)` = c(18, 18, 16, 23, 24, 40, 26, 44, 0, 0, 77, 71, 61, 78, 109, 145, 93, 213, 0, 0), 
    `Gross CPM ($)` = c(0, 0, 0, 0, 0, 0, 0, 0, 23, 13, 0, 0, 0, 0, 0, 0, 0, 0, 23, 13), 
    `Historical Override CPP ($)` = c(18, 18, 16, 23, 24, 40, 26, 44, 0, 0, 77, 71, 61, 78, 109, 145, 93, 213, 0, 0), 
    `Historical Override CPM ($)` = c(0, 0, 0, 0, 0, 0, 0, 0, 23, 13, 0, 0, 0, 0, 0, 0, 0, 0, 23, 13)
  ), 
  .Names = c("Market", "Daypart", "Mix (%)", "Spot:30 (%)", "Spot:15 (%)", "Gross CPP ($)", "Gross CPM ($)", "Historical Override CPP ($)", "Historical Override CPM ($)"), 
  class = "data.frame", 
  row.names = c(NA, -20L)
)

df_parent <- structure(
  list(
    Market = c("ABILENE-SWEETWATER", "ALBANY-SCHENECTADY-TROY, NY"), 
    `Gross CPP` = c("$0", "$0"), 
    `Gross CPM` = c("$0", "$0"), 
    `Historical Composite Gross CPP` = c("$0", "$0"), 
    `Historical Composite Gross CPM` = c("$0", "$0")
  ), 
  .Names = c("Market", "Gross CPP", "Gross CPM", "Historical Composite Gross CPP", "Historical Composite Gross CPM"), 
  row.names = c(NA, -2L), 
  class = "data.frame")

# function to make the required dataframe
NestedData <- function(dat, children){
  stopifnot(length(children) == nrow(dat))
  g <- function(d){
    if(is.data.frame(d)){
      purrr::transpose(d)
    }else{
      purrr::transpose(NestedData(d[[1]], children = d$children))
    }
  }
  subdats <- lapply(children, g)
  oplus <- sapply(subdats, function(x) if(length(x)) "&oplus;" else "")
  cbind(" " = oplus, dat, "_details" = I(subdats), stringsAsFactors = FALSE)
}

# make the required dataframe
# one must have: length(children) == nrow(dat)
Dat <- NestedData(
  dat = df_parent,
  children = split(df_children, df_children$Market)
)

## whether to show row names (set TRUE or FALSE)
rowNames <- FALSE
colIdx <- as.integer(rowNames)

## make the callback
parentRows <- which(Dat[,1] != "")
callback = JS(
  "var slider = 50;",
  "Shiny.addCustomMessageHandler('sliderValue', function(value){",
  "  slider = value;",
  "  $('#' + children[0]).DataTable().draw();",
  "  $('#' + children[1]).DataTable().draw();",
  "});",
  "function onUpdate(updatedCell, updatedRow, oldValue) {};",
  "table.MakeCellsEditable({",
  "  onUpdate: onUpdate,",
  "  inputCss: 'my-input-class',",
  "  confirmationButton: {",
  "    confirmCss: 'my-confirm-class',",
  "    cancelCss: 'my-cancel-class'",
  "  }",
  "});",
  sprintf("var parentRows = [%s];", toString(parentRows-1)),
  sprintf("var j0 = %d;", colIdx),
  "var nrows = table.rows().count();",
  "for(var i=0; i < nrows; ++i){",
  "  if(parentRows.indexOf(i) > -1){",
  "    table.cell(i,j0).nodes().to$().css({cursor: 'pointer'});",
  "  }else{",
  "    table.cell(i,j0).nodes().to$().removeClass('details-control');",
  "  }",
  "}",
  "",
  "// make the table header of the nested table",
  "var format = function(d, childId){",
  "  if(d != null){",
  "    var html = ", 
  "      '<table class=\"display compact hover\" ' + ",
  "      'style=\"padding-left: 30px;\" id=\"' + childId + '\"><thead><tr>';",
  "    for(var key in d[d.length-1][0]){",
  "      html += '<th>' + key + '</th>';",
  "    }",
  "    html += '</tr></thead><tfoot><tr>'",
  "    for(var key in d[d.length-1][0]){",
  "      html += '<th></th>';",
  "    }",
  "    return html + '</tr></tfoot></table>';",
  "  } else {",
  "    return '';",
  "  }",
  "};",
  "",
  "// row callback to style the rows of the child tables",
  "var rowCallback = function(row, dat, displayNum, index){",
  "  if($(row).hasClass('odd')){",
  "    $(row).css('background-color', 'papayawhip');",
  "    $(row).hover(function(){",
  "      $(this).css('background-color', '#E6FF99');",
  "    }, function() {",
  "      $(this).css('background-color', 'papayawhip');",
  "    });",
  "  } else {",
  "    $(row).css('background-color', 'lemonchiffon');",
  "    $(row).hover(function(){",
  "      $(this).css('background-color', '#DDFF75');",
  "    }, function() {",
  "      $(this).css('background-color', 'lemonchiffon');",
  "    });",
  "  }",
  "};",
  "",
  "// header callback to style the header of the child tables",
  "var headerCallback = function(thead, data, start, end, display){",
  "  $('th', thead).css({",
  "    'border-top': '3px solid indigo',", 
  "    'color': 'indigo',",
  "    'background-color': '#fadadd'",
  "  });",
  "};",
  "",
  "// make the datatable",
  "var format_datatable = function(d, childId, rowIdx){",
  "  // footer callback to display the totals",
  "  // and update the parent row",
  "  var footerCallback = function(tfoot, data, start, end, display){",
  "    $('th', tfoot).css('background-color', '#F5F2F2');",
  "    var api = this.api();",
  "    var col_mix = api.column(2).data();",
  "    for(let i = 0; i < col_mix.length; i++){",
  "      api.cell(i,3).data(parseFloat(col_mix[i])*slider/100);",
  "      api.cell(i,4).data(parseFloat(col_mix[i])*(100-slider)/100);",
  "    }",
  "    api.columns().eq(0).each(function(index){",
  "      if(index == 0) return $(api.column(index).footer()).html('Mix Total');",
  "      var coldata = api.column(index).data();",
  "      var total = coldata",
  "          .reduce(function(a, b){return parseFloat(a) + parseFloat(b)}, 0);",
  "      if(index == 3 || index == 4 ||index == 5 || index == 6 || index==7 || index==8) {",
  "        $(api.column(index).footer()).html('');",
  "      } else {",
  "        $(api.column(index).footer()).html(total);",
  "      }",
  "      if(total == 100) {",
  "        $(api.column(index).footer()).css({'color': 'green'});",
  "      } else {",
  "        $(api.column(index).footer()).css({'color': 'red'});",
  "      }",
  "    })",
  "  // update the parent row",
  "    var col_share = api.column(2).data();",
  "    var col_CPP = api.column(5).data();",
  "    var col_CPM = api.column(6).data();",
  "    var col_Historical_CPP = api.column(7).data();",
  "    var col_Historical_CPM = api.column(8).data();",
  "    var CPP = 0, CPM = 0, Historical_CPP = 0, Historical_CPM = 0;",
  "    for(var i = 0; i < col_share.length; i++){",
  "      CPP += (parseFloat(col_share[i])*parseFloat(col_CPP[i]).toFixed(2));",
  "      CPM += (parseFloat(col_share[i])*parseFloat(col_CPM[i]).toFixed(2));",
  "      Historical_CPP += (parseFloat(col_share[i])*parseFloat(col_Historical_CPP[i]).toFixed(2));",
  "      Historical_CPM += (parseFloat(col_share[i])*parseFloat(col_Historical_CPM[i]).toFixed(2));",
  "    }",
  "    table.cell(rowIdx, j0+2).data((CPP/100).toFixed(2));",
  "    table.cell(rowIdx, j0+3).data((CPM/100).toFixed(2));",
  "    table.cell(rowIdx, j0+4).data((Historical_CPP/100).toFixed(2));",
  "    table.cell(rowIdx, j0+5).data((Historical_CPM/100).toFixed(2));",
  "  }",
  "  var dataset = [];",
  "  var n = d.length - 1;",
  "  for(var i = 0; i < d[n].length; i++){",
  "    var datarow = $.map(d[n][i], function (value, index) {",
  "      return [value];",
  "    });",
  "    dataset.push(datarow);",
  "  }",
  "  var id = 'table#' + childId;",
  "  if (Object.keys(d[n][0]).indexOf('_details') === -1) {",
  "    var subtable = $(id).DataTable({",
  "                 'data': dataset,",
  "                 'autoWidth': true,",
  "                 'deferRender': true,",
  "                 'info': false,",
  "                 'lengthChange': false,",
  "                 'ordering': d[n].length > 1,",
  "                 'order': [],",
  "                 'paging': false,",
  "                 'scrollX': false,",
  "                 'scrollY': false,",
  "                 'searching': false,",
  "                 'sortClasses': false,",
  "                 'rowCallback': rowCallback,",
  "                 'headerCallback': headerCallback,",
  "                 'footerCallback': footerCallback,",
  "                 'columnDefs': [{targets: '_all', className: 'dt-center'}]",
  "               });",
  "  } else {",
  "    var subtable = $(id).DataTable({",
  "            'data': dataset,",
  "            'autoWidth': true,",
  "            'deferRender': true,",
  "            'info': false,",
  "            'lengthChange': false,",
  "            'ordering': d[n].length > 1,",
  "            'order': [],",
  "            'paging': false,",
  "            'scrollX': false,",
  "            'scrollY': false,",
  "            'searching': false,",
  "            'sortClasses': false,",
  "            'rowCallback': rowCallback,",
  "            'headerCallback': headerCallback,",
  "            'footerCallback': footerCallback,",
  "            'columnDefs': [", 
  "              {targets: -1, visible: false},", 
  "              {targets: 0, orderable: false, className: 'details-control'},", 
  "              {targets: '_all', className: 'dt-center'}",
  "             ]",
  "          }).column(0).nodes().to$().css({cursor: 'pointer'});",
  "  }",
  "  subtable.MakeCellsEditable({",
  "    onUpdate: onUpdate,",
  "    inputCss: 'my-input-class',",
  "    confirmationButton: {",
  "      confirmCss: 'my-confirm-class',",
  "      cancelCss: 'my-cancel-class'",
  "    }",
  "  });",
  "};",
  "",
  "// display the child table on click",
  "var children = [];", # array to store the id's of the already created child tables
  "table.on('click', 'td.details-control', function(){",
  "  var tbl = $(this).closest('table'),",
  "      tblId = tbl.attr('id'),",
  "      td = $(this),",
  "      row = $(tbl).DataTable().row(td.closest('tr')),",
  "      rowIdx = row.index();",
  "  if(row.child.isShown()){",
  "    row.child.hide();",
  "    td.html('&oplus;');",
  "  } else {",
  "    var childId = tblId + '-child-' + rowIdx;",
  "    if(children.indexOf(childId) === -1){", # this child table has not been created yet
  "      children.push(childId);",
  "      row.child(format(row.data(), childId)).show();",
  "      td.html('&CircleMinus;');",
  "      format_datatable(row.data(), childId, rowIdx);",
  "    }else{",
  "      row.child(true);",
  "      td.html('&CircleMinus;');",
  "    }",
  "  }",
  "});")

## the datatable
dtable <- datatable(
  Dat, callback = callback, rownames = rowNames, escape = -colIdx-1,
  options = list(
    columnDefs = list(
      list(visible = FALSE, targets = ncol(Dat)-1+colIdx),
      list(orderable = FALSE, className = 'details-control', targets = colIdx),
      list(className = "dt-center", targets = "_all")
    )
  )
)
path <- "~/Work/R/DT" # folder containing the files dataTables.cellEdit.js
                      # and dataTables.cellEdit.css
dep <- htmltools::htmlDependency(
  "CellEdit", "1.0.19", path, 
  script = "dataTables.cellEdit.js", stylesheet = "dataTables.cellEdit.css")
dtable$dependencies <- c(dtable$dependencies, list(dep))

# Shiny ####
library(shiny)

ui <- fluidPage(
  fluidRow(
    column(
      width = 4,
      sliderInput("slider", "Percentage", min = 0, max = 100, value = 50, step = 1)
    ),
    column(
      width = 8, 
      DTOutput("tbl")
    )
  )
)

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

  output[["tbl"]] <- renderDT(dtable)

  observeEvent(input[["slider"]], {
    session$sendCustomMessage("sliderValue", input[["slider"]])
  })

}

shinyApp(ui, server)



来源:https://stackoverflow.com/questions/60999913/using-values-from-slider-in-javascript-datatables-calculations

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!