How to avoid duplicate button clicks inside Template.myTemplate.events?

I can disable the following button from the console via $("#myButton").prop('disabled', true);
However, when I do this in Template.myTemplate.events it does not work:

<template name = "myTemplate">
    <button id="myButton"></button>
</template>

I am now using Session variables, because in my case it makes sense to disable all buttons when one is clicked (dont want other user interactions while one action is performing) - but I am not sure if this a good approach:

Template.myTemplate.events({
  'click #myButton': function (event, instance) {
     $("#myButton").prop('disabled', true); //why does this not work?
     event.preventDefault();
    //Do my stuff and enable button click again
}
<template name = "myTemplate">
    <button id="myButton" {{buttonStateDisabled}} ></button>
</template>
Template.registerHelper("buttonStateDisabled", function() {
    if(Session.get("buttonStateDisabled")==true){
        setTimeout(function(){
            //safety net: after 2 seconds enable button again...
            Session.set("buttonStateDisabled", false);
        }, 2000);

        return "disabled";
    }
    else {
        return "";
    }
});
1 Like

your template wouldn’t work this way because Spacebars/Blaze treats “disabled” (and other standard attributes) in a special way.
here’s how it should be:

<button id="myButton" disabled={{buttonStateDisabled}}></button>

Now, I’d advise against 2 points here:

  1. don’t use Session variables for something that is well contained within a template
  2. don’t use helpers to mutate state (i.e. your setTimeout callback), especially in the case where multiple elements use the same helper. this would redundantly trigger your timeout callback
Template.myTemplate.onCreated(function() {
   this.buttonStateDisabled = new ReactiveVar(false);
});

Template.myTemplate.helpers({

    buttonStateDisabled: function() { return Template.instance().buttonStateDisabled.get(); }

});

Template.myTemplate.events({
   
'click #myButton': function(e, instance) {

      instance.buttonStateDisabled.set(true);
      setTimeout(function() { instance.buttonDisabled.set(false); }, 2000);
   }
});

3 Likes

It should works. Spacebars (Blaze) affects properties that have been defined for templates. In a Blaze documentation written that Blaze do not touch changes have been maden by the hand (or with jQuery) - it means Blaze can’t override or clear disabled attribute.
I use such way too and it works as expected. Next I guess $("#myButton").prop('disabled', true) doesnt works. You could try this one

Template.myTemplate.events({
  'click #myButton': function (event, instance) {
     $(event.currentTarget).prop('disabled', true); 
}
1 Like

Same basic idea as @chenroth, but different UI. Instead of disabling the button like this

You could instead throw up a spinner like this:

{{#spinnerIf buttonStateDisabled}}
<button id="myButton"></button>
{{/spinnerIf}}

Internals of spinnerIf below

<template name="spinnerIf">
  {{#if this}}
    <img src="/files/images/loader2.gif"/>
  {{else}}
    {{> UI.contentBlock}}
  {{/if}}
</template>