1
votes

My Shiny application allows the user to create/delete inputs dynamically.

I then loop over these inputs to get the values (eg. val1 <- input[["input_for_val1"]]).

My problem is that values from deleted inputs remain in the shiny 'input' list.

I have tried removing the html widgets using removeUI or javascript (plus unbindAll/bindAll) but it does not help, I guess because once the value is in the 'input' list, it stays there until something on the UI updates it.

I also tried to edit the 'input' list itself (on the server side) but I get an error because it is readonly.

Any idea on how to clean the 'input' list from deleted shiny input widgets ?

Here is the code of a small project to illustrate the problem:

ui.R

library(shiny)

# Define UI for dataset viewer application
shinyUI(fluidPage(

  # Javascript to handle the add/remove action of inputs
  tags$head(tags$script(src="script.js")),

  # Container where the script adds the dynamic inputs
  tags$div(id = "container_for_dynamic_inputs"),

  # 'Add' button
  tags$button(onclick="addNewInputText()",
              class = "btn btn-default",
              "Add input"),

  # 'Remove' button
  tags$button(onclick="removeLastInputText()",
              class = "btn btn-default",
              "Remove input"),

  # Keeps tracks of the number of inputs (see server.R) 
  verbatimTextOutput("summary")

  )
)

www/script.js

var number_of_dynamic_inputs = 0;

var addNewInputText = function () {
  console.log("addNewInputText");

  var container_elt = document.getElementById("container_for_dynamic_inputs");

  Shiny.unbindAll(container_elt);

  var new_input = document.createElement("input");
  var id = "input_" + number_of_dynamic_inputs++;
  new_input.setAttribute("id", id);
  new_input.setAttribute("name", id);
  new_input.setAttribute("type", "text");
  new_input.setAttribute("value", id);

  container_elt.append(new_input);

  Shiny.bindAll(container_elt);

}


var removeLastInputText = function () {

  var container_elt = document.getElementById("container_for_dynamic_inputs");

  Shiny.unbindAll(container_elt);

  number_of_dynamic_inputs--;
  var id = "input_" + number_of_dynamic_inputs ;

  console.log("removeLastInputText: ", id);

  var elementToRemove = document.getElementById(id);

  container_elt.removeChild(elementToRemove);

  Shiny.bindAll(container_elt);

}

server.R

library(shiny)

shinyServer(function(input, output) {

  output$summary <- renderPrint({
    for (i in names(input)) {
      print(input[[i]])
    } 
  })

})
1
I also tried using shinyjs function 'reset', with no better resulttencnivel
can you provide a better example with code which can be run pleasePork Chop
@PorkChop: I've added the code of a project to illustrate the problemtencnivel

1 Answers

0
votes

The documentation on htmlwidgets has improved since the last time I checked. These is especially a very useful post from deanattali.

http://www.htmlwidgets.org/develop_intro.html http://deanattali.com/blog/htmlwidgets-tips/#widget-to-r-data

So my workaround is to use a custom widget using htmlwidgets. The widget manages the creation/deletion of input fields and send the inputs as one json message to the server side. For Shiny, this means that there is only one input...no more problem.