这不是关于使用renderUI创建模块。 有了我理解的renderUI,你在UI函数中放置一个占位符,然后在服务器函数中编写控件/小部件。
模块分为两部分。您必须使用callModule()将一部分添加到UI功能,另一部分添加到服务器功能。
我有一个滑块模块。我想在单击“添加”操作按钮时将其添加到wellpanel。如果有帮助,您可以在单击按钮时想到多次复制模块。重复模块应该都是独立的。
目视
我想知道一个动作按钮如何在服务器功能内的UI功能和服务器部分中添加模块的UI部分。
#Dynamically adding modules
library(shiny)
#slider module ------------------------
sliderUI <- function(id) {
ns <- NS(id)
sliderInput(ns("bins"), "Number of Bins:", min = 1, max = 5, value = 3)
}
slider <- function(input, output, session) {}
#shiny app ------------------------
ui <- fixedPage(
fixedRow(
column(width = 4, wellPanel(
h4("Slider Module"),
sliderUI("slider"),
actionButton("addSliderModule", "Add Slider Module"))
),
column(width = 4, wellPanel(
h4("Dynamic Loading Modules"),
p("Clicking on the 'Add' button on the left should add the module here. You should be able to duplicate that slider module as many times as the button is clicked"),
hr())
)
)
)
server <- function(input, output, session) {
observeEvent(input$addSliderModule, {
#what goes here
})
}
shinyApp(ui, server)
上发布
答案 0 :(得分:3)
好的,这是你的解决方案。我很高兴我找到了一个,因为它花了我几个小时。
基本上,如果你想从零开始添加一个模块(没有渲染函数),它必须通过JavaScript。这有三个步骤:
如果你从Shiny打电话给script
,这三个都是为你完成的。但没有它,我们必须独自完成这些事情。好的,如果你知道怎么做,那就不那么难了。
我的代码的重要部分发生在sliderUI
内。在那里我创建了元素(之前在函数ionRangeSlider
中尝试过的),然后调用Shiny.unbindAll() / Shiny.bindAll()
,使其看起来像一个真正的滑块,最后,input
创建一个绑定相应的library(shiny)
ui <- fixedPage(
fixedRow(
column(width = 4, wellPanel(
h4("Slider Module"),
tags$div(
sliderInput("slider-bins", "Number of Bins:", min = 1, max = 5, value = 3)
),
actionButton("addSliderModule", "Add Slider Module"))
),
column(width = 4, wellPanel(id = "target",
h4("Dynamic Loading Modules"),
p("Clicking on the 'Add' button on the left should add the module here. You should be able to duplicate that slider module as many times as the button is clicked"),
hr(),
tags$script('
Shiny.addCustomMessageHandler("createSlider",
function(ID) {
Shiny.unbindAll();
var targetContainer = document.getElementById("target");
var container = document.createElement("div");
container.setAttribute("class", "form-group shiny-input-container");
var label = document.createElement("label");
label.setAttribute("class", "control-label");
label.setAttribute("for", "ID");
var labelText = document.createTextNode("Number of Bins");
label.appendChild(labelText);
container.appendChild(label);
var input = document.createElement("input");
input.setAttribute("class", "js-range-slider");
input.setAttribute("id", ID);
input.setAttribute("data-min", "1");
input.setAttribute("data-max", "5");
input.setAttribute("data-from", "3");
input.setAttribute("data-step", "1");
input.setAttribute("data-grid", "true");
input.setAttribute("data-grid-num", "4");
input.setAttribute("data-grid-snap", "false");
input.setAttribute("data-prettify-separator", ",");
input.setAttribute("data-keyboard", "true");
input.setAttribute("data-keyboard-step", "25");
input.setAttribute("data-drag-interval", "true");
input.setAttribute("data-data-type", "number");
container.appendChild(input);
targetContainer.appendChild(container);
$("#" + ID).ionRangeSlider();
Shiny.bindAll();
}
);'
)
)),
column(width = 4, wellPanel(
uiOutput("response")
))
)
)
server <- function(input, output, session) {
observeEvent(input$addSliderModule, {
session$sendCustomMessage(type = "createSlider", message = paste0("slider-", input$addSliderModule))
})
output$response <- renderUI({
if(input$addSliderModule >0){
lapply(1:input$addSliderModule, function(x){
output[[paste("response", x)]] <- renderText({paste("Value of slider", x, ":", input[[paste0("slider-", x)]])})
textOutput(paste("response", x))
})
}
})
}
runApp(shinyApp(ui, server))
变量。
其他新增内容仅供参考。
享受!
代码:
<Input i_IISSITES>
Module im_file
File "C:\Logs\u_ex*"
SavePos TRUE
Recursive TRUE
InputType LineBased
Exec $Hostname = 'stg-01-iom';
Exec if $raw_event =~ /^#/ drop(); \
else \
{ \
w3c->parse_csv(); \
$SourceName = "IIS"; \
$EventTime = parsedate($date + " " + $time); \
$Message = to_json(); \
}
</Input>
<Output o_PLAINTEXT>
Module om_udp
Host 10.50.108.32
Port 5555
</Output>
<Route r_IIS>
Path i_IISSITES => o_PLAINTEXT
</Route>
答案 1 :(得分:1)
好的,我有一个部分解决方案只复制模块一次。我们的想法是在actionButton观察者事件中添加模块UI和CallModule代码。
看起来您必须手动创建x uiOutput()占位符以复制模块x次。
我尝试动态添加另一个uiOutput()inideide renderUI(),但这不起作用。
这是将其复制一次的代码。
#Dynamically adding modules
library(shiny)
#slider module ------------------------
sliderUI <- function(id) {
ns <- NS(id)
tagList(
sliderInput(ns("bins"), "Number of Bins:", min = 1, max = 5, value = 3),
textOutput(ns("textBins"))
)
}
slider <- function(input, output, session) {
output$textBins <- renderText({
input$bins
})
}
#shiny app ------------------------
ui <- fixedPage(
fixedRow(
column(width = 4, wellPanel(
h4("Slider Module"),
sliderUI("originalSlider"),
actionButton("addSliderModule", "Add Slider Module"))
),
column(width = 4, wellPanel(
h4("Dynamic Loading Modules"),
p("Clicking on the 'Add' button on the left should add the module here. You should be able to duplicate that slider module as many times as the button is clicked"),
hr(),
uiOutput("addModule"))
)
)
)
server <- function(input, output, session) {
#server code for the original module
callModule(slider, "originalSlider")
#Here we add the UI and callModule of the duplicate module
observeEvent(input$addSliderModule, {
duplicateSliderid <- paste0("duplicateSlider", input$addSliderModule)
output$addModule <- renderUI({
sliderUI(duplicateSliderid)
})
callModule(slider, duplicateSliderid)
})
}
shinyApp(ui, server)
答案 2 :(得分:1)
另一个答案延伸, MySchizoBuddy 一直在做什么。它也可能不完全令人满意,但它确实有效。
我添加了一个脚本,只是将所有元素从动态创建者移动到目标div。这样,动态创建元素不会擦除之前创建的元素。
#Dynamically adding modules
library(shiny)
#slider module ------------------------
sliderUI <- function(id) {
ns <- NS(id)
tagList(
sliderInput(ns("bins"), "Number of Bins:", min = 1, max = 5, value = 3),
textOutput(ns("textBins"))
)
}
slider <- function(input, output, session) {
output$textBins <- renderText({
input$bins
})
}
#shiny app ------------------------
ui <- fixedPage(
fixedRow(
column(width = 4, wellPanel(
h4("Slider Module"),
sliderUI("originalSlider"),
actionButton("addSliderModule", "Add Slider Module"))
),
column(width = 4, wellPanel(
h4("Dynamic Loading Modules"),
p("Clicking on the 'Add' button on the left should add the module here. You should be able to duplicate that slider module as many times as the button is clicked"),
hr(),
tags$script(HTML('
Shiny.addCustomMessageHandler("moveModule", function(message) {
var source = document.getElementById("addModule").childNodes;
var target = document.getElementById("target");
for (var i = 0; i < source.length; i++) {
target.appendChild(source[i]);
}
})
')),
tags$div(id = "target"),
uiOutput("addModule"))
)
)
)
server <- function(input, output, session) {
#server code for the original module
callModule(slider, "originalSlider")
#Here we add the UI and callModule of the duplicate module
observeEvent(input$addSliderModule, {
session$sendCustomMessage(type = "moveModule", message = "Something")
duplicateSliderid <- paste0("duplicateSlider", input$addSliderModule)
output$addModule <- renderUI({
sliderUI(duplicateSliderid)
})
callModule(slider, duplicateSliderid)
})
}
shinyApp(ui, server)
答案 3 :(得分:0)
我认为您会发现此解决方案更为通用。首先,它使用InsertUI代替JavaScript(自上次响应以来已引入InsertUI)。但是,我还没有找到任何人在以后的其他反应式代码中介绍如何使用callModule产生的相应对象。请注意,根据您的目标,renderText内的部分可能需要做的非常不同(例如,使用for语句)
# user interface module----
numberInput = function(id, label = "Numeric input"){
ns = NS(id)
numericInput(ns("term"), label, value = 0)
}
#Module server logic
number = function(input, output, session){
#just returns the expression for a reactive containing whatever you want (the relevant numericInput in this case)
num_out = reactive({input$term})
return(num_out)
}
# User interface ----
ui = fluidPage(
titlePanel("Inserting UI and Callable Reactive using Modules"),
actionButton('insertBtn', 'Insert module'),
textOutput("total")
)
# Server logic
server = function(input, output, session) {
num_values = reactiveValues()# this is basically a list that can store reactive expressions
observeEvent(ignoreNULL = FALSE, #simple way of running module initially by allowing to run when button is at 0
input$insertBtn, {
btn = as.character(input$insertBtn + 1)#so first module will be labeled #1
insertUI(
selector = "#insertBtn",
where = "afterEnd",
ui = numberInput(btn,paste0('term #', btn))
)
num_values[[btn]] = callModule(number, btn)#stores the reactive expression from the call of the module related to the input inserted in a corresponding element of num_Values
})
output$total = renderText({
num_vector = sapply(num_values, function(num_out){num_out()}) #calls each reactive expression in num_values (defined in the module) to get each input$term
sum(num_vector) #sums all the numericInputs
})
}
# Run the app
shinyApp(ui, server)