r - updateNumericInput not updating from reactiveValues
问题描述
I think I have run into some strange scoping issue that I have fought with for a week now without understanding what is going on. I have also been unable to really make a small example that have the same problem but I hope the symptoms ring some bells. The real code is also available but the app is pretty complex.
Let me explain the players in the code.
A number of inputs in a
bsModal
, mainlynumericInput
.An
observeEvent
, lets call it "the reader", fires when a file is read that contains cached results. It updates areactiveValues
object that contains the equivalent of all the inputs in a special S4 object.Then we have an
observe
, lets call it "the object creator" that takes all the inputs and updates the reactiveValues` object if any inputs are changed.an
observeEvent
, lets call it "the input updater", that fires when thereactiveValues
reactive is invalidated and should update all the inputs. This is done to allow other processes to change the inputs by changing thereactiveValues
reactive (for example "the object creator"). The first functionality I need is simply that it updates the inputs when the cached results are read by the "the object creator".
So it should go:
"the reader" reads a file --> "the input updater" sees a new reactiveValues
reactive and updates the inputs (--> the "the object creator" sees new inputs and re-writes the reactiveValues
reactive but they should be what the "the reader" already set).
The issue I have is in the "the input updater". I cannot get it to update the input based on the reactiveValues
.
The code looks like this:
observeEvent(settings$processing_local, {
cat("\n\n\n")
print("Modifying inputs")
print(paste0("before ppm input is: ", input$local_ppm))
set <- ppm(settings$processing_local) # THIS DOES NOT WORK
print(paste0("setting: ", set)) # SHOWS CORRECT VALUE
# set <- 1000 # THIS WORKS!
updateNumericInput(session,"local_ppm",value = set)
print(paste0("after ppm input is: ", input$local_ppm))
cat("\n\n\n")
}, priority = 2)
When set
is based on the reactiveValues
settings$processing_local
then the update doesn't happen. The crazy thing is that the output of print
does show the right value AND if I hardcode a value to set
then it also works.
The full code for 1, 2, 3 and 4.
EDIT 1: Version of the relevant processes based on the example of @cuttlefish44 This is closer to my action app but unfortunately does not have the problem I am experiencing in the full app.
ui <- fluidPage(
numericInput("inNumber", "Input number", 0),
actionButton("but", "Update")
)
server <- function(input, output, session) {
settings <- reactiveValues(aaa = NULL)
# proxy for reading cached file
observeEvent(input$but, {
settings$aaa <- 30
})
observe({
settings$aaa <- input$inNumber
}, priority = 1)
observeEvent(settings$aaa, {
set <- settings$aaa
print(c(set, input$inNumber))
updateNumericInput(session, "inNumber", value = set)
print(c(set, input$inNumber))
}, priority = 2)
}
shinyApp(ui, server)
EDIT 2: In lieu of a working example of the issue I have dockerized my app so it should be possible to see the issue albeit annoying to do. Dockerized app here.
Can be build with docker build --tag mscurate .
and run with docker run --publish 8000:3838 mscurate
.
After starting the app the issue can be seen by:
- click "Load"
- Select the one available file
- click "local settings"
- Now the "ppm" value in the loaded data is 500. But the input was never updated and the reactive is then changed back to the default value of 100.
The logging shows the sequence of events when loading the file:
-------Loading started-------
before the reactive is:
settings not present
after the reactive is:
500
-------Loading finished-------
-------Modifying inputs-------
before ppm input is: 100
setting: 500
after ppm input is: 100 <---- @cuttlefish44's answer explains why this is not updated
--------------
-------updating reactive objects-------
before ppm input is: 100 <---- this should have been updated to 500!
before the reactive object is: 500
after ppm input is: 100
after the reactive object is: 100
--------------
-------Modifying inputs-------
before ppm input is: 100
setting: 100
after ppm input is: 100
--------------
-------updating reactive objects-------
before ppm input is: 100
before the reactive object is: 100
after ppm input is: 100
after the reactive object is: 100
--------------
-------updating reactive objects-------
before ppm input is: 100
before the reactive object is: 100
after ppm input is: 100
after the reactive object is: 100
--------------
解决方案
我认为这里的问题是“对象创建者”对 RVs 具有反应性依赖,导致当“阅读器”更新 RVs 时,它在与“输入更新器”相同的周期内失效。input
然后在“输入更新器”的更新发生在下一个周期之前,这些设置被旧值覆盖。
我对逐个播放演练的解释如下所示:
- 阅读器更新设置,使对象创建者和输入更新器无效。
- 新的评估周期开始。
- 输入更新器发送消息以根据新设置更新输入,但输入对象中的值尚未更改。
- 对象创建者根据旧输入更新设置,使设置无效,从而使输入更新程序和对象创建者本身无效。
- 输入更新器发送另一条消息来更新输入,这一次基于对象创建者刚刚设置的旧设置。
- 对象创建者再次更新设置,仍然基于旧输入。Invalidaiton 不会被触发,因为值没有改变。
- 所有输出都准备就绪,评估结束,会话处于休息状态。
- 输入更新器发送的更新消息到达;只注意到后者,它将输入更改为旧值。
- 对象创建器运行并将设置设置为旧值。同样,不会触发设置失效,因为值没有改变。
- 评估再次结束,这次没有待处理的输入消息。
要解决此问题,请从“对象创建者”中删除 RV 依赖项,例如使用
isolate()
. 我无法req()
使用isolate()
,但在这种情况下,您可以完全放弃它。
这是该问题的一个最小示例。删除req()
此处修复它:
library(shiny)
lgr <- list(debug = function(...) cat(sprintf(...), "\n"))
ui <- fluidPage(
sliderInput("file_number", "Number to \"read from file\"", 0, 10, 5),
actionButton("read", "Read"),
numericInput("number", "Input number to sync", 0)
)
server <- function(input, output, session) {
settings <- reactiveValues(number = NULL)
observeEvent(input$read, {
settings$number <- input$file_number
lgr$debug("Loaded settings from \"file\".")
}, label = "reader")
observe({
req(settings$number) # The dependency on settings
settings$number <- input$number
lgr$debug("Updated settings from input.")
}, priority = 1, label = "object-creator")
observeEvent(settings$number, {
updateNumericInput(session, "number", value = settings$number)
lgr$debug("Set input from settings: %d", settings$number)
}, priority = 2, label = "input-updater")
}
shinyApp(ui, server)
以及点击“阅读”后产生的日志:
Loaded settings from "file".
Set input from settings: 5
Updated settings from input.
Set input from settings: 0
Updated settings from input.
Updated settings from input.
您可以使用reactlog很好地了解该过程:
reactlog::reactlog_enable()
reactlogReset()
shinyApp(ui, server)
reactlogShow()
推荐阅读
- c# - 如何恢复包 Visual Studio 2017
- javascript - 从我自己的 WebHosting 服务器读取多个 JSON 文件并构建几个Html 中的结构以及 Javascript 中读取的信息
- java - 无法让 Jgrid 中的 JPanel 立即对更改做出反应
- python - 在 python 中结束一个线程(也使用回调)
- python - 如何实现密钥检查定义
- python-3.x - 神经网络成本不低于某个值
- node.js - 启用 CORS 时 Express 服务器没有响应
- python - 将多个键:值对添加到 DynamoDB 到现有地图?
- javascript - 如何使用 React 在 handleChange 上构建嵌套对象?
- excel - 基于变量从范围复制行