2015-01-12 25 views
1

我正在写一个Shinyapp,使用户能够将新条目输入到MongoDB中,并从中删除特定的行。为什么我使用不同的actionLink后,我的Shiny(R)actionButton没有响应?

我想添加一个功能,可以通过保存行的临时副本来撤消上次删除。它似乎工作正常,但在使用撤消之后,出于某种原因,删除按钮不起作用了,我不知道为什么。

我想也许它有一些事实,有一些其他地方,我使用观察员的两个按钮,但我不明白为什么会导致任何问题(我需要他们的应用程序以正常工作) - 无论如何,他们不会阻止我逐一删除多行,只要我不使用undo功能。你可以从下面的代码中看到,我已经在其中加入了一堆print()函数来试图找出它的前进方向。奇怪的是 - 他们都没有出现!就好像删除按钮根本不会在撤消使用后激活脚本。任何想法为什么?

UPDATE:下面是重现问题(不使用的MongoDB)server.R和ui.R短版:

server.R

tempEntry<-NULL 
shinyServer(function(input, output, session) { 
    dat<-data.frame(nums=1:3,ltrs=c("a","b","c")) 
    ## Action: Delete entry 
    output$delError<-renderText({ 
     input$delButton 
     isolate({if (!is.na(input$delNum)) { 
      tempEntry<<-dat[input$delNum,] 
      output$undo<<-renderUI({ 
       actionLink("undo","Undo last delete") 
       }) 
      dat<<-dat[-input$delNum,] 
      print("deleted") 
      print(dat) 
     } else print("nope2") 
     }) 
    }) 

    ## Action: Undo delete 
    output$undoError<-renderText({ 
     input$undo 
     if (!is.null(input$undo)) { 
     if (input$undo>0) { 
     isolate({if (!is.null(tempEntry)) { 
      dat<<-rbind(dat,tempEntry) 
      tempEntry<<-NULL 
      output$delError<<-renderText({""}) 
      print(dat) 
     } else print("nope3") 
     }) } else print("undo==0") } else print("undo null") 
    }) 
}) 

ui.R:

library(shiny) 
shinyUI(navbarPage("example", 
        tabPanel("moo", 
        titlePanel(""), 
        fluidPage(numericInput("delNum","Row to delete",value=NULL), 
          actionButton("delButton","Delete row"), 
          uiOutput("undo"), 
          div(p(textOutput("delError")),style="color:red"), 
          div(p(textOutput("undoError")),style="color:blue") 
          ))))   

(这也给出了一个错误“参数1(类型'列表')不能由'猫'处理删除一行后,我不知道为什么......但问题不是似乎与此有关)。

谢谢!

+1

你可以给为重现此问题尽可能小的'server.R'和'ui.R'文件? –

+0

嗨Marat,感谢评论。我编辑了我的问题,以包含一个短版本的server.R和ui.R,它重现了这个问题。 – doviod

回答

0

发生这种情况的原因是由于output$delError<<-renderText({""})代码覆盖原来的空白表达式output$delError,因此output$delError不会在input$delButton上再次触发。


[更新]

的OP的应用程序使用actionButtonactionLink从数据库中删除分别取消删除和记录。 '删除'按钮应该触发delError表达式,删除记录并显示删除的结果(例如'记录已删除')。同样,“取消删除”按钮会触发undoError表达式,该记录会将记录放回表中并报告取消删除的结果(例如,'记录未删除')。问题是,undoError必须摆脱由delError产生的输出,因为输出'记录删除'和'记录未删除'在它们一起出现时没有太大意义,但输出'删除记录'只能通过delError的表达。

似乎可以通过修改delError来解决此问题,以便在按下“取消删除”按钮(或链接)时隐藏其输出。但在这种情况下,delError会在'删除'和'取消删除'按钮上触发,而不能说出哪个按钮导致评估,所以当按下'取消删除'按钮时它会尝试删除记录!

下面的示例应用程序提供了一种通过使用存储最后一个操作的状态的全局变量来解决此问题的方法。这种状态是由两个高优先级的观察者(一个用于“删除”,另一个用于“取消删除”)生成的,它还负责实际删除/删除记录。观察者不会产生直接进入网页的输出,所以没有摆脱其他观察者产生的消息的麻烦。相反,状态变量通过简单的反应式表达式显示。

server.R

tempEntry<-NULL 
dat<-data.frame(nums=1:3,ltrs=c("a","b","c")) 


shinyServer(function(input, output, session) { 

    del.status <- NULL 


    ################## 
    ### Observers #### 
    ################## 

    delete.row <- observe({ 
     if (input$delButton ==0) return() # we don't want to delete anything at start 

     delNum <- isolate(input$delNum) # this is the only thing that needs to be isolated 
     if (is.na(delNum)) { 
      print('nope2') 
      return() 
     } 

     tempEntry <<- dat[delNum,] 
     dat <<- dat[-delNum,] 

     output$undo <<- renderUI(actionLink("undo","Undo last delete")) 
     del.status <<- 'deleted' 
    },priority=100) # make sure that del.status will be updated *before* the evaluation of output$delError 



    undelete.row <- observe({ 
     if (is.null(input$undo) || input$undo==0) return() # trigger on undowe don't want to undelete anything at the beginning of the script 

     dat <<- rbind(dat,tempEntry) 
     tempEntry <<- NULL 

     output$undo <<- renderUI("") 
     del.status <<- 'undeleted' 
    },priority=100) 



    ################## 
    ### Renderers #### 
    ################## 

    output$delError <- renderText({ 
     if (input$delButton == 0) return() # show nothing until first deletion 
     input$undo       # trigger on undo 

     return(del.status) 
    }) 

    output$show.table <- renderTable({ 
     input$delButton; input$undo  # trigger on delete/undelete buttons 
     return(dat) 
    }) 

}) 

ui.R

library(shiny) 
shinyUI(
    navbarPage(
     "example" 
     , tabPanel("moo" 
     , titlePanel("") 
     , fluidPage(
      numericInput("delNum","Row to delete",value=NULL) 
      , div(p(textOutput("delError")),style="color:red") 
      , actionButton("delButton","Delete row") 
      , uiOutput("undo") 
      , tableOutput('show.table') 
      ) 
     ) 
    ) 
) 
+0

我认为任何包含被激活的无功元素的声明都会被触发。毕竟 - 输出$ delError以NULL开始,并且在我调用输入$ delButton之前没有任何东西... 如何实现我的目标(一旦发生撤消操作就从delError中移除消息)而不会导致这个? – doviod

+0

@dovoid,'output $ delError' *在开始时返回*'NULL',但它可以触发'input $ delButton'并返回不同的东西。在输出$ delError << - renderText({“”})后,它自己变成NULL,因此不能再对输入$ delButton做出反应。关于你从delError中删除消息的问题 - 我需要考虑一下... –

+0

但是等待,我没有传递NULL,我将它传递给了rendertext({“”})。我在其他多个地方都没有问题。我可以使_return_ NULL没有**使它** NULL? – doviod

相关问题