Pass additional arguments into javascript event - javascript

I'm trying to use a JavaScript function with as an event handler for jQuery, but it needs one additional peice of information. I tried adding it on to an object with the data, and using this, but this is null when it gets executed. I believe this has something to do with function copying with in JavaScript. How can I pass my extra info.
<script type="text/javascript">
var WIDTH_ATTR = 'initWidth';
function resizeHandler(event, ui){
var change = ui.size.width - this.master.attr(WIDTH_ATTR);
this.slave.width(slave.attr(WIDTH_ATTR) - change);
};
function splitResize(master, slave, masterHandles){
var s = new SharedResize(master, slave);
master.resizable({ handles: masterHandles, resize: s.resizeHandler });
}
function SharedResize(master, slave){
this.master = master;
this.slave = slave;
this.resizeHandler = resizeHandler;
master.attr(WIDTH_ATTR, master.width());
slave.attr(WIDTH_ATTR, slave.width());
}
// initialise plugins
$(function(){
try {
$('ul.sf-menu').superfish();
splitResize($('#Content'), $('#InfoPanel'));
}catch(ex){
alert(ex.message);
}
});
</script>
This code gives an error of
Line:13
'this.master' is null or not an object.
When a resize is attempted.
Can I make this scheme work, or is there another way to associate the event handler with my data.

Try this change:
function splitResize(master, slave, masterHandles){
var s = new SharedResize(master, slave);
master.resizable({ handles: masterHandles,
resize: function(event, ui) { s.resizeHandler(event, ui); } });
}
With that, the "resize" handler will be an anonymous function that, in turn, calls your handler with the proper context (the "SharedResize" instance).

You can either do what Pointy suggested or you can do this:
function SharedResize(master, slave){
this.master = master;
this.slave = slave;
this.resizeHandler = function(event, ui){
var change = ui.size.width - this.master.attr(WIDTH_ATTR);
this.slave.width(slave.attr(WIDTH_ATTR) - change);
};
master.attr(WIDTH_ATTR, master.width());
slave.attr(WIDTH_ATTR, slave.width());
}

Related

Jquery executing/triggering same code on different events

I have this function onclick event of custom tag densitybtn='yes'
$("[densitybtn='yes']").on('click', function () {
var no_of_people = 0;
//calcdensity
$("[calcdensity='yes']").each(function () {
no_of_people = parseInt($(this).val()) + no_of_people;
});
var total_density = parseInt(carpetArea) / parseInt(no_of_people);
$("#densityVal").html(Myval);
});
Can i extend same code by extending it to $("[calcdensity='yes']").on('blur')
$("[calcdensity='yes']").on('blur').$("[densitybtn='yes']").on('click', function () {
});
Am not sure on executing same code on different events
Let me know is this method correct? or is there any alternative way available?
Define the function normally (not as an anonymous function) and pass the function to the event listeners
function listener() {
var no_of_people = 0;
//calcdensity
$("[calcdensity='yes']").each( function() {
no_of_people = parseInt($(this).val())+no_of_people;
});
var total_density = parseInt(carpetArea)/parseInt(no_of_people);
$("#densityVal").html(Myval);
}
$("[densitybtn='yes']").on('click', listener);
$("[calcdensity='yes']").on('blur', listener);
Nope, thats not a good practise.
Instead you can write a function for the second intent and call it on blur of $("[calcdensity='yes']").
You can bind multiple events using jQuery's .on() method by space-separating the event arguments.
$("[densitybtn='yes']").on('click blur', function() {
// actions to perform
})
You can bind events to multiple elements using jQuery's .add() method.
$("[densitybtn='yes']").add("[calcdensity='yes']").on('click blur', function() {
// actions to perform
})

Problems with eventHandler arguments using geous.js lib

I'm having problems to retrieve the argument passed to my eventHandler.
I'm using geous to put a map inside and activeadmin interface. The solution is working on the show page but I didn't get things working on the index page. The idea is to attach the handler to the dragend event on a marker with my model geographic coordinates.
What I do:
map.locations.add($fields.geousable('getLocation'), { draggable: true, on: { dragend: setFieldsLocation }});
and setFieldsLocation is defined below:
function setFieldsLocation (event) {
alert(setFieldsLocation.caller);
console.log(event);
$('.geousable').find("input")[0].value = event.data.lat;
$('.geousable').find("input")[1].value = event.data.lng;
};
So the first line bind the handler (for dragend) and a method inside the geous lib code attachs it and calls it when the event is fired, here is the snippet:
var _onAdd = function (locationMarker, opts) {
// not relevant code
if (options.on) {
for (event in options.on) {
eventHandler = function() {
var handler = options.on[event],
location = locationMarker.location;
return function() {
handler.call(location);
}
}();
google.maps.event.addListener(locationMarker.marker, event, eventHandler);
}
}
};
Debugger shows the location correct location variable when the handler is called, but I can't get the location variable inside my "setFieldsLocation" function. I tried a lot of things. I changed the header of the javascript function, I used event, e, arguments and this kind of things:
console.log("arguments.callee.caller.name = " +
arguments.callee.caller.name);
console.log("arguments.callee.caller.toString() = " +
arguments.callee.caller.toString());
But no luck.
Ideas with an explanation of what is occurring here will be very appreciated.

How to attach Event Listeners to only newly created elements?

When I fire a function I want it to apply listeners just to elements I pass, particular this jQuery element.
addEventListeners(this);
function addEventListeners(el) {
$(el).mouseenter(function() {
$(this).stop(true,true).switchClass("", "HIGHLIGHT", 400, "easeInOutQuad");
});
$(el).mouseleave(function() {
$(this).stop(true,true).switchClass("HIGHLIGHT", "", 400, "easeInOutQuad");
});
}
It fires from AJAX result:
$.post(url,{el:wartosc_inputa},function(returned) {
var data = $(returned).hide();
$("#listaElementow").prepend(data);
data.slideDown();
loading();
addEventListeners(this);
});
How to code it good? This code is not passing variables from addEventListeners(this); to function.
in the ajax callback function "this" will be the ajax object i think and no longer an element so you need to save "this" in a variable before the ajax starts.
that = this;
$.post(url,{el:wartosc_inputa},function(returned) {
var data = $(returned).hide();
$("#listaElementow").prepend(data);
data.slideDown();
loading();
addEventListeners(that);
});
Judging from the context of the rest of your success handler, I assume returned is the DOM element you're attempting to bind your handlers to. Assuming this is the case:
$.post(url,{el:wartosc_inputa},function(returned) {
var data = $(returned).hide();
$("#listaElementow").prepend(data);
data.slideDown();
loading();
addEventListeners(data[0]);
// change this ^^^^
// pass the DOM element here, or
// change the addEventListeners function to take a jquery element
});
this in that context is not what you expect it to be. Try this:
var self = this;
$.post(url,{el:wartosc_inputa},function(returned) {
var data = $(returned).hide();
$("#listaElementow").prepend(data);
data.slideDown();
loading();
addEventListeners(self);
});

Overwriting a Backbone Models Change Event

I think what I want to do is pretty simple I just don't know how to do it. I would like to fire my own event when one of my models attributes changes for the purpose of passing some data to the event handler (whether the change was an increase or decrease in value).
Basically I want my handler to do this in the view
handler: function(increased) {
if(increased) {
alert("the value increased")
}
else {
alert("the value decreased")
}
}
// ...
this.model.on("change:attr", this.handler, this);
Here you go: You basically listen for change:myvar. When a change occurs you use your model's previous() to get the old value. Depending on whether it increased or decreased you fire the appropriate event. You can listen to these events as shown in the initialize().
(function($){
window.MyModel = Backbone.Model.extend({
initialize: function () {
this.on('change:myvar', this.onMyVarChange);
this.on('increased:myvar', function () {
console.log('Increased');
});
this.on('decreased:myvar', function () {
console.log('Decreased');
});
},
onMyVarChange: function () {
if (this.get('myvar') > this.previous('myvar')) {
this.trigger('increased:myvar');
} else {
this.trigger('decreased:myvar');
}
}
});
window.mymodel = new MyModel({myvar: 1});
mymodel.set({myvar: 2});
mymodel.set({myvar: 3});
mymodel.set({myvar: 1});
})(jQuery);​
Running the above will print "Increased", "Increased", "Decreased" to your console.
Just look at previousAttributes()
You can then compare:
If(this.get(attr) > this.previousAttributes()[attr]){
console.log('bigger');
} else {
console.log('smaller');
}
If you use that in your change event handler you're all set. No need for a custom trigger or a ton of code.
EDIT
This is from my Backbone.Validators project and how I obtain the list of all attributes which have changed during the validation step:
var get_changed_attributes = function(previous, current){
var changedAttributes = [];
_(current).each(function(val, key){
if(!_(previous).has(key)){
changedAttributes.push(key);
} else if (!_.isEqual(val, previous[key])){
changedAttributes.push(key);
}
});
return changedAttributes;
};
This requires Underscore 1.3.1 because it's using _.has. If you can't upgrade that's an easy thing to replace though. In your case you'd passing this.previousAttributes() and this.attributes
What if you fire your own custom event after listening to the change event?
handler: function(increased) {
this.model.trigger('my-custom-event', stuff, you, want);
},
myHandler: function(stuff, you, want){
// Do it...
}
// ...
this.model.on("change:attr", this.handler, this);
this.model.on('my-custom-event, this.myHandler, this);

jQuery Event Plugin issues

Following on from my earlier question, I have decided to have a go at writing a series of jQuery plugins that mimic mobile events (tap, taphold, etc.).
I have the concept working, but am having problems executing the handler functions. Here's how I am defining the plugin methods:
(function($) {
var touch_capable = isTouchCapable();
var settings = {
swipe_h_threshold : 30,
swipe_v_threshold : 50,
taphold_threshold : 750,
startevent : (touch_capable) ? 'touchstart' : 'mousedown',
endevent : (touch_capable) ? 'touchend' : 'mouseup'
};
// tap Event:
$.fn.tap = function(handler) {
return this.each(function() {
var $this = $(this);
var started = false;
$this.bind(settings.startevent, function() {
started = true;
});
$this.bind(settings.endevent, function() {
if(started)
{
handler();
}
});
});
};
}) (jQuery);
And then I can bind these 'events' using $('#a_div').tap();. The problem that I have is this one:
If I pass in a function to the tap() method which works upon the element, there's an error. For example:
$('#my_div').tap(function() { alert($(this).get()) });
Actually alerts [object DOMWindow]. Can anyone point me in the direction of correctly executing the handler function? Could it be somehow related to event propagation?
You can use the Function.prototype.call and Function.prototype.apply methods to set the execution context of a function;
$this.bind(settings.endevent, function() {
if(started)
{
handler.call(this);
}
});
This allows you to minic the interface bind provides to the provided handler;
$this.bind(settings.endevent, function() {
if(started)
{
handler.apply(this, arguments);
}
});
Now the handler will receive the event object as it's first parameter, and this will be set the the element the event fired on.

Categories