这是此问题的后续问题使用shinyjqui拖放到网格表中
这是代码:
library(shiny)
library(shinyjqui)
connections <- paste0("droppable_cell_", 1:7) # id of the grid cells
ui <- fluidPage(
tags$head(tags$script(
JS(
"
$(function() {
$('[id^=droppable_cell]').sortable({
connectWith: '#letters',
drop: function(event, ui) {
$(this).append(ui.draggable);
}
})
});
"
)
),
# some styling
tags$style(
HTML(
"
.grid-table {
width: 150px;
border-collapse: collapse;
}
.grid-cell {
width: 100%;
height: 50px;
border: 1px solid black;
background-color: white;
text-align: center;
margin: 0;
padding: 5px;
}
.grid-cell-text {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
background-color: steelblue;
color: white;
font-size: 18px;
}
.droppable-cell {
background-color: lightgray;
}
.table-container {
display: flex;
position: absolute;
left: 550px;
top: 30px;
margin-top: 0px;
overflow: hidden;
}
"
)
)),
div(
class = "table-container",
div(
class = "grid-table",
id = "my_grid",
div(
class = "grid-row",
div(class = "grid-cell grid-cell-text", "my_grid"),
div(id = "droppable_cell_1", class = "grid-cell droppable-cell", ""),
div(id = "droppable_cell_2", class = "grid-cell droppable-cell", ""),
div(id = "droppable_cell_3", class = "grid-cell droppable-cell", ""),
div(id = "droppable_cell_4", class = "grid-cell droppable-cell", ""),
div(id = "droppable_cell_5", class = "grid-cell droppable-cell", ""),
div(id = "droppable_cell_6", class = "grid-cell droppable-cell", ""),
div(id = "droppable_cell_7", class = "grid-cell droppable-cell", "")
)
),
orderInput('letters', 'Letters', items = LETTERS[1:7],
connect = connections) # defined above
)
)
server <- function(input, output, session) {
}
shinyApp(ui, server)
我正在尝试使用由actionButton触发的observeEvent来实现拖放功能。我的目标是实现向量的拖放,比如说 vec <- c(A, B, C), onto the my_grid table through a button click.
上下文:基本概念涉及在 my_grid 内的特定位置预选择和定位项目。需要注意的是,当项目移动到 my_grid 时,它们也应该从字母部分消失。
正如评论中所讨论的,我们为开头字母的放置定义了两个建议,例如这是你给的
connections <- paste0("droppable_cell_", 1:7) # id of the grid cells
vec_suggestion1 <- c("A", NA, "G", NA, "B", "C", "D")
vec_suggestion2 <- c("A", "B", "C", "D", "E", "F", "G")
df <- data.frame(
connections = connections,
vec_suggestion1 = vec_suggestion1,
vec_suggestion2 = vec_suggestion2
)
,我们想实现三个按钮。其中两个用于填充两个建议中给出的网格,其中之一应具有重置拖放的功能。此外,原始的拖放功能必须保持原样。这应该看起来像这样:
我们在这里使用
shinyjs
方法,为按钮添加一些自定义 JS
功能。我在下面解释了重要的变化,并在最后包含了完整的最小工作示例。
按钮像往常一样在
ui
内定义,例如
actionButton("btn_suggestion1", "Suggestion 1")
在服务器内部,我们使用
shinyjs::js$pageCol(df)
observeEvent(input$btn_suggestion1, {
shinyjs::disable("btn_suggestion1")
shinyjs::js$setSuggestion(1)
shinyjs::enable("btn_suggestion1")
})
根据您的要求,
observeEvent
由按钮触发,基本上会调用参数为1的函数setSuggestion
。1是df
中选项的列索引(因为JS
索引从0开始) )。函数定义在pageCol
内部,这是这里的重要部分。 pageCol
获取 df
作为参数并包含
var dataArray = Object.values(params[0]);
dataArray = dataArray[0].map((col, i) => dataArray.map(row => row[i]));
var cacheLetters = $('#letters').html();
var cacheGridCells = $('[id^=droppable_cell]').html();
dataArray
只是将 df
转换为 JS
,为了方便起见,我们将其转置。 cacheLetters
和cacheGridCells
用于保存字母和网格的原始状态(稍后用于重置按钮)。
setSuggestion
功能 shinyjs.setSuggestion = function (idxSuggestion) {
// loop over the array rows
$.each(dataArray, function (index, value) {
// define the selector for the grid cell using the first array column
var cellSelector = '#' + dataArray[index][0];
// define the new innerHTML of the grid cell such that it will
// contain the shinyjqui sortable element
var cellHTML = '<div data-value=\"'
+ dataArray[index][idxSuggestion]
+ '\" class=\"btn btn-default ui-sortable-handle\" style=\"margin: 1px;\" jqui_sortable_idx=\"letters__'
+ (index + 1).toString()
+ '\">'
+ dataArray[index][idxSuggestion]
+ '</div>';
// if the current value is na, next
if (dataArray[index][idxSuggestion] === null) {
return true;
}
// change the innerHTML of the grid cell such that it gets the letter attached
$(cellSelector).html(cellHTML);
// drop the current letter from the original list
$('#letters').find(`[data-value='${dataArray[index][idxSuggestion]}']`)[0].remove()
})
}
resetDnD
功能。 shinyjs.resetDnD = function (params){
$('#letters').html(cacheLetters).sortable('refresh');
$('[id^=droppable_cell]').html(cacheGridCells).sortable('refresh');
}
它只是使用元素的最初缓存的
HTML
来刷新字母和可放置的单元格。
这是完整的示例:
library(shiny)
library(shinyjqui)
library(shinyjs)
connections <- paste0("droppable_cell_", 1:7) # id of the grid cells
vec_suggestion1 <- c("A", NA, "G", NA, "B", "C", "D")
vec_suggestion2 <- c("A", "B", "C", "D", "E", "F", "G")
df <- data.frame(
connections = connections,
vec_suggestion1 = vec_suggestion1,
vec_suggestion2 = vec_suggestion2
)
js <- "shinyjs.pageCol = function(params){
$('[id^=droppable_cell]').sortable({
connectWith: '#letters',
drop: function(event, ui) {
$(this).append(ui.draggable);
}
})
var dataArray = Object.values(params[0]);
dataArray = dataArray[0].map((col, i) => dataArray.map(row => row[i]));
var cacheLetters = $('#letters').html();
var cacheGridCells = $('[id^=droppable_cell]').html();
shinyjs.setSuggestion = function (idxSuggestion) {
$.each(dataArray, function (index, value) {
var cellSelector = '#' + dataArray[index][0];
var cellHTML = '<div data-value=\"'
+ dataArray[index][idxSuggestion]
+ '\" class=\"btn btn-default ui-sortable-handle\" style=\"margin: 1px;\" jqui_sortable_idx=\"letters__'
+ (index + 1).toString()
+ '\">'
+ dataArray[index][idxSuggestion]
+ '</div>';
if (dataArray[index][idxSuggestion] === null) {
return true;
}
$(cellSelector).html(cellHTML);
$('#letters').find(`[data-value='${dataArray[index][idxSuggestion]}']`)[0].remove()
})
}
shinyjs.resetDnD = function (params){
$('#letters').html(cacheLetters).sortable('refresh');
$('[id^=droppable_cell]').html(cacheGridCells).sortable('refresh');
}
};
"
ui <- fluidPage(
useShinyjs(),
extendShinyjs(text = js, functions = c("pageCol", "resetDnD", "setSuggestion")),
tags$head(
# some styling
tags$style(
HTML(
"
.grid-table {
width: 150px;
border-collapse: collapse;
}
.grid-cell {
width: 100%;
height: 50px;
border: 1px solid black;
background-color: white;
text-align: center;
margin: 0;
padding: 5px;
}
.grid-cell-text {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
background-color: steelblue;
color: white;
font-size: 18px;
}
.droppable-cell {
background-color: lightgray;
}
.table-container {
display: flex;
position: absolute;
left: 400px;
top: 30px;
margin-top: 0px;
overflow: hidden;
}
#btn_suggestion1, #btn_suggestion2 {
background-color: lightblue;
}
#btn_resetDnD {
background-color: pink;
}
"
)
)),
actionButton("btn_suggestion1", "Suggestion 1"),
actionButton("btn_suggestion2", "Suggestion 2"),
actionButton("btn_resetDnD", "Reset Drag and Drop"),
div(
class = "table-container",
div(
class = "grid-table",
id = "my_grid",
div(
class = "grid-row",
div(class = "grid-cell grid-cell-text", "my_grid"),
div(id = "droppable_cell_1", class = "grid-cell droppable-cell", ""),
div(id = "droppable_cell_2", class = "grid-cell droppable-cell", ""),
div(id = "droppable_cell_3", class = "grid-cell droppable-cell", ""),
div(id = "droppable_cell_4", class = "grid-cell droppable-cell", ""),
div(id = "droppable_cell_5", class = "grid-cell droppable-cell", ""),
div(id = "droppable_cell_6", class = "grid-cell droppable-cell", ""),
div(id = "droppable_cell_7", class = "grid-cell droppable-cell", "")
)
),
orderInput('letters', 'Letters', items = LETTERS[1:7],
connect = connections) # defined above
)
)
server <- function(input, output, session) {
shinyjs::js$pageCol(df)
observeEvent(input$btn_suggestion1, {
shinyjs::disable("btn_suggestion1")
shinyjs::js$setSuggestion(1)
shinyjs::enable("btn_suggestion1")
})
observeEvent(input$btn_suggestion2, {
shinyjs::disable("btn_suggestion2")
shinyjs::js$setSuggestion(2)
shinyjs::enable("btn_suggestion2")
})
observeEvent(input$btn_resetDnD, {
shinyjs::disable("btn_resetDnD")
shinyjs::js$resetDnD()
shinyjs::enable("btn_resetDnD")
})
}
shinyApp(ui, server)