Reputation: 717
I am using .on() to add listeners a few items in my DOM - one input range field, and a number of blocks with the class .colorBlock. These event listeners only need to be active intermittently, and I would like to turn them .off() when they are not in use. Doing this means using a named function instead of an anonymous one.
So fair enough, except that I need to pass data into the callback functions. I know I can use the second (third?) argument field to pass in an object to the event, which is readable in the callback, but doing so seems to be scoping this to the event, instead of to the DOM node that .on() was listened on. See below for example:
$('#brushSize').on('touchend', { size: $(this).val() }, utils.setBrushSize);
$('.colorBlock').on('touchstart', { color: $(this).data('color') }, utils.setColor);
In my callback functions, I added an alert for e.data.color and e.data.size, and both call out undefined.
To make matters worse, this is a phone gap app, so I am limited in my options to trace what is getting passed around, so some of what I am assuming could be wrong about what is going on.
Any suggestions?
Thanks.
Upvotes: 0
Views: 103
Reputation: 717
So the solution for this particular problem ended up requiring that I strip this bit of code out of Phone Gap and rebuild it in a browser. I was then able to console.log the event that was being sent to the callbacks, and examine them to understand the event object better.
The solutions was to use event.target. This allowed to get the event.target.dataset.color for the .colorBlock listener, and event.target.value from the brushSize range listener.
So for future me, I would be good to have a solid working version of my app in the browser with the phone gap stuff stripped out, to do better testing for problems like this.
Upvotes: 0
Reputation: 1823
The value you're sending in the arguments object is always going to be the number it was when you called the .on() statement. That function's not going to be dynamically re-called every time the event fires.
Personally I think it's really ugly to have the util class go looking for some DOM element and get its value, when as you alluded, what you really want to do is have your util function run in the same scope as the .on() statement.
Your first instinct was probably correct. You don't want an anonymous function, because you want to be able to call off(). Ideally you want a named function that runs in the same scope as the thing that calls the on() statement. So what you want to do is bind the util function to your current scope:
$('#brushSize').on('touchend', utils.setBrushSize.bind(this));
Then in utils.setBrushSize, $(this) is whatever function you called .on() from.
edit Just a warning on this though: when you call off(), you want to call it like this:
$('#brushSize').off('touchend', utils.setBrushSize);
Not on a new scope-bound version of setBrushSize. JQuery should recognize it as equal to the original function you bound and turn it off.
re-edit I'm realizing now that your val() is in $('#brushSize') as that's the "this" you're trying to call... not the function holding the on statement. In that case you can do it this way:
$('#brushSize').on('touchend', utils.setBrushSize.bind($(this)));
Upvotes: 1
Reputation: 1074475
Let's break down this line:
$('#brushSize').on('touchend', { size: $(this).val() }, utils.setBrushSize);
It's exactly the same (other than the variables) as this:
var sizeValue = $(this).val();
$('#brushSize').on('touchend', { size: sizeValue }, utils.setBrushSize);
E.g., you're calling $(this).val()
, and then passing the result of calling it in as part of your data object. So unless this
is already what you want to get the value from at that point, it's not going to work.
If you want to get some information from the element when the event happens, just put that code in your event handler. For example, looking at this line:
$('.colorBlock').on('touchstart', { color: $(this).data('color') }, utils.setColor);
It looks to me like you're trying to get the color from the .colorBlock
element that was touched. If so:
$('.colorBlock').on('touchstart', function() {
utils.setColor($(this).data('color'));
});
Or if you're going to reuse it:
utils.setColorFromEventElement = function() {
utils.setColor($(this).data('color'));
};
and
$('.colorBlock').on('touchstart', utils.setColorFromEventElement);
Side note:
There's also a possible second problem with that line. You're using utils.setBrushSize
as the event handler. Note that within the call to setBrushSize
, this
will refer to the DOM element on which you hooked the event, not utils
. Now, given the name utils
, maybe that doesn't matter, but I thought I'd mention it.
More: Mythical methods, You must remember this
Upvotes: 1