Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple event handlers on single loadingButton #71

Open
bartekch opened this issue Jan 31, 2023 · 0 comments
Open

Multiple event handlers on single loadingButton #71

bartekch opened this issue Jan 31, 2023 · 0 comments

Comments

@bartekch
Copy link

I bumped into this when investigating #69. When creating loadingButton with already existing inputId, it is correctly removed from buttons array, but it looks like click event handlers are accumulated. I added some logs to check this, bartekch@d7878b8.

remotes::install_github("bartekch/shinyFeedback", "d7878b8b45959bf65ce4de8c05df5a6f86ad87b7")

library("shiny")

shinyApp(
  ui = basicPage(
    shinyFeedback::useShinyFeedback(),
    actionButton("rerender", "Rerender button"),
    uiOutput("button"),
    verbatimTextOutput("b_val"),
    verbatimTextOutput("val")
  ),
  server = function(input, output, session) {
    output$button <- renderUI({
      input$rerender
      shinyFeedback::loadingButton("b", "loadingbutton")
    })

    output$b_val <- renderPrint(input$b)
    val <- eventReactive(input$b, {
      shinyFeedback::resetLoadingButton("b")
      rnorm(1)
    })
    output$val <- renderPrint(val())
  }
)

After a few clicks and renders console output looks like this.
image

To be honest I didn't find any harmful effect on the actual Shiny application, however it still doesn't seem to be correct.

One simple way to fix this is to add $(document).off('click', "#" + inputId); before adding new listener. However this would remove all click events handlers, which may be undesired (or maybe this is not a problem?). To fix this we could pass handler to buttons array, so later we could remove an exact handler when an existing id is encountered.

  click_button = function() {
    // increment the button value by 1.  This is consistent with how `shiny::actionButton`
    // value works.
    console.log("Click button " + id + " with value ", btn_value);

    if (btn_value === null) {
      btn_value = 1;
    } else {
      btn_value = btn_value + 1;
    }
    Shiny.setInputValue(inputId, btn_value);

    var loading_button = $(this);

    loading_button.attr('disabled', true);
    loading_button.html('<i class="fas fa-' + options.loadingSpinner + ' fa-spin"></i> ' + options.loadingLabel);
    loading_button.attr('style', options.loadingStyle);
    loading_button.removeClass(options["class"]);
    loading_button.addClass(options.loadingClass);
  };
  
  $(function() {
    var allDOMLoadingButtons = $(document).find(".sf-loading-button");
    var loadingIds = [];
    for(var obj of allDOMLoadingButtons) {
      loadingIds.push(obj.id);
    }
    
    // if element in this.buttons represents a loadingButton that is no longer in the DOM
    // then remove it from this.buttons.  Also remove remove it if the button being added already
    // exists in this.buttons
    self.buttons = self.buttons.filter(obj => {
      if (obj.inputId == inputId) {
        $(document).off('click', "#" + inputId, obj.click_handler);
      };
      return loadingIds.includes("sf-loading-button-" + obj.inputId) && (obj.inputId !== inputId);
    });  
  
    self.buttons.push({inputId: inputId, options: options, click_handler: click_button}); 
  });
  
  // Disable button & change text
  $(document).on('click', "#" + inputId, click_button);

I'm not JS expert, so probably it could be done better. Anyway, I've made a draft pull request with my suggestions: #70. There are still some console.log calls there, I'd be happy to clean it after your suggestions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant