如何配合shinyjs包使用Shiny.setInputValue()?
问题描述
在Chrome开发者工具中运行JavaScript代码片段时,可以在Shiny应用运行过程中使用Shiny.setInputValue('input',0)重置actionButton的值,仅需这一行代码即可正常生效。
需求是在应用内部结合shinyjs包实现该功能,已经正确配置shinyjs,应用内其他shinyjs功能均可正常使用。
编写的自定义JS函数如下:
shinyjs.zeroInput = function(inputID) { Shiny.setInputValue(inputID, 0); };
设置按钮A,点击按钮A时将按钮B的值重置为0,对应R端代码:
observeEvent(input$mybuttonA, { shinyjs::js$zeroInput("mybuttonB") })
上述代码运行失败,点击按钮A时Chrome JavaScript控制台会抛出引用错误,但直接在控制台运行Shiny.setInputValue("mybuttonB",0)可以正常生效。
原因说明
问题出在JS作用域差异:
- 控制台执行代码默认在全局
window作用域下,Shiny初始化完成后会将Shiny对象挂载到window对象上,因此可以直接调用Shiny.setInputValue。 - shinyjs执行自定义注册函数时,运行在自身的闭包作用域内,不会默认将全局作用域的
Shiny对象透传到函数内部,执行时找不到Shiny对象就会抛出引用错误。
另外存在一个易忽略的兼容问题:Shiny.setInputValue默认会比对新旧输入值,如果新值和当前存储值完全一致,不会触发R端的反应式更新,重置按钮值的场景下需要手动指定事件优先级,保证重复赋值为0时也能正常触发更新。
修复方法
直接修改自定义JS函数,显式从全局window对象获取Shiny实例,同时补充第三个优先级参数即可:
shinyjs.zeroInput = function(inputID) { window.Shiny.setInputValue(inputID, 0, {priority: "event"}); };
如果修改后仍存在加载顺序相关问题,改用shinyjs官方推荐的extendShinyjs方式注册自定义函数即可,该方式会自动处理Shiny就绪判断和作用域隔离问题:
- 在应用www目录下新建
custom.js文件,写入以下代码:
shinyjs.init = function() { shinyjs.zeroInput = function(inputID) { Shiny.setInputValue(inputID, 0, {priority: "event"}); } }
- 在R端UI部分正式注册shinyjs扩展:
library(shinyjs) ui <- fluidPage( useShinyjs(), extendShinyjs(script = "custom.js"), # 其余UI组件代码 )
这种写法会等shinyjs和Shiny前端依赖全部初始化完成后再注册自定义函数,不会出现作用域或加载顺序问题。
内容的提问来源于stack exchange,提问作者Adrarc
相关产品推荐
相关产品推荐

