如何解决从可编辑的数据表中替换初始数据框,然后在另一个表中使用该新数据框
我的Shiny应用程序中有一个嵌套的DataTable。子表中的某些列可由用户编辑。此处的目标是让用户编辑值,然后将数据框替换为这些新值。然后,我想将替换后的数据框用于另一个表。我需要在另一个表中使用编辑后的值进行计算。
工作流程:
create nested data table -> user edits values -> initial data is replaced by new data -> use the new data for another table
我尝试使用reactiveValues()
,dataTableProxy()
,replaceData()
和observeEvert()
来遵循该工作流程,但是没有运气。
# Parent table
structure(list(Market = c("ABILENE-SWEETWATER","ALBANY-SCHENECTADY-TROY,NY"
),`Gross CPP` = c("$1.94","$7.89"),`Gross CPM` = c("$1.02","$0.82"),`Historical Composite Gross CPP (if applicable)` = c("$0","$0"),`Historical Composite Gross CPM (if applicable)` = c("$0","$0")),.Names = c("Market","Gross CPP","Gross CPM","Historical Composite Gross CPP (if applicable)","Historical Composite Gross CPM (if applicable)"),row.names = c(NA,-2L),class = "data.frame")
# Child table
structure(list(Market = c("ABILENE-SWEETWATER","ABILENE-SWEETWATER",NY",NY"),Daypart = c("Daytime","Early Fringe","Early Morning","Early News","Late Fringe","Late News","Prime Access","Prime Time","tv_2","tv_3","tv_cross_screen","Daytime","tv_cross_screen"),`Mix (%)` = c(15,10,15,5,0),`Spot:30 (%)` = c(15,`Spot:15 (%)` = c(0,0
),`Gross CPP ($)` = c(18,18,16,23,24,40,26,44,77,71,61,78,109,145,93,213,`Gross CPM ($)` = c(1.57,1.57,1.39,2,2.09,3.49,2.27,3.83,21,13,6.71,6.19,5.32,6.8,9.5,12.63,8.1,18.56,13),`Historical Composite CPP ($)` = c(0,`Historical Composite CPM ($)` = c(0,0)),"Daypart","Mix (%)","Spot:30 (%)","Spot:15 (%)","Gross CPP ($)","Gross CPM ($)","Historical Composite CPP ($)","Historical Composite CPM ($)"
),class = "data.frame",-22L))
# 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)
}
# Bind the market level and mix breakout data together for the final table
market_mix_table <- reactive({
# Take a dependency on input$goButton
input$goButton
isolate({
# The rolled up market view - Parent table
parent <- market_level_view()
# The daypart breakout for each market - Child table
child <- mix_breakout_digital_elements()
# Make the dataframe
# This must be met length(children) == nrow(dat)
Dat <- NestedData(
dat = parent,children = split(child,child$Market)
)
return(Dat)
})
})
# Render the table
output$daypartTable <- DT::renderDataTable({
# Whether to show row names (set TRUE or FALSE)
rowNames <- FALSE
colIdx <- as.integer(rowNames)
# The data
Dat <- market_mix_table()
parentRows <- which(Dat[,1] != "")
excelTitle <- paste(
input$name,input$medium,input$quarter,"Market CPM-CPP Breakout",sep=" "
)
## If the JS stops working take the coed and put it here
callback_js = JS(
"var ok = true;","function onUpdate(updatedCell,updatedRow,oldValue) {"," var column = updatedCell.index().column;"," if(column === 8){"," ok = false;"," }else if(column === 7){"," ok = true;"," }","}",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>';"," } else {"," 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"," // and update the parent row"," var footerCallback = function(tfoot," $('th',tfoot).css('background-color','#F5F2F2');"," var api = this.api();","// update the Override CPM when the Override CPP is changed"," var col_override_cpp = api.column(7).data();"," var col_population = api.column(9).data();"," if(ok){"," for(var i = 0; i < col_override_cpp.length; i++){"," api.cell(i,8).data(((parseFloat(col_override_cpp[i])*100)/(parseFloat(col_population[i])/1000)).toFixed(2));"," }","// update the Override CPP when the Override CPM is changed"," var col_override_cpm = api.column(8).data();"," for(var i = 0; i < col_override_cpm.length; i++){"," api.cell(i,7).data(((parseFloat(col_override_cpm[i])*parseFloat(col_population[i])/1000)/100).toFixed(0));","// Update the spot mixes"," var col_mix_percentage = api.column(2).data();"," var col_mix60_mix30 = api.column(10).data();"," var col_mix30_mix15 = api.column(11).data();"," for(var i = 0; i < col_mix_percentage.length; i++){",3).data((parseFloat(col_mix_percentage[i])*parseFloat(col_mix60_mix30[i])).toFixed(1));",4).data((parseFloat(col_mix_percentage[i])*parseFloat(col_mix30_mix15[i])).toFixed(1));"," var child_col_CPM = api.column(6).data();"," for(var i = 0; i < child_col_CPM.length; i++){",6).data(parseFloat(child_col_CPM[i]).toFixed(2));",# " parseFloat(api.column(5)).toFixed(2)","// Make the footer sums"," 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 parseInt(a) + parseInt(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'});"," $(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 += (parseInt(col_share[i])*parseInt(col_CPP[i]).toFixed(0));"," CPM += (parseInt(col_share[i])*parseInt(col_CPM[i]).toFixed(2));"," Historical_CPP += (parseInt(col_share[i])*parseInt(col_Historical_CPP[i]).toFixed(0));"," Historical_CPM += (parseInt(col_share[i])*parseInt(col_Historical_CPM[i]).toFixed(2));"," table.cell(rowIdx,j0+3).data((CPP/100).toFixed(2));",j0+4).data((CPM/100).toFixed(2));",j0+5).data((Historical_CPP/100).toFixed(2));",j0+6).data((Historical_CPM/100).toFixed(2));"," var n = d.length - 1;"," var id = 'table#' + childId;"," var columns = Object.keys(d[n][0]).map(function(x){"," return {data: x,title: x};"," if (Object.keys(d[n][0]).indexOf('_details') === -1) {"," var subtable = $(id).DataTable({"," 'data': d[n]," 'columns': columns," '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: [0,9,11],visible: false}," {targets: '_all',className: 'dt-center'}"," ]"," });"," 'data': d[n]," 'columns': columns," '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: [0," {targets: -1," {targets: 0,orderable: false,className: 'details-control'}," {targets: '_all'," ]"," }).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","// 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);","});"
)
# Download button
downloadButtonJS <- c(
"function(xlsx) {"," var table = $('#daypartTable').find('table').DataTable();"," // Letters for Excel columns."," var LETTERS = ["," 'A','B','C','D','E','F','G','H','I','J','K','L','M'," 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z'"," ];"," // Get sheet."," var sheet = xlsx.xl.worksheets['sheet1.xml'];"," // Get a clone of the sheet data. "," var sheetData = $('sheetData',sheet).clone();"," // Clear the current sheet data for appending rows."," $('sheetData',sheet).empty();"," // Row count in Excel sheet."," var rowCount = 1;"," // Iterate each row in the sheet data."," $(sheetData).children().each(function (index) {"," // Used for DT row() API to get child data."," var rowIndex = index - 2;",#
" // Don't process row if its the header row.",sprintf(" if (index > 1 && index < %d) {",nrow(Dat)+2),#
" // Get row"," var row = $(this.outerHTML);"," // Set the Excel row attr to the current Excel row count."," row.attr('r',rowCount);"," // Iterate each cell in the row to change the row number."," row.children().each(function (index) {"," var cell = $(this);"," // Set each cell's row value."," var rc = cell.attr('r');"," rc = rc.replace(/\\d+$/,\"\") + rowCount;"," cell.attr('r',rc);"," });"," // Get the row HTML and append to sheetData."," row = row[0].outerHTML;"," $('sheetData',sheet).append(row);"," rowCount++;"," // Get the child data - could be any data attached to the row."," // Basically this grabd all the rows of data",sprintf(" var childData = table.row(':eq(' + rowIndex + ')').data()[%d];",ncol(Dat)-1)," if (childData.length > 0) {"," var colNames = Object.keys(childData[0]).slice(1,9);"," // Prepare Excel formatted row"," headerRow = '<row r=\"' + rowCount +"," '\"><c t=\"inlineStr\" r=\"A' + rowCount +"," '\"><is><t></t></is></c>';"," for(var i = 0; i < colNames.length; i++){"," headerRow = headerRow +"," '<c t=\"inlineStr\" r=\"' + LETTERS[i+1] + rowCount +"," '\" s=\"7\"><is><t>' + colNames[i] +"," '</t></is></c>';"," }"," headerRow = headerRow + '</row>';"," // Append header row to sheetData."," $('sheetData',sheet).append(headerRow);"," rowCount++; // Inc excelt row counter."," // The child data is an array of rows"," for (let c = 0; c < childData.length; c++) {"," // Get row data."," var child = childData[c];"," var childRow = '<row r=\"' + rowCount +"," for(let i = 0; i < colNames.length; i++){"," childRow = childRow +"," '\" s=\"5\"><is><t>' + child[colNames[i]] +"," childRow = childRow + '</row>';"," // Append row to sheetData.",sheet).append(childRow);"," rowCount++; // Inc excel row counter."," // Just append the header row and increment the excel row counter."," } else {",sheet).append(this.outerHTML);","}"
)
# Table
table <- DT::datatable(
Dat,callback = callback_js,rownames = rowNames,escape = -colIdx-1,style = "bootstrap4",extensions = 'Buttons',options = list(
dom = "Bt",columnDefs = list(
list(width = '30px',targets = 0),list(width = '330px',targets = 1),list(visible = FALSE,targets = ncol(Dat)-1+colIdx),list(orderable = FALSE,className = 'details-control',targets = colIdx),list(className = "dt-center",targets = "_all")
),buttons = list(
list(
extend = "excel",className = 'btn btn-primary glyphicon glyphicon-download-alt',text = " Export",exportOptions = list(
orthogonal = "export",columns = 0:(ncol(Dat)-2)
),title = excelTitle,orientation = "landscape",customize = JS(downloadButtonJS)
)
),lengthMenu = list(c(-1,20),c("All",20))
)
)
# Call the html tools deps (js & css files in this directory)
cell_edit_dep <- htmltools::htmlDependency(
"CellEdit","1.0.19",src = 'www/',script = "dataTables.cellEdit.js",stylesheet = "dataTables.cellEdit.css"
)
table$dependencies <- c(table$dependencies,list(cell_edit_dep))
table %>% formatStyle(
c(MARKET[2],'Population',SQAD_CPP_DOLLAR,SQAD_CPM_DOLLAR,OVERRIDE_CPP_DOLLAR,OVERRIDE_CPM_DOLLAR),target = 'row',backgroundColor = "#F5F2F2"
)
},server = FALSE)
### This is where I am trying to save the edits to the table and
### use those new values for the below table
output$market_costings_gross_net_table <- renderTable({
# Get the data from reative function
market_costings <- market_level_view()
reactive_market_costings <- reactiveValues(data = market_costings)
proxy <- dataTableProxy("daypartTable")
observeEvent(input$tableRefresh,{
DT::replaceData(proxy,reactive_market_costings$data)
})
})
解决方法
第一轮
要获取Shiny中的数据:
-
在
footerCallback
函数的末尾添加以下行:" Shiny.setInputValue('data:nestedData',table.data().toArray());",
-
在“闪亮”应用之前,添加:
library(jsonlite)
registerInputHandler(
"nestedData",function(data,...){
fromJSON(toJSON(data))
},force = TRUE
)
- 然后数据在
input[["data"]]
中可用:
observe({
print(input[["data"]])
})
如果您需要更多帮助,请编辑您的帖子以使代码可重复。我没有此代码的最新版本。
第二轮
如我的评论所述,最好在toFixed
选项中使用render
。我还将可编辑单元格的类型设置为number
,这样,已编辑单元格的值就不会转换为字符串,并且在编辑框中还有旋转箭头。
library(DT)
df_children <-
structure(
list(
Market = c(
"ABILENE-SWEETWATER","ABILENE-SWEETWATER","ALBANY-SCHENECTADY-TROY,NY",NY"
),Daypart = c(
"Daytime","Early Fringe","Early Morning","Early News","Late Fringe","Late News","Prime Access","Prime Time","tv_2","tv_3","tv_cross_screen","Daytime","tv_cross_screen"
),`Mix (%)` = c(15,10,15,5,0),`Spot:30 (%)` = c(15,`Spot:15 (%)` = c(0,`Gross CPP ($)` = c(
18,18,16,23,24,40,26,44,77,71,61,78,109,145,93,213,0
),`Gross CPM ($)` = c(
1.57,1.57,1.39,2,2.09,3.49,2.27,3.83,21,13,6.71,6.19,5.32,6.8,9.5,12.63,8.1,18.56,13
),`Historical Composite CPP ($)` = c(0,`Historical Composite CPM ($)` = c(0,population = c(
47200L,47200L,162700L,162700L
),slider_60s = c(
0.4,0.4,0.4
),slider_30s = c(
0.6,0.6,0.6
)
),.Names = c(
"Market","Daypart","Mix (%)","Spot:30 (%)","Spot:15 (%)","Gross CPP ($)","Gross CPM ($)","Historical Composite CPP ($)","Historical Composite CPM ($)","population","slider_60s","slider_30s"
),class = "data.frame",row.names = c(NA,-22L)
)
df_parent <-
structure(
list(
Market = c("ABILENE-SWEETWATER",NY"),`Gross CPP` = c(1.94,7.89),`Gross CPM` = c(1.02,0.82),`Historical Composite Gross CPP (if applicable)` = c(0,`Historical Composite Gross CPM (if applicable)` = c(0,0)
),"Gross CPP","Gross CPM","Historical Composite Gross CPP (if applicable)","Historical Composite Gross CPM (if applicable)"
),-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)) "⊕" 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 = JS(
"var ok = true;","function onUpdate(updatedCell,updatedRow,oldValue) {"," var column = updatedCell.index().column;"," if(column === 8){"," ok = false;"," }else if(column === 7){"," ok = true;"," }","}","function render0(data,type,row) {",# @Timothy,new
" if(type === 'display') {"," return parseFloat(data).toFixed(0);"," } else {"," return data;","function render2(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"," // and update the parent row"," var footerCallback = function(tfoot,I removed all the 'toFixed'
" $('th',tfoot).css('background-color','#F5F2F2');"," var api = this.api();","// update the Override CPM when the Override CPP is changed"," var col_override_cpp = api.column(7).data();"," var col_population = api.column(9).data();"," if(ok){"," for(var i = 0; i < col_override_cpp.length; i++){"," api.cell(i,8).data(((parseFloat(col_override_cpp[i])*100)/(parseFloat(col_population[i])/1000)));"," }","// update the Override CPP when the Override CPM is changed"," var col_override_cpm = api.column(8).data();"," for(var i = 0; i < col_override_cpm.length; i++){"," api.cell(i,7).data(((parseFloat(col_override_cpm[i])*parseFloat(col_population[i])/1000)/100));","// Update the spot mixes"," var col_mix_percentage = api.column(2).data();"," var col_mix60_mix30 = api.column(10).data();"," var col_mix30_mix15 = api.column(11).data();"," for(var i = 0; i < col_mix_percentage.length; i++){",3).data((parseFloat(col_mix_percentage[i])*parseFloat(col_mix60_mix30[i])));",4).data((parseFloat(col_mix_percentage[i])*parseFloat(col_mix30_mix15[i])));"," var child_col_CPM = api.column(6).data();"," for(var i = 0; i < child_col_CPM.length; i++){",6).data(parseFloat(child_col_CPM[i]));","// Make the footer sums"," 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'});"," $(api.column(index).footer()).css({'color': 'red'});"," })"," // update the parent row",I replaced everywhere parseInt with parseFloat
" 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]));"," CPM += (parseFloat(col_share[i])*parseFloat(col_CPM[i]));"," Historical_CPP += (parseFloat(col_share[i])*parseFloat(col_Historical_CPP[i]));"," Historical_CPM += (parseFloat(col_share[i])*parseFloat(col_Historical_CPM[i]));"," table.cell(rowIdx,j0+2).data(CPP/100);",there were errors here (it's j0 + 2/3/4/5)
" table.cell(rowIdx,j0+3).data(CPM/100);",j0+4).data(Historical_CPP/100);",j0+5).data(Historical_CPM/100);"," Shiny.setInputValue('data:nestedData'," 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': 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: [2,3,4],render: render0},new
" {targets: [5,6,7,8],render: render2},new
" {targets: [0,9,11],visible: false}," {targets: '_all',className: 'dt-center'}"," ]"," });"," subtable.MakeCellsEditable({"," onUpdate: onUpdate," inputCss: 'my-input-class'," columns: [2," inputTypes: [",new
" {column: 2,type: 'number'}," {column: 7," {column: 8,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);","});"
)
render_js <- JS( # @Timothy,new
"function(data," if(type === 'display') {"," return '$' + data.toFixed(2);","}"
)
## the datatable
dtable <- datatable(
Dat,callback = callback_js,rownames = rowNames,escape = -colIdx-1,extensions = "Buttons",options = list(
dom = "Bfrtip",columnDefs = list(
list(render = render_js,targets = colIdx + 1 + 1:4),new
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))
library(shiny)
library(jsonlite)
registerInputHandler(
"nestedData",...){
fromJSON(toJSON(data))
},force = TRUE
)
ui <- fluidPage(
br(),DTOutput("dtable")
)
server <- function(input,output){
output[["dtable"]] <- renderDT(dtable)
observe({
print(input[["data"]])
})
}
shinyApp(ui,server)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。