Jquery 使用ajax创建具有子行的数据表
我正在尝试使用datatables库进行更多定制 这是我想举的一个例子。 请注意,我在不同的data.frame R变量中有详细信息。像这样Jquery 使用ajax创建具有子行的数据表,jquery,ajax,r,datatables,shiny,Jquery,Ajax,R,Datatables,Shiny,我正在尝试使用datatables库进行更多定制 这是我想举的一个例子。 请注意,我在不同的data.frame R变量中有详细信息。像这样 A= data.frame(Name = c("Airi Satou", "Angelica Ramos","Paul Byrd") , Position = c("Accountant","Accountant", "CEO") , Office = c("Tokyo", "Tokyo",
A= data.frame(Name = c("Airi Satou", "Angelica Ramos","Paul Byrd")
, Position = c("Accountant","Accountant", "CEO")
, Office = c("Tokyo", "Tokyo", "New York"))
A.detail= data.frame(Name = c("Airi Satou", "Angelica Ramos")
, Extension= c("5407c", "8422")
, salary = c(16000, 20000))
我不喜欢合并两个data.frame变量,如果不合并也可以,因为计算时间太长。显然,某些行可能没有任何详细信息
我可以在数据表中选择一行,并通过将其绑定为输入将行信息发送到R(感谢)
然后我可以从第二个data.frame变量中找到与R中所选行相关的详细信息。
但我不知道如何将其发送回html(在所选行下)上显示。我已经按Shinyout的话装订好了第一张桌子,所以我;我不确定是否可以传递另一个数据来再次更改此输出
也许我应该在单击detail按钮时使用ajax来请求更多数据,但我不知道如何在shiny中执行ajax请求。在回答您的问题之前,我想指出,CRAN上当前版本的shiny(0.10.1)使用的是旧版本的DataTables.js(1.0.9),而您提到的示例使用DataTables.js 1.10。DataTables 1.10中有相当一部分API与版本1.0.9不兼容 您可以在Github:(提供DataTables.js 1.10支持)上查看此拉取请求
首先,让我们离题一点,了解数据表是如何在文本中呈现的 该示例使用AJAX请求从服务器URL“拉”出数据,然后将数据绑定到表模板。这就是所谓的服务器端数据呈现 Shining还使用服务器端数据呈现。但是,您提供的示例与Shiny的主要区别在于,Shiny中的数据传输对您来说是透明的 从技术上讲,Shinny通过调用
shinny:::registerDataObj()
为AJAX请求创建JSON API。您可以在此处找到构造自定义AJAX请求的示例:
示例和Shiny之间的另一个区别(稍后将在R代码中反映)是如何将表内容编码为JSON blob。
该示例使用普通对象对每条线进行编码。例如,第一行编码为:
{
“名字”:“老虎尼克松”,
“职位”:“系统架构师”,
“工资”:“$320800”,
“开始日期”:“2011\/04\/25”,
“办公室”:“爱丁堡”,
“extn”:“5421”
},
而Shining将data.frame
的每一行编码为数组,例如
[“老虎尼克松”,“系统架构师”,
“$320800”、“2011\/04\/25”、“爱丁堡”、“5421”]
rawJSON数据的差异会影响我们以后如何实现format()
函数
最后,示例使用固定的HTML
模板来呈现数据表。您可能已经注意到,模板中只包含可见列(例如,
模板中不包含分机号码列);然而,Shining为您创建模板,您无法决定如何执行数据绑定(例如,{“data”:“name”},
)
注意:下面的R代码使用了Shiny的开发分支,您可以在上面的pull request链接中找到它。 虽然我们无法决定哪些列要绑定到哪些数据,但在调用
DataTable()
函数时,我们可以通过指定columnDefs
选项来选择要隐藏哪些列。您可以传递中定义的任何选项https://datatables.net/reference/option/
将它们包装在R中的列表中
使用示例数据的闪亮应用程序示例如下:
用户界面
现在,如果您单击数据表的第一(空)列(因为我没有编写CSS),您应该能够看到扩展区域中显示的额外信息
编辑:延迟加载“更多详细信息”信息
上述解决方案涉及将所有信息发送到客户端,尽管在大多数使用情况下,用户可能不会费心查看隐藏的信息。实际上,我们最终会向客户端发送大量冗余数据
更好的解决方案是在Shiny中实现AJAX请求处理程序,它只在需要时(即在用户请求时)返回信息
要实现AJAX请求处理程序,可以使用会话$registerDataObj
。此函数在唯一的URL注册请求处理程序,并返回此URL
为了调用这个已注册的请求处理程序,您需要首先将这个AJAX URL发送到客户端
下面我给出了一个快速的解决方案:基本上你可以在网页上创建一个隐藏的
元素,你可以在上面绑定一个更改
事件监听器。闪亮服务器通过调用函数会话$sendInputMessage
向客户端发送消息来更新此
元素的值。收到消息后,它会更改
元素的值,从而触发事件侦听器。然后,我们可以正确设置AJAX请求URL
之后,您可以启动任何普通的AJAX请求来获取所需的数据
用户界面
库(闪亮)
format.func您可以将其作为输出对象(df或list)从服务器发回,然后在输出变量更改或设置标志时显示详细信息。如果您在github上安装现有代码,我可能会尝试这样做,并提出一个拉取请求。@Mahdi Jadaliha:我也对让它工作起来感兴趣。你有一个有效的例子吗?不幸的是,我还没有找到答案。谢谢killkeeper,它是有效的。这是否可以避免“left_join(A,A.detail,by=“Name”)”?我的桌子很大,很少使用
library(shiny)
format.func <- "
<script type='text/javascript'>
function format ( d ) {
return '<table cellpadding=\"5\" cellspacing=\"0\" border=\"0\" style=\"padding-left:50px;\">'+
'<tr>'+
'<td>Full name:</td>'+
'<td>'+d[1]+'</td>'+
'</tr>'+
'<tr>'+
'<td>Extension number:</td>'+
'<td>'+d[4]+'</td>'+
'</tr>'+
'</table>';
}
</script>
"
shinyUI(
fluidPage(
h5("Data table"),
dataTableOutput("dt"),
tags$head(HTML(format.func))
)
)
library(shiny)
library(dplyr)
shinyServer(function(input, output, session) {
A <- data.frame(Name = c("Airi Satou", "Angelica Ramos","Paul Byrd"),
Position = c("Accountant","Accountant", "CEO"),
Office = c("Tokyo", "Tokyo", "New York"))
A.detail <- data.frame(Name = c("Airi Satou", "Angelica Ramos"),
Extension = c("5407c", "8422"),
Salary = c(16000, 20000))
# You don't necessarily need to use left_join. You can simply put every column,
# including the columns you would by default to hide, in a data.frame.
# Then later choose which to hide.
# Here an empty column is appended to the left to mimic the "click to expand"
# function you've seen in the example.
A.joined <- cbind("", left_join(A, A.detail, by="Name"))
columns.to.hide <- c("Extension", "Salary")
# Javascript uses 0-based index
columns.idx.hidden <- which(names(A.joined) %in% columns.to.hide) - 1
# Everytime a table is redrawn (can be triggered by sorting, searching and
# pagination), rebind the click event.
draw.callback <- "
function(settings) {
var api = this.api();
var callback = (function($api) {
return function() {
var tr = $(this).parent();
var row = $api.row(tr);
if (row.child.isShown()) {
row.child.hide();
tr.removeClass('shown');
}
else {
row.child(format(row.data())).show();
tr.addClass('shown');
}
}
})(api);
$(this).on('click', 'td.details-control', callback);
}"
# wrap all options you would like to specify in options=list(),
# which will be converted into corresponding JSON object.
output$dt <- renderDataTable(A.joined,
options=list(
searching=F,
columnDefs=list(
list(targets=0,
title="", class="details-control"),
list(targets=columns.idx.hidden,
visible=F)
),
drawCallback=I(draw.callback)
))
})
library(shiny)
format.func <- "
<script type='text/javascript'>
var _ajax_url = null;
function format ( d ) {
// `d` is the original data object for the row
return '<table cellpadding=\"5\" cellspacing=\"0\" border=\"0\" style=\"padding-left:50px;\">'+
'<tr>'+
'<td>Full name:</td>'+
'<td>'+d.Name+'</td>'+
'</tr>'+
'<tr>'+
'<td>Extension number:</td>'+
'<td>'+d.Extension+'</td>'+
'</tr>'+
'</table>';
}
$(document).ready(function() {
$('#ajax_req_url').on('change', function() { _ajax_url = $(this).val()});
})
</script>
"
shinyUI(
fluidPage(
# create a hidden input element to receive AJAX request URL
tags$input(id="ajax_req_url", type="text", value="", class="shiny-bound-input", style="display:none;"),
h5("Data table"),
dataTableOutput("dt"),
tags$head(HTML(format.func))
)
)
library(shiny)
library(dplyr)
shinyServer(function(input, output, session) {
# extra more.details dummy column
A <- data.frame(more.details="", Name = c("Airi Satou", "Angelica Ramos","Paul Byrd"),
Position = c("Accountant","Accountant", "CEO"),
Office = c("Tokyo", "Tokyo", "New York"))
A.detail <- data.frame(Name = c("Airi Satou", "Angelica Ramos"),
Extension = c("5407c", "8422"),
Salary = c(16000, 20000))
draw.callback <- "
function(settings) {
var api = this.api();
var callback = (function($api) {
return function() {
var tr = $(this).parent();
var row = $api.row(tr);
if (row.child.isShown()) {
row.child.hide();
tr.removeClass('shown');
}
else {
// we can use the unique ajax request URL to get the extra information.
$.ajax(_ajax_url, {
data: {name: row.data()[1]},
success: function(res) {
row.child(format(res)).show();
tr.addClass('shown');
}
});
}
}
})(api);
$(this).on('click', 'td.details-control', callback);
}"
ajax_url <- session$registerDataObj(
name = "detail_ajax_handler", # an arbitrary name for the AJAX request handler
data = A.detail, # binds your data
filter = function(data, req) {
query <- parseQueryString(req$QUERY_STRING)
name <- query$name
# pack data into JSON and send.
shiny:::httpResponse(
200, "application/json",
# use as.list to convert a single row into a JSON Plain Object, easier to parse at client side
RJSONIO:::toJSON(as.list(data[data$Name == name, ]))
)
}
)
# send this UNIQUE ajax request URL to client
session$sendInputMessage("ajax_req_url", list(value=ajax_url))
output$dt <- renderDataTable(A,
options=list(
searching=F,
columnDefs=list(
list(targets=0,
title="", class="details-control")
),
drawCallback=I(draw.callback)
))
})