微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

存储列总计并使用该值更新同一列 R Shiny+DT

如何解决存储列总计并使用该值更新同一列 R Shiny+DT

我正在开发一个使用 DT 包和一些 JavaScript 创建漂亮嵌套表的 Shiny 应用程序。在子表中,用户可以编辑第二列(混合 (%))。编辑该列后,第 6 列(GRP/TRP)也将更新。更新混合 (%) 时,我试图存储总 GRP/TRP(或点),然后使用该总数来更新 GRP/TRP 列。请参阅下面的等式。但是,编辑混合百分比时,总分不会正确更新。

主要问题在CosterTableJS中的footerCallback

totalGRPs/TRPs = sum(GRPs/TRPs 列)

GRPs/TRPs = (mix%/100)*totalGRPs/TRPs

以下也将使用 https://github.com/ejbeaty/CellEdit(MIT 许可)

# parent table 
parent_table  <- data.frame(structure(list(Market = "ABILENE-SWEETWATER",`Total GRPs/TRPs` = 500L,Cost = 82500,Impressions = 877215,Population = 175443),.Names = c("Market","Total GRPs/TRPs","Cost","Impressions","Population"),row.names = c(NA,-1L),class = "data.frame"))


# child table
child_table <- structure(list(Market = c("ABILENE-SWEETWATER","ABILENE-SWEETWATER","ABILENE-SWEETWATER"),Daypart = c("Early Morning","Daytime","Early Fringe","Early News","Prime Access","Prime Time","Late News","Late Fringe","Non-Linear"),`Mix (%)` = c(10,10,20),Week = c(1,1,1),Weeks = c(5L,5L,5L),`Override CPP` = c(16,18,17,24,27,55,43,22,58),`GRPs/TRPs` = c(10,Cost = c(160,180,170,240,270,550,430,220,1160),Impressions = c(17544.3,17544.3,35088.6),Population = c(175443,175443,175443
),`Full Flight Cost` = c(800,900,850,1200,1350,2750,2150,1100,5800),`Full Flight GRPs/TRPs` = c(50,50,100),`Full Flight Impressions` = c(87721.5,87721.5,175443)),"Daypart","Mix (%)","Week","Weeks","Override CPP","GRPs/TRPs","Population","Full Flight Cost","Full Flight GRPs/TRPs","Full Flight Impressions"),-9L),class = "data.frame")


# 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)) "<img src=\'https://raw.githubusercontent.com/DataTables/DataTables/master/examples/resources/details_open.png\'/>" else "")
  cbind(" " = oplus,dat,"_details" = I(subdats),stringsAsFactors = FALSE)
}


table <- nestedData(
        dat = parent_table,children = split(child_table,child_table$Market)
)
# Whether to show row names (set TRUE or FALSE)
rowNames <- FALSE
colIdx <- as.integer(rowNames)
parentRows <- which(table[,1] != "")
# Some JS for the table
coster_callback_js <- CosterTableJS(
  parentRows,colIdx
)
# Table
dtable <- datatable(
  table,callback = coster_callback_js,rownames = rowNames,escape = -colIdx-1,style = "bootstrap4",extensions = 'Buttons',options = list(
      dom = "Bt",columnDefs = list(
        list(width = '30px',targets = 0),list(width = '300px',targets = 1),list(width = '80px',targets = 3),list(visible = FALSE,targets = c(2,3,4,5)),targets = ncol(table)-1+colIdx),list(orderable = FALSE,className = 'details-control',targets = colIdx),list(className = "dt-center",targets = "_all")
    )
  )
)
# Call the html tools deps (js & css files in this directory)
path <- "/Users/timmcwilliams/Desktop" # folder containing the file dataTables.cellEdit.js
dep <- htmltools::htmlDependency(
  "CellEdit","1.0.19",path,script = "dataTables.cellEdit.js")
dtable$dependencies <- c(dtable$dependencies,list(dep))

dtable

CosterTableJS <- function(parentRows,colIdx) {
  return( 
    JS(
        "function onUpdate(updatedCell,updatedRow,oldValue) {","}","function renderInt(data,type,row) {","  if(type === 'display') {","    return parseFloat(data).toFixed(0);","  } else {","    return data;","  }","function renderDollars(data,"    return '$' + parseFloat(data).toFixed(2);",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{",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>'","      html += '<th></th>';","    return html + '</tr></tfoot></table>';","    return '';","};","// row callback to style the rows of the child tables","var rowCallback = function(row,displayNum,index){","  if($(row).hasClass('odd')){","    $(row).css('background-color','white');","    $(row).hover(function(){","      $(this).css('background-color','lightgreen');","    },function() {","    });",'lightblue');","// header callback to style the header of the child tables","var headerCallback = function(thead,data,start,end,display){","  $('th',thead).css({","    'color': 'black',","    'background-color': 'white'","  });","// make the datatable","var format_datatable = function(d,childId,rowIdx){","  // footer callback to display the totals","  var footerCallback = function(tfoot,"    $('th',tfoot).css('background-color','#F5F2F2');","    var api = this.api();","    var cpp = api.column(5).data();","    var mix = api.column(2).data();","    var points = api.column(6).data();","    var population = api.column(9).data();","    // HERE","    // Grab the sum of the points to use later on","    var pointsSumTotal = 0;","    for(var i = 0; i < points.length; i++) {","      pointsSumTotal += (parseFloat(points[i]));","    console.log('points',pointsSumTotal)","    // Update the Point column when the Mix column is edited","    for (var z = 0; z < mix.length; z++) {","      api.cell(z,6).data((mix[z]/100)*pointsSumTotal);","    // Update the Cost and Impressions with the new Points values","    for (var i = 0; i < points.length; i++) {","      // The cost","      api.cell(i,7).data(parseFloat(points[i]).toFixed(0)*parseFloat(cpp[i]));","      // The Imps",8).data((((parseFloat(points[i]).toFixed(0)/100)*parseFloat(population[i]))));","    // Update the full flight cost,points,and imps","    var weeks = api.column(4).data();","    var cost = api.column(7).data();","    var imps = api.column(8).data();","    for (var i = 0; i < weeks.length; i++) {","      // The full flight cost",10).data(parseFloat(weeks[i])*parseFloat(cost[i]));","      // The full flight points",11).data(parseFloat(weeks[i])*parseFloat(points[i]).toFixed(0));","      // The full flight imps",12).data(parseFloat(weeks[i])*parseFloat(imps[i]).toFixed(0));","// Make the footer sums","    api.columns().eq(0).each(function(index){","      if(index == 1) return $(api.column(index).footer()).html('Totals');","      var coldata = api.column(index).data();","      var total = coldata","          .reduce(function(a,b){return parseInt(a) + parseInt(b)},0);","      if(index == 3 || index == 4 ||index == 5) {","        $(api.column(index).footer()).html('');","      } else if (index == 7 || index == 10) {","        $(api.column(index).footer()).html('$' + total);","      } else {","        $(api.column(index).footer()).html(total);","      }","      if(index == 2 && total == 100) {","        $(api.column(index).footer()).css({'color': 'green'});","      } else if (index == 2 && total > 100) {","        $(api.column(index).footer()).css({'color': 'red'});","        $(api.column(index).footer()).css({'color': 'black'});","    Shiny.setInputValue('costerData:costernestedData',table.data().toArray());","    })","    // TO HERE","  var n = d.length - 1;","  var id = 'table#' + childId;","  var columns = Object.keys(d[n][0]).map(function(x){","    return {data: x,title: x};","    var subtable = $(id).DataTable({","                 'data': d[n],"                 'columns': columns,"                 'autoWidth': false,"                 'deferRender': true,"                 'info': false,"                 'lengthChange': false,"                 'ordering': d[n].length > 1,"                 'order': [],"                 'paging': false,"                 'scrollX': false,"                 'scrollY': false,"                 'searching': false,"                 'sortClasses': false,"                 'pageLength': 50,"                 'rowCallback': rowCallback,"                 'headerCallback': headerCallback,"                 'footerCallback': footerCallback,"                 'columnDefs': [","                    {targets: [4,2,6,8,11,12],render: renderInt},"                    {targets: [5,7,10],render: renderDollars},"                    {targets: [0,9],visible: false},"                    {targets: [1],width: '75px'},"                    {targets: [2],"                    {targets: [3],width: '135px'},"                    {targets: [4],"                    {targets: [5],width: '100px'},"                    {targets: [6],width: '80px'},"                    {targets: '_all',className: 'dt-center'}","                  ]","               });","  subtable.MakeCellsEditable({","    onUpdate: onUpdate,"    inputCss: 'my-input-class',"    columns: [2],"    inputTypes: [","      {column: 2,type: 'number'},"    ],"    confirmationButton: {","      confirmCss: 'my-confirm-class',"      cancelCss: 'my-cancel-class'","// display the child table on click","// array to store the id's of the already created child tables","var children = [];","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('<img src=\"https://raw.githubusercontent.com/DataTables/DataTables/master/examples/resources/details_open.png\"/>');","    var childId = tblId + '-child-' + rowIdx;","// this child table has not been created yet","    if(children.indexOf(childId) === -1){","      children.push(childId);","      row.child(format(row.data(),childId)).show();","    td.html('<img src=\"https://raw.githubusercontent.com/DataTables/DataTables/master/examples/resources/details_close.png\"/>');","      format_datatable(row.data(),rowIdx);","    }else{","      row.child(true);","});"
    )
  )
}

需要将此作为 dataTables.cellEdit.css

存储在本地文件夹中
.my-input-class {
  padding: 3px 6px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

.my-confirm-class {
  padding: 3px 6px;
  font-size: 12px;
  color: white;
  text-align: center;
  vertical-align: middle;
  border-radius: 4px;
  background-color: #337ab7;
  text-decoration: none;
}

.my-cancel-class {
  padding: 3px 6px;
  font-size: 12px;
  color: white;
  text-align: center;
  vertical-align: middle;
  border-radius: 4px;
  background-color: #a94442;
  text-decoration: none;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。