I'm working with some event handlers, and am getting a bit confused as to one aspect.
According to this thread, Firefox adheres to WC3 standards and passes click events as a parameter to your handler. You can then access this event by coding MyHandler(event). However, what if you're passing another parameter already?
Specifically, my onClick function is editItem(this) where this refers to the table row that was clicked. However, I need to call event.stopPropagation() inside the editItem function in order to prevent some other handlers from going off. In IE and Chrome, this works, but in Firefox, event.stopPropagation() gives me a null pointer, which makes sense because I'm not taking in an event parameter into editItem(this).
My question is, how do I take in both this and event in my onClick function? Can I just append them like editItem(this, event)? How will Firefox know which one is the event and which one is my personal parameter?
You can do editItem(this, event) as you mentioned. Then your function just needs to be defined like this:
function editItem(element, event){
...
}
It will know which parameter is which because of the order of the parameters.
Related
I have a form element with an ng-change handler. I want to programmatically trigger the handler, but without direct inspection of scope. I want to do this because I'm writing a Chrome extension so I can't easily access '$scope' to get the handler.
I have tried the obvious choice of
$(element).triggerHandler('change')
but that doesn't seem to work. See example here: https://plnkr.co/edit/iaz7trxVT09XWBktGhE9?p=preview (in this example I'm logging some lines to console when the change handler runs, but clicking the button doesn't log those lines).
I tried a few other methods found in various threads here, such as trigger() or manual construction of event and fire with dispatchEvent but to no avail. I don't quite understand why the event handler isn't triggering. Can anyone help?
Well, apparently (according to docs), the model change will not be triggered when the value is not changed. An ugly (yet effective) workaround would be to actually change the value briefly:
var v = $('#testField1').val();
$('#testField1').val(0)
$('#testField1').triggerHandler('change');
$('#testField1').val(v)
$('#testField1').triggerHandler('change');
Of course this will trigger the event twice, if this is a problem you could for example use a known "magic value" (e.g. min negative integer) and ignore it.
Alternatively, I'm afraid there is no simple solution: you might need to access the scope / controller to invoke the function you want directly or meddle with angular's event handling.
I want a generic (cross browser) way to get the browser to execute the default action for an object for a specified event preferably without getting any attached listeners to fire.
This kind of question has been asked before but in the context of already being in an event, &/or strictly talking about synchronously holding off the default action before letting it happen later.
Basically, let's say you have an DOM element (you don't know which) variable, and you want to invoke a click, such that if it were an anchor, it'd follow its href, if it were an input[type="submit"] it would submit the form.
But without firing that element's listeners for the click event (which may be prone preventDefault()s in the listeners).
For those that need a reason to answer questions; you may want to do it if you're implementing something like dispatchEvent() for browsers that only have fireEvent().
Both functions return true if the default wasn't 'prevented', but only dispatchEvent() actually follows through and invokes the default.
As a side question, jQuery's trigger() is meant to do this (although after firing the listeners) and be cross-browser, maybe the solution is there? As nice as jQuery is I'd like to know the vanilla methods it is calling (if it [this particular feature] indeed works on things like IE8).
It appears that, at least for the click event, you can call .click() on the element in these browsers.
This will have the element enact the default (as well as calling all listeners and the .onclick value, if defined).
I don't know of any other defaults on DOM elements, would scroll need to be accounted for? Keypress? Maybe those exist as functions too, but I haven't tested.
When I did test .click(), I noticed it obeyed any of the listeners returning false and did not fire the default, and the event did bubble (a listener I had on document fired too!).
There may be no other alternative (I.e. calling the default directly, avoiding the listeners). And as for passing it an event object, the browser in question has the single global event thing going on, so maybe you can manipulate that and it wont have changed when executing .click().
Adding as I find more information in my travels :)
Furthermore, there is an doScroll() function, but I think it would be really hard to translate a given event into the string accepted by this method
Is there a way to temporarily disable an event listener?
In my case, I have a third party library (not jQuery centric) that creates mouseover/mouseout events on an element using addEventListener/attachEvent.
Under certain circumstances another event fires on a different element and I need to disable those event listeners. My solution thus far has been to simply unbind the mouseover/mouseout. This usually works fine because that event generally causes the page to refresh.
However, every now and again an error can occur (think validation error) that results in the page not refreshing, and I need to re-attach the mouseover/mouseout event listeners.
Helpful information
It's probably worth mentioning that because the mouseover/mouseout event listeners are created and attached within a third party library I cannot simply assign the event to a variable and bind/unbind it in that manner (which AFIK is the best way to do this).
Update
I had originally asked
Is there a way in jQuery to get the event listeners already assigned to an object?
I have since found out it is impossible to access events assigned by addEventListener/attachEvent: Access events added with attachEvent() / addEventListener() in JavaScript
jQuery uses data to store events internally, so you can use it to get all of the event handlers for an object:
$("#foo").data("events")
You can then remove a specific handler by using unbind:
$("#foo").unbind('click', $("#foo").data("events").click[42]);
Unfortunately, you can't access them. At best, you can remove event listeners using W3C's removeEventListener (docs) and/or Microsofts detachEvent (docs). Once the listener is removed, however, it's gone for good.
There's one caveat with removeEventListener, in that if the event was registered twice, once indicating to capture, and once indicating not to capture, you must remove it twice; once for each case.
To learn more about capturing and not capturing, see the W3C spec.
If you want to temporarily disable an event handler being run, why not just add escape code to the function?
like so:
$('#button').click(function(){
var clicked_element = $(this);
if(elem.hasClass('event-click-disabled'))
{
// logging code so we know exactly what events are being skipped
console.info(
'The click event on following element was skipped',
clicked_element
);
return;
}
alert('Button clicked');
});
Then if you want to disable an event on a specific element, just call
element.addClass('event-click-disabled');
The event handler is still run, but it will return immediately.
I'm using jQuery in an app which registers user clicks to perform a given action through the .click() binding, and I want this functionality to be available only through a user mousedown. One of my friends pointed out today that it's possible to run $(element).click() from a javascript terminal in Firebug (or something similar), and achieve the same functionality as clicking on the element -- something I'd like to prevent. Any ideas on how to go about doing this? Thanks for your input.
Short answer: No, you can't really prevent it.
Long answer: Any event like a click event is bound to such called Event handlers. Those handlers are functions which are executed when a given event occurs. So if you click on an element, your browser checks if any event handlers are bound to it, if so it fires them. If not, the browser will try to bubble up the event to the parent elements, again checks if there are any event handlers bound for that kind of event .. and so forth.
jQuerys .trigger() method (which is what you actually call if calling .click() for instance) just does the same thing. It calls the event handlers which are bound to a specific element, for a specific event.
EDIT
There might some simple ways to somekind of soft detect a real click, for instance you might check for the toElement property within an event object. That property is not set when triggered. But then again, you can easily fake that aswell with .trigger(). Example:
$(document).ready(function() {
$('#invalid2').bind('click', function(e){
alert('click\nevent.target: ' + e.toElement.id);
console.log(e);
});
$('#invalid1').bind('click', function(){
$('#invalid2').trigger({
type: 'click',
toElement: {id: 'Fake'}
});
});
});
Working example: http://www.jsfiddle.net/v4wkv/1/
If you would just call $('#invalid2').trigger('click') the toElement property would not be there and therefore fail. But as you can see, you can add like anything into the event object.
What are you trying to prevent? Someone messing with your client side script? You can do things like obfuscate your code but not much other than that. But even doing this is just making it more hassle than it's worth in my opinion.
If you don't want people doing certain things move the functionality to the server.
Sorry to be bearer of bad news.
You cannot really do anything against it, it would also be possible to write the complete function and then fire it.
But why is this a problem? If somebody is changing something client side it only affects him. Or are you trying to check some data? This MUST always be done in the backend, because you can never be sure what is really sent to it.
You can check event object (which is passed as first argument to handler) originalEvent.
It will be undefined if event is simulated by .click()
But it's completely useless. You cannot use javascript for security - client has full control over it (and firebug console is just most obvious tool). Client-side security checks should be only hint for user and protection against errors, malicious input can be stopped on server-side only.
Today is jQuery day. I found this in the documentation:
blur() Returns: jQuery Triggers the blur event of each matched element.
blur(fn) Returns: jQuery Bind a function to the blur event of each matched
element.
In other words, the behavior of the function is totally different depending if it accepts or not an argument.
Is this a design mistake or there's a historical reason for this ?
Keep into account that I know nothing about javascript nor jQuery, and I am trying to get a feeling of it.
That's how jQuery is designed, it's the same for all events. To add a handler to an element you use e.blur(function(){...}), and to trigger the event, you use e.blur(). It kind of makes sense, you just have to get used to it.
Definitely not a design mistake, because it goes for multiple events, such as click, however you should be using .trigger('blur')
It makes sense because .blur() or .click() by nature invokes the event handlers attached to the specific event, and all .blur(fn) does is bind it to .bind('event') where behind the scenes it registers the event handlers.