jQuery.off not working with a variable function name - javascript

I'm using a modular pattern for writing my Javascript code, and it is totally fun! But I'm stuck very badly at one situation.
My Namespace is as follows:
var settings, handlers, objects,
Namespace = {
handlers: {
//All event handlers go here
},
objects: {
//All jquery button references go here
},
init: function(){
//Initial stuff
}
};
//Call init with the Namespace
I have a button which toggles between two different handlers for a mousedown event on a single object (a div), and handlers are properties of the handlers object. On init, one handler is automatically on to the div and works fine. Now when I click the toggle button, I'm trying to turn off the first handler so I can turn on the other, but it isn't working!
I turn on my first mousedown event handler (or all handlers for that matter!) like this:
Namespace.objects.someObject.on('mousedown', Namespace.handlers.mouseDownHandlerOne);
This works fine. When I try to turn it off like this:
Namespace.objects.someObject.off('mousedown', Namespace.handlers.mouseDownHandlerOne);
It doesn't work! No errors or warnings. If I just use off with mousedown without passing the handlers name, it works. But I need to separate between 2 different handlers!
How should it be done in a modular js environment?

Jquery .off method can take up to 3 arguments, use the following code:
Namespace.objects.someObject.off('mousedown', '**', Namespace.handlers.mouseDownHandlerOne);

Related

Using window.onkeyup in two different JavaScript files

I have a web app that uses multiple JavaScript files. I have two event handlers like this in two files:
window.onkeyup = function (e) { SomeFunction1(e) }
window.onkeyup = function (e) { SomeFunction2(e) }
SomeFunction1 is in a file that's used in every part of the site but SomeFunction2 is in a file that's only used in one part of the site.
The problem is that when I include the JavaScript file that contains the handler for SomeFunction2, it replaces the handler for SomeFunction1, which means the event doesn't trigger any more.
Instead of replacing the window.onkeyup handler, I want to add another handler in the javascript file that contains SomeFunction2 so that both functions are called. How can I do that? jQuery available.
You can use on event function for this:
$(window).on('onkeyup', SomeFunction1);
$(window).on('onkeyup', SomeFunction2);
Or using vanilla JS
window.addEventListener('onkeyup', SomeFunction1);
window.addEventListener('onkeyup', SomeFunction2);
If jQuery available, you could easily add as many listener as you want
$(window).on("keyup", function(){alert(1);});
$(window).on("keyup", function(){alert(2);});
Try it on https://jsfiddle.net/45zf9vkd/
That's because you're using the DOM attribute to attach the handler, and there can only be one.
You're better off using the addEventHandler API:
document.querySelector('foo').addEventListener('click', function(){
// Your code goes here
})
OR
document.querySelector('foo').addEventListener('click', someFunction);
function someFunction(){
// Your code goes here
}
You can add as many as you want.
Try this ;)
Add this in a common file:
window.onkeyup = function(e){
try{
SomeFunction1(e);
}catch(e){}
try{
SomeFunction2(e);
}catch(e){}
}
And include your files where SomeFunction1(e) and SomeFunction2(e) where you need them?
You will need to use addEventListener to have multiple handlers for a DOM element e.g.:
document.querySelector('#elementID').addEventListener('keyup', function(){...
If you already have jQuery set up (it is not worth adding jQuery to your site just for this), you can use
$(window).on('keyup', function(){...
This will only add additional handlers and won't overwrite any existing ones

Call a function saved to a variable that has an event handler attached to it

Hi I am currently trying to call a function that is saved to a variable, but also has an event handler on it.
col.onclick = function(e){
}
I have not been able to find how to call this kind of set up, and was wondering if it's possible at all, and if it can be done without using jquery.
Help would be nice, thanks in advance.
http://pastebin.com/JJYQeZDG //Code that is the root of the problem.
This code is for a game of checkers, for context.
Simply use () like any other function.
Based on your comments, it looks like you may also have a scoping issue.
I would recommend refactoring your code so your onclick function can be accessed without needed the col object:
var onclick = function(e) {
// note: you will only have "e" if this is invoked as an event callback
};
// later when defining col
col.onclick = onclick;
// ...and later when you want to directly invoke onclick
onclick();

Overwrite listener without handler reference, is it ok to access the (possibly private) events property on a Ext.data.store?

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.

'This' scope in TypeScript

On my webpage I have remove icons on rows in a table like this:
I am using TypeScript where I have attached an onClick listener to execute a function called OnRemoveClick, like this $('.remove').click(this.OnRemoveClick);
OnRemoveClick zeros 2 fields (on the row the remove icon is clicked) and then executes 2 functions, like this:
private OnRemoveClick(): void {
$(this).parents('tr').find('.input-qty').val('0');
$(this).parents('tr').find('.sub-total').html('0');
this.GetInputFieldsToJson();
this.CalculateTotal();
}
The problem I have is that it falls over when I get to GetInputFieldsToJson I get:
TypeError: this.GetInputFieldsToJson is not a function at
HTMLAnchorElement.Index.OnRemoveClick
I realise it is because this in the context of OnRemoveClick is attached to the HTMLAnchorElement which means I cannot access my functions from there.
What I have tried
I have tried setting the onClick listener with a lambda expression like this:
$('.remove').click(() => this.OnRemoveClick);
but that means that the two jQuery expressions to zero fields on the row no longer work
As you might have already understood, the problem here is, when the event handler is invoked the default context as the dom element which triggered that event. So you are unable to invoke your object's method using that reference.
There are multiple solutions to this problem, one easy solution is to pass a custom context to the callback function using Function.bind() as given below and access the targeted element using Event.currentTarget in the callback like
private OnRemoveClick(e): void {
$(e.currentTarget).parents('tr').find('.input-qty').val('0');
$(e.currentTarget).parents('tr').find('.sub-total').html('0');
this.GetInputFieldsToJson();
this.CalculateTotal();
}
then
$('.remove').click(this.OnRemoveClick.bind(this));
$('.remove').click(() => this.OnRemoveClick); should be $('.remove').click(() => this.OnRemoveClick()); i.e. call the function.
More on this : https://www.youtube.com/watch?v=tvocUcbCupA

Can you bind to jQuery events with plain JavaScript?

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()"

Categories