6

Possible Duplicate:
jQuery - How can I bind all events on a DOM element?

Imagine, if we want to make some element completely initeractable.

We could, of course bind a prevent default for a click event as follows:

$('form *').bind('click', function(event) {
    event.preventDefault();
});

But that's just one event, and there are many more, like hover, focus, selectstart, and many more.

We could specify them all in one line like 'click focus hover dblclick blur selectstart' but that doesn't make much sense and is not easy to maintain.

So, is it possible to bind an event listener without discriminating for the type of the event? Maybe some native JavaScript listeners allow it?

Community
  • 1
  • 1
Anonymous
  • 4,692
  • 8
  • 61
  • 91
  • Look at this question http://stackoverflow.com/questions/9735608/how-to-bind-to-all-custom-events-in-jquery – Erwin Aug 31 '12 at 11:06
  • 1
    What is the benefit of doing so? Do you want to reinvent the wheel? – Ram Aug 31 '12 at 11:08
  • I want to lock my forms and some of the elements. If there's no simple way of doing this, maybe I should place a transparent bg div on the top. But what are the other ways? Mind sharing the wheel? :) – Anonymous Aug 31 '12 at 11:11

6 Answers6

4

No such possibility because not all elements support same events and not all events behave in the same way. You always have to explicitly provide a list of events whether defined statically or dynamically by a script that spits out event names.

Even though I linked to a script that creates an array of event names, these are made on one element only. You should of course be generating this with a more complex and slower script that enumerates over all elements in question and adds missing events. Using Javascript objects as associative array for faster searching whether a particular event has been added or not.

A better suggestion

What you're trying to do is likely a highly over-engineered solution. When I'm creating a demo clickable interface that should disable some elements (be it links, buttons or anything else) I rather do it by defining a CSS class that disables an element in question and have a simple script that does disabling afterwards.

You could leverage this even further by also providing which events you'd like to disable on particular element (with default being a click event).

<!-- no events; use defaults -->
<a href="#" class="disable">No-follow link</a>
<button class="disable">Nothing happens</button>
<!-- provide events -->
<a href="#" class="disable" data-events="click blur">No-follow link</a>
<form class="disable" data-events="submit">...</form>

Script

$(function() {

    var disable = function(evt) {
        evt.preventDefault();
        console.log("Prevented on " + evt.target.tagName);
    };

    $(".disable").each(function() {
        var ctx = $(this);
        ctx.bind(ctx.data("events") || "click", disable);
    });
});

Using smart defaults

Upper example defines one single event default. click event. This is fine and works in majority of cases, but not in all. form elements for instance would always have to define submit event that should be disabled. So. Smart defaults then. We should also consider the fact that list events that need supression is usually short. And if we cover majority of cases using defaults we only have a small overhead on those elements that actually do deviate from defaults.

$(function() {

    // click is still default event
    // this object defines per element events that aren't just click
    var extraDefaults = {
        form: "submit"
    };

    var disable = function(evt) {
        evt.preventDefault();
        console.log("Prevented on " + evt.target.tagName);
    };

    $(".disable").each(function() {
        var ctx = $(this);
        ctx.bind(
            // use inline-defined events
            ctx.data("events") ||
            // use extra defaults if present
            extraDefaults[this.tagName.toLower()] ||
            // just use default click event
            "click",
            disable);
    });
});
Community
  • 1
  • 1
Robert Koritnik
  • 103,639
  • 52
  • 277
  • 404
  • Well, I understand now that there's no simple way. I'll have to think of some entirely different approach in that case. – Anonymous Aug 31 '12 at 11:13
  • @Anonymous: I heavily edited my answer to provide a simple and nice solution that may work for you just as much as it does for me. Based on your comment on the question I can see that my solution would work perfectly for you. – Robert Koritnik Aug 31 '12 at 11:20
  • The above example is the exact approach I was using. The problem with it is that all the input elements have different properties, for example checkboxes may even be triggered by tabbing and pressing space on your keyboard. It takes a lot of scripting, a lot of thinking, and a lot of time each time we want to implement it. – Anonymous Aug 31 '12 at 11:22
  • @Anonymous: You were apparently **not** using this kind of approach, because if you'd disable your `form` element (as shown in example), no form submission could occur whatever triggered it. but otherwise you could disable keydown events and presses as well on your elements if you wanted to. This approach permits that. – Robert Koritnik Aug 31 '12 at 11:24
  • I did use the exact approach, it does work and it does what it does, but it sums up that we need to list all the events once again, which was the exact subject of the question from the beginning... – Anonymous Aug 31 '12 at 11:36
  • @Anonymous: But this is list is normally very short. And if you provide defaults, you don't have to provide this list at all. Having an object with *smart defaults* that define defaults per element type would be even easier so you could define that `form` element has default event **submit**, `input`, `button` and `a` have **click** and so on. Let me edit my answer a bit more. – Robert Koritnik Aug 31 '12 at 11:40
1

You can bind most jQuery events like this :

$("#elementID").on(Object.keys(jQuery.event.fixHooks).join(" "), function(e) { 
    e.preventDefault(); 
});

This will preventDefault on the following events :

click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave keydown keypress keyup contextmenu

FIDDLE

adeneo
  • 312,895
  • 29
  • 395
  • 388
  • This looks simple, and I guess might be as well suitable for many different situations. How about the key though? Do they differ from object to object? If no - it wouldn't make much difference than defining them as a string constant. The number of events listed is also limited. – Anonymous Aug 31 '12 at 11:31
  • @RobertKoritnik - Nope, but how do you submit a form when clicks and keys are disabled on the submit button ? – adeneo Aug 31 '12 at 11:31
  • 1
    enter in the browser's query string `javascript:document.forms[0].submit();` - just kidding :D – Anonymous Aug 31 '12 at 11:33
  • 1
    @Anonymous - this would be the same as using a string with all the events, only difference is it gets the events from jQuery so you don't have to type them, and it only gets the usual events, special events are in `jQuery.event.special`, but if you console log `jQuery.event` you can explore the object yourself and get whatever you need. – adeneo Aug 31 '12 at 11:35
1

Well after considering all the options, it still does not look convenient for all this event hustling. As it also has to bind the handlers for each event individually the script will hit the performance as well.

I am going to stick with a much simpler solution, just putting a div with transparent bg on top to cover our element.

$('form').css('position','relative').prepend($('<div class="mask" style="position:absolute;z-index:9000;height:100%;width:100%;background-image:url(1px_transparent.png);"></div>'));

Which is going to automatically fill the whole area of the element, alternatively, we can use a half-transparent picture so it will be also understood by a user that this is locked element, and would not cause confusion.

And to unlock we simply remove the .mask div from our element.

EDIT

New Fiddle: http://jsfiddle.net/YAdXk/8/

Actually we can disable tabbing by setting tabindex attribute to -1

.find('input,textarea,select').attr('tabindex','-1');

The updated fiddle prevents from tabbing as well.

EDIT2

OR, we can extend jQuery to use our custom lock() and unlock() functions on any element.

See the last fiddle: http://jsfiddle.net/YAdXk/13/

(function($) {
$.fn.lock= function() {
    return this.each(function() {
        $(this).css('position','relative').prepend($('<div class="mask" style="position:absolute;z-index:9000;height:100%;width:100%;background-image:url('+transparent_picture+');"></div>')).find('input,textarea,select').attr('tabindex','-1');
    });
};   

$.fn.unlock= function() {
    return this.each(function() {
        $(this).find('*').removeAttr('tabindex').filter('.mask').remove();
   });
};

})( jQuery )
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Anonymous
  • 4,692
  • 8
  • 61
  • 91
0
var all_events = "click blur focus mouse"; //etc...

$('form *').bind(all_events, function(event) {
        event.preventDefault();
});

Now is easier to maintain ;)

Pawel Dubiel
  • 18,665
  • 3
  • 40
  • 58
0

jQuery defines all shortcut event types here, so you can use that string to store all events for re-use:

var events = "blur focus focusin focusout load resize scroll unload click dblclick " +
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
"change select submit keydown keypress keyup error contextmenu";

$('button').bind(events, function() {
    // hey
});
David Hellsing
  • 106,495
  • 44
  • 176
  • 212
0

Yes, it is possible, to catch all events of one type at once! But you'll need to specify all the event types explicitly.

Your code example of "form *" is inefficient, and would not catch events on elements that are added after your code executes.

Because of the bubbling effect of javascript events, you can assign a catch all event handler on the most parent element, eigther $("form") or $("body"), and add preventDefault() to that.

Example code:

$("a").on("click", function() {
    $("body").append("<p>Clicked...</p>");
});
$("body").on("click", function(e) {
  e.preventDefault();
});

with:

<div>
    <p><a href="#" target="_blank">Click on me</a></p>
</div>​

The concept of catching all events on a parent element, is often referred to as event delegation.

Andreas Åkre Solberg
  • 1,705
  • 12
  • 11
  • event delegation works when events are being delegated. They can of course be served in between by any other element in DOM branch between event originator and delegated element. Not to mention that propagation can be cut in the middle just as well. – Robert Koritnik Aug 31 '12 at 11:49