I want to delete an event handler form a form that contains an inline definition of onsubmit.
<form id="loginForm" onsubmit="return performTask(this);">
I have already try :
$("#loginForm").off("submit")
$("#loginForm").unbind("submit")
$("#loginForm").die("submit")
$("#loginForm").removeAttr("onsubmit")
$("#loginForm").removeProp("onsubmit")
$("#loginForm").attr("onsubmit", "")
$("#loginForm").prop("onsubmit, "")
$("#loginForm")[0].onsubmit = null
$("#loginForm")[0].onsubmit = undefined
$("#loginForm")[0].onSubmit = null
$("#loginForm")[0].onSubmit = undefined
And nothing works !
I add my own event listener usin jquery method on() but it is never called. It apear that the old event listener is executed before mine... It does the same thing with onClick event on button.
I have to explicit that I'm in a chrome extension and more precisely in a Content Script injected in a page.
So the question is, is there any way to purge event handlers ? Or much better is there any way to add an event listener that will be call before the inline handler ?
EDIT : After lot of ugly code, I have find a way to do what I want... I do a copy of the form, delete the inline envent handler, replace in the dom the old form by mine and then create my event handler. It's ugly but it works ... If anyone can explain why I can't do this other way ...
This is an isolated world problem. Chrome extensions run is a separate context from the page; while access to the DOM is shared, inline event listeners are isolated.
Quote from the documentation, emphasis mine:
It's worth noting what happens with JavaScript objects that are shared by the page and the extension - for example, the window.onload event. Each isolated world sees its own version of the object. Assigning to the object affects your independent copy of the object. For example, both the page and extension can assign to window.onload, but neither one can read the other's event handler. The event handlers are called in the order in which they were assigned.
So, to override a page-level listener, you need to inject your overriding code into the page context itself. This is possible; see this excellent answer for details, and here's an example:
var actualCode = "document.getElementById('loginForm').onsubmit = null;";
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);
This adds a <script> element to the page, which then executes in the page's own context.
Try this:
window.addEventListener('submit', function(event) {
event.stopImmediatePropagation();
}, true);
It will stop the propagation of the event.
I actually don't know the object whose 'onSubmit' event is being processed here, so using pseudo logic here:
Identify the object whose event is being processed - say obj.
Identify it's registered events - console.log(obj._events); - say it returns submit [ Function ]
Purge the call back: obj._events.submit = null;
Register your handler.
Hope this helps.
Related
A picture is worth a 1000 words:
As you can see from the picture above the form has a onsubmit event. But when I try to reference the onsubmit even it's telling me it's null.
The reason I'm asking this question is because I'm trying to clear the onsubmit event:
doc.getElementById("frmMaster").onsubmit = null;
Which is not working.
What am I doing wrong here?
I was able to work around the issue yesterday. After browsing the object hierarchy using chrome developer tools i noticed the object had a "onsubmit" attribute but the "onsubmit" property was already null. So:
doc.getElementById("frmMaster").removeAttribute("onsubmit");
successfully removed the event. I admit i don't totally grasp the difference between the event as a property or as an attribute but at least it resolved the issue.
I believe to unregister events you must use removeEventListener('event', boundFunction). A problem that arises from the code you have is that WebForm_OnSubmit may not be defined at a place accessible to you. What you will need to do is get that function into a context you can access from the console (or wherever you ultimately want to call this code). So you can essentially do this:
/*
somewhere in your server code, or wherever this WebForm_OnSubmit is defined
var handleToWebForm_OnSubmit = WebForm_OnSubmit; //must be global scope
// you will need to get a reference in javascript to this function
// and bind it so that you can willingly unbind it
*/
doc.getElementById("frmMaster").removeEventListener('submit', handleToWebForm_OnSubmit)
I'm working on replacing an Ext.data.Store load event handler.
The variable me is different every time within the code block but me.store is the same (obtained via StoreManager.lookup). I want the store event listener to update the various me references. Best way i could find was to add another listener (and delete the old one since i don't need it anymore)
I haven't been able to use un / removeListener i.e. it had not effect.
I've found that i could replace the it by accesing the me.store.events and popping the listener from the load event. However this feels hacky and it might make the code dependant on a specific ExtJS version (4.2) since i don't know if it's a private property or not.
Also me.store.hasListeners['load'] doesn't get notified so it only helps because it removes the actual listener but not in the intended manner. The docs don't mention it, but i'm wondering if it may be an inherited property which can be accessed freely.
Are there any alterntives to the working approach i've come to? Can i remove all event handlers for an event without having a reference to the handler? Or is there a simpler approach i'm missing?
var me = this; // an enriched Ext.form.FormPanel, different every time code runs
me.store //obtained via StoreManger.lookup - so the same every time
me.storeLoaded = function (store, records,successful, opts) {
// some code to select a record from records and use it
me.loadRecord(record);
}
};
if (!me.store.hasListener('load')) {
me.store.on('load', me.storeLoaded);
} else{
//tried this, but it doesn't remove it, probably because me.storeLoaded is different each time (parentForm is different)
me.store.un('load', me.storeLoaded);
//this feels hacky, i couldn't find out if events is a private property
if (me.store.events && me.store.events['load']){
me.store.events['load'].listeners.pop()
}
me.store.on('load', me.storeLoaded);
}
The easiest way to implement adding/removing listeners is using the destroyable parameter as described in the addListener function. That way, you can always be sure which one is removed.
Example:
setActive:function(cmp) {
cmp.myActiveListeners = cmp.eventStore.on({
destroyable: true,
load:cmp.refreshStores,
filterchange:cmp.refreshStores,
scope:cmp
});
},
setInactive:function(cmp) {
Ext.destroy(cmp.myActiveListeners);
},
I cannot recommend to blindly remove ALL listeners, since they may be added by other components (e.g. combobox) that you add later. To track down these bugs will grow you quite some gray hairs.
I was able to find an answer in this article ExtJS overwrite listener:
Sometimes you need to overwrite an event listener in ExtJS. Usually
listeners are registered like this myStore.on('load',
this.myFunction, this); then to remove our previously registered
listener, all we have to do is call un (which is an alias for
removeListener): myStore.un('load', this.myFunction, this);
But, what happens when you don't know what function is registered?
Sometimes you will not have a reference to the original function that
was registered. This situation may arise if there is code that exists
in a different flow or may even come as a package! If that is true,
the you may not be able to get a reference to the javascript function
or edit the existing code. In this case, we will have to look at all
of the functions that are registered for this event. We can then
remove the listeners just for a certain event by calling
clearListeners.
clearListeners was the method i was looking for.
It would seem he uses the events property so i assume it is a valid use. It could be translated in my case to:
me.store.events.load.clearListeners()
However since i will only be using the load event on this particular store, i will simply call on them all.
me.store.clearListeners()
Thanks to Alexander, by suggesting not to remove all listeners that actually helped me find the article. However i will stil go with his solution, even if it polutes the store object because i like it better than clearing all listeners on a store, even if only for a specific event.
So here' s the piece of code. I'm very new to JavaScript so don't be afraid to explain the obvious
$(".my-css-class").on("click", function() {
($(this).attr("data-property-1"), $(this).attr("data-property-2"), this);
});
There's an element in the .jsp page that looks like this:
<i class="clickMe"></i>
I know the .jsp creates a link-icon, and that the above JavaScript is an event handler. I know that it passes these 3 values as arguments another JavaScript method:
function doStuff(prop1, prop2, obj) {
if (prop1 == 'foo') {
//do stuff with prop2
}
else{
// do stuff with obj
}
}
It all works fine. What I want to know is what exactly is going on to make it work? I can't find anything in the code that connects what the event-handler returns to the 'doStuff' java-script function.
The names are totally different, so it's not reflection, it can't be parameter matching because there's other functions with the same number and type of parameters in the file, it can't be convention based because it still works if I find/replace the name of the function to gibberish.
I guess basically I'm asking what this line is doing:
($(this).attr("data-property-1"), $(this).attr("data-property-2"), this);
tl;dr: I'm at a loss, I know how the properties get as far as the onClick event-handler's anonymous function - but how does JavaScript know to pass them as arguments the to the doStuff() function?
the onClick event is a standard event triggered on click of any clickable html element and is automatically raised by the DOM.
You are hooking in to this by listening on any matched ".my-css-class" elements for an onClick Event.
The jquery syntax ".on" has been simplified over time and allows you to hook into any number of events like "submit" - OnSubmit event , or "load" - onLoad Event
Wherever your on("click", myFunction) event hook is picked up, your myFunction will execute.
Looking at your second point...
because it still works if I find/replace the name of the function to gibberish.
The DoStuff function will be found and replaced across all files in your site? or page? or open tabs? , so therefore it must exist somewhere as "doStuff(" or "giberish(".
so when you do a global find/replace, do each one slowly, until you locate it.
Finally, when you do a view source in the browser, this should either explicitly show you the doStuff function, or at the very least give you a clue as to satelite files loaded at runtime, where you can go and investigate.
Use firebug in firefox to debug loaded resources; the ".net tab" to view external loaded resources and the html/javascript they might contain. (for example: your master page might be loading in an embeded resource that contains the doStuff method, becuase of a user or server control reference in that master page)
Also have a look at this:
http://www.developerfusion.com/article/139949/debugging-javascript-with-firebug/
You can step through the javascipt piece by peice until it hits the doStuff method.
Just remember to set at least 1 breakpoint ;-)
I'm working on a project where a number of different companies are working on the same site.
The main developer have set up an event - let's call it init - which indicates the page is ready for our code to execute.
They're basically calling it like this:
$(window).trigger('init');
For a number of reasons I won't go into here, we prefer to avoid using jQuery in our own code wherever possible. I tried to bind to it like this:
window.addEventListener('init', function (event) {
alert('hehehehe');
});
But that doesn't seem to work. This works perfectly, though:
$(window).bind('init', function (event) {
alert('hehehehe');
});
Does jQuery use special event objects by default that you can't bind to with plain JS? Am I just doing something stupid?
The docs for bind seem to contain the answer:
Any string is legal for eventType; if the string is not the name of a native DOM event, then the handler is bound to a custom event. These events are never called by the browser, but may be triggered manually from other JavaScript code using .trigger() or .triggerHandler().
There's no native DOM event called 'init':
http://en.wikipedia.org/wiki/DOM_events
Hence "These events are never called by the browser, but may be triggered manually from other JavaScript code using .trigger() or .triggerHandler()"
I'm looking for an updated answer to this question.
It seems that Event.observers is no longer used (perhaps to avoid memory leaks) in Prototype 1.6+, so how do I track down now what event listeners are attached to an element?
I know Firebug has a "break on next" button, but there are several mouse listeners on the body element that execute before I can get to the behavior that I want on another particular element, so is there some other way?
I've update the answer you linked to with more comprehensive Prototype coverage accounting for changes in versions 1.6.0 to 1.6.1.
It got very messy in between there, but 1.6.1 is somewhat clean:
var handler = function() { alert('clicked!') };
$(element).observe('click', handler);
// inspect
var clickEvents = element.getStorage().get('prototype_event_registry').get('click');
clickEvents.each(function(wrapper){
alert(wrapper.handler) // alerts "function() { alert('clicked!') }"
})
Things are now routed through Element storage : )
Element.getStorage(yourElement).get('prototype_event_registry') will give you an instance of Prototype's Hash, so you can do anything that you would do with hash.
// to see which event types are being observed
Element.getStorage(yourElement).get('prototype_event_registry').keys();
// to get array of handlers for particular event type
Element.getStorage(yourElement).get('prototype_event_registry').get('click');
// to get array of all handlers
Element.getStorage(yourElement).get('prototype_event_registry').values();
// etc.
Note that these are undocumented internal details which might be changed in the future, so I wouldn't rely on them except for, perhaps, debugging purposes.