2

There is the knockout-3.3.0 & jquery-1.11.2 & bootstrap-3 application.

The template with click binding:

<div class="modal-footer">
    <button type="button" class="btn btn-primary" data-bind="click: $parent.Submit, text: 'Submit'"></button>
</div>

The viewmodel contains handler:

self.Submit = function (data, event) {
    console.log('fired');
    /* do some very important staff */
};

If I clicked on Submit button then the event fires once. But if I pressed and held Enter key and clicked on Submit button helding the Enter key being pressed then the event fires from 10 to 20 times.

There is an option to modify the handler like this:

self.isSubmitting = ko.observable(false);
self.Submit = function (data, event) {
    if (self.isSubmitting()) {
        return;
    }

    console.log('fired');
    self.isSubmitting(true);

    /* do some very important staff */

    self.isSubmitting(false);
};

But I'd prefer some more general solution instead of modifying each click handler in the application.

So, what do you think? Thank you in advance!

Edit: The problem is fosus on the button after it was clicked. Modifying the event binding is not the option because this behaviour is correct. That's why the solution is to modify the handler to avoid unwanted execusion using isSubmitting boolean variable.

Enam
  • 1,268
  • 1
  • 9
  • 16
  • 1
    keypress fires multiple times so that is what happens. No different than people who double click on a button. So you would have same issue when someone double clicks... – epascarello Oct 26 '18 at 14:53
  • I have 'click' handler and no 'keypress' handlers. In console there are multiple logs for click handler and each time the event has type 'click'. Actually, double click doesn't fire the event twice or more. – Enam Oct 26 '18 at 14:59
  • 1
    Not sure what browser you are using that 2 clicks does not fire two click events. And enter key fires click, so does space bar. – epascarello Oct 26 '18 at 15:04
  • I have modal with a couple of buttons. Neither 'enter' nor 'space bar' fires the 'click' event. About the 'double click' you were right. I didn't get it cuz my modal closes too fast. I use latest Chrome. – Enam Oct 26 '18 at 15:08
  • wait.... your question says enter key is firing the event too many times but the last comment says it does not fire the click event.... lol – epascarello Oct 26 '18 at 15:19
  • Enter key press itself doesn't fire any event. But in case of holding the Enter key pressed while clicking on the button the event is fired multiple times. See? Press Enter key and don't release it, keep the Enter key being pressed. Then click on the button. After a while release the Enter key. While the Enter key was being pressed the event have been fired multiple times. – Enam Oct 26 '18 at 15:33
  • 1
    https://jsfiddle.net/bq1wg3p6/ <-- If the button is focused, enter and space will fire click. That is how you can enter data into a form without the need for a mouse. Focus a link, hit enter or click. It will follow it. Not everyone uses a mouse. – epascarello Oct 26 '18 at 15:37
  • I didn't think about focus, I like this idea. – Enam Oct 26 '18 at 15:39

1 Answers1

2

Unsure if this will work with your UX design, but I assume you could use the mouseup event to get around this?

Edit You will want to do this for touch devices as well, so you'll want to bind to 2 events 'mouseup' and 'touchend', unsure of the syntax in knockout to so this, so I have done what I assume to be correct below, might be a knockout error there though.

<div class="modal-footer">
    <button type="button" class="btn btn-primary" data-bind="mouseup: $parent.Submit, text: 'Submit', touchend: $parent.Submit"></button>
</div>

Otherwise you could apply a throttle / debounce. For ease of reference, check out lodash documentation on the usage of throttle:

https://lodash.com/docs/4.17.10#throttle

I'm not saying to import lodash purely for their throttle (it's like 70kb un gzipped), but that should give you the idea (the usage).

var waittime = 1000;
self.Submit = _.throttle(function (data, event) {
    console.log('fired');
    /* do some very important staff */
}, waittime);

I don't think that will help though, as it would still execute once the waittime had passed, assuming the user still had their finger/hand on the enter button.

Lee Brindley
  • 6,242
  • 5
  • 41
  • 62
  • 1
    But then the button won't fire on click anymore – Sv443 Oct 26 '18 at 14:38
  • 1
    Sorry, yes you are right, I meant mouseup, not keyup! – Lee Brindley Oct 26 '18 at 14:42
  • 'mouseup' looks fine for now. I'll test it and accept your answer if everything is OK. – Enam Oct 26 '18 at 14:45
  • Awesome, glad to hear. Good luck! – Lee Brindley Oct 26 '18 at 14:46
  • 1
    So you are going to prevent people who do not use a mouse from clicking the button? mouseup is still not going to get around a person that double clicks which is very common. – epascarello Oct 26 '18 at 14:56
  • 1
    Of course not, you raise a good point, and I did wonder if it worked on touch, turns out it does not! So I have edited my answer to include the equivalent touch event (Y) – Lee Brindley Oct 26 '18 at 15:00
  • And you are of course correct about the double-click, that is not what the OP is asking though, if that is the case, then the throttle/debounce would work, or the OPs suggestion of a boolean variable in his application code. – Lee Brindley Oct 26 '18 at 15:03