user4227915
user4227915

Reputation:

Overwriting tap event with preventDefault

I had a lot of:

$('#element').on('tap', function(){
    // some code ..
})

I searched many questions about the tap event problem firing twice, and I solved my problem using e.preventDefault(), now I have a lot of:

$('#element').on('tap', function(e){
    e.preventDefault();
    // some code ..
})

Ok, but as I said, I have many of these calls and I don't like much to write every time e.preventDefault(), then I typed $.fn.tap on chrome's console and it showed me:

function (a){return a?this.bind(c,a):this.trigger(c)}

I tried to overwrite it this way:

$.fn.tap = function (a) {
    a.preventDefault(); 
    return a?this.bind(c,a):this.trigger(c)
}

But it didn't worked as it did in the previous e.preventDefault().

I'm not seeing anything obvious and I'm out of ideas for this.

Any help or idea is appreciated. Thanks in advance.

Upvotes: 11

Views: 1381

Answers (4)

Rogier Spieker
Rogier Spieker

Reputation: 4187

One of the cool features of jQuery (I usually don't use 'jQuery' and 'cool' in a single sentence) is that it lets you specify custom behaviour for events, using the $.event.special object.

There is very little documentation on the subject, so a little example would be in order. A working fiddle using the click event (as this was more convenient for me to write on my laptop) can be found here

Translated to your request to have all tap events have e.preventDefault() invoked before the actual handler, would look like:

$.event.special.tap.add = function(options) {
  var handler = options.handler;

  options.handler = function(e) {
    e.preventDefault();

    return handler.apply(this, arguments);
  }
}

What this code does (should do, as I haven't actually tested the tap version above) is telling jQuery that you want a special treatment for the tab event, more particularly you want to provide a 'wrapping handler' which does nothing more than call e.preventDefault() before calling the provided event handler.

UPDATE: prevented the default tap-settings from being overwritten, for future visitors


NOTE: Before you make any attempt on changing the default behaviour of things, you should ask yourself why the defaults don't work for you. Mostly because changing default (=expected) behaviour will upset your future self (or worse, another person) while maintaining your code and adding features.

In order to create a maintainable (and predictable) flow in your code the suggested solution to create a special case function ($.fn.tap) is in fact a very viable solution, as it does not interfere with the default (=expected) behaviour of things.

From the links I provided you should also be able to create your own event type (e.g. tapOnly) and make it more obvious there is some custom work involved. Then again, both of these solutions will require you to change your event bindings, which is what you are trying to prevent.

Upvotes: 3

BenG
BenG

Reputation: 15154

This is how you can create your $.fn.tap:-

$.fn.tap = function(f) {
  $(this).on('tap', function(e) {
    e.preventDefault();
    f();
  });
  return this;
};

//usage
$('.selector').tap(function() {
  alert('foo bar')
})

@Washington Guedes - overwrite the default tap-event to always use e.preventDefault() rather than changing from $(element).on('tap', function(){}) to $(element).tap(function(){})

You could add a delegate event to body for tap, without specifying a target. This will then fire for all tap events on the body, which you can then check if the target has its own tap event, so you can then e.preventDefault();.

NOTE: This will not work for delegated tap events as shown.

// global tap handler
$('body').on('tap', function(e) {
  if ($._data(e.target, "events").tap)
    e.preventDefault();
});

// tap event
$('a.tap').on('tap', function(e) {
  $(this).css('color', 'red');
});

// delegated tap event
$('body').on('tap', 'a.delegate', function(e) {
  $(this).css('color', 'green');
});
a {
  display: block;
  margin: 20px 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.js"></script>

<a class="tap" href="www.google.co.uk">tap event, prevented.</a>
<a class="delegate" href="www.google.co.uk">delegate tap event, not prevented.</a>
<a href="www.google.co.uk">no tap event, not prevented</a>

Upvotes: 10

Vixed
Vixed

Reputation: 3509

I knew can be a bad idea but I've just tested this in Chrome

$('*').on('tap',function(e){
    e.preventDefault();
});

$('#element').on('tap', function(){
    // some code ..
});

and if you don't need this for all elements:

$('*').not('#aCertainElement').on('tap',function(e){
    e.preventDefault();
});

Upvotes: 1

Vasim Shaikh
Vasim Shaikh

Reputation: 4512

I had a similar problem, in which e.preventDefault() would work on some cases, but not on others. It showed no errors, and using try-catch was not displaying the catch alert. Adding e.stopImmediatePropagation() did the trick, in case it helps anyone

Upvotes: 0

Related Questions