jQuery Event Plugin issues - javascript

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.

Related

javascript action to trigger an event

I've been working on this for a while. But I think it is going to be difficult for me to simply it for this question.
I have this object. It is a child to an other object.
The child object has an 'action' attribute which executes a fn();
On a mouse click I fire off the action I can see I am executing fn() with no problems.
I want fn() to trigger an event of the parent object.
$('#par).on('trgr.obj', fn(e, dta) { alert('success'); });
$('#par').obj({
chi: { action: fn(dta) {
console.log("doing okay so far");
// Here is where I'm trying to trigger trgr.obj event
// this is what I have so far.
var inst = $.obj.reference(dta.reference);
var objT = inst.get_node(dta.reference);
inst.trgr(
objT, { type: "default" }, "last"
, function (newDta) {
setTimeout(function () { inst.edit(newDta); }, 0);
}
);
}}
});
How does action trigger event 'trgr.obj'?
Any help appreciated.
Are you looking for jQuery to trigger a custom event?
Try $('#par').trigger('trgr.obj')
http://api.jquery.com/on/

jQuery event collision

I have an object :
var myObject = {
open : function() {
console.log('Object open');
$(this).trigger('open');
}
};
$(myObject).on('open', function() {
console.log('Open event received');
});
myObject.open();
This code throw an "too much recursion".
The problem is that trigger is calling the method, if I rename the open method, this works :
var myObject = {
_open : function() {
console.log('Object open');
$(this).trigger('open');
}
};
$(myObject).on('open', function() {
console.log('Open event received');
});
myObject._open();
Does this make sense for anyone ?
Well you created a recursive loop when you try to trigger 'open' again.
a reccursive loop is a function that calls itself over and over agains until the "stackoverflow" error happen ( no puns intended). it's a more efficient way to make loops.
on the second scenario, you trigger _open and then the function tries to trigger the 'open' event, which trigger the on('open') listener.
simple as that.
In your first example
$(this).trigger('open');
recursively triggers the invocation of the myObject.open function.
In a second one
$(this).trigger('open');
triggers new custom event 'open' and then you handle this event with handler that you defined via on() method.
So it sounds like your trying to create a event listener for when your function is executed?
If so this is how I have handled many of these types of events. I use custom events bound to the document so they are avaiable at a global level.
JS Fiddle: https://jsfiddle.net/7eaoe1hp/
var myObject = {
open : function() {
console.log('Object open');
$(document).triggerHandler('open');
}
};
$(document).on('open', function(){
console.log('Open event received');
});
myObject.open();

JQuery.one() event that fires immediately

I'm making a jquery plugin in which you can set the event for something to happen.
$.fn.makeSomething = function(options) {
var defaults = {
activationEvent: "mouseover"
};
options = $.extend(defaults, options);
this.each(function() {
var elem = $(this);
elem.one(options.activationEvent, function(){
// some code to be called at the event (in which I use elem)
// but by default should be called immediately on load
});
});
return this;
}
I would like the default to be that it just happens without any needed interaction. Is this possible?
A little more info:
I have several divs in which some extra content should be loaded. By default I want the content to be loaded when the page loads. However, on some pages I don't want all the content to be loaded with the page, but I want each piece to be loaded only when you hover your mouse over its div.
Thanks!
If you separate the function definition from the binding:
$.fn.makeSomething = function(options) {
// ...
function doSomething() {
// ...
}
$(this).one(options.activationEvent, doSomething);
};
You can test the activationEvent for a default value that isn't an event, such as null, providing the that same function to .each():
$.fn.makeSomething = function(options) {
var defaults = {
activationEvent: null
};
options = $.extend(defaults, options);
function doSomething() {
var $elem = $(this);
// ...
}
if (!options.activationEvent)
this.each(doSomething);
else
this.one(options.activationEvent, doSomething);
};
// act immediately
$('...').makeSomething();
// act on mouseover
$('...').makeSomething({ activationEvent: 'mouseover' });
Both .one() and .each() will invoke doSomething() with this referring to the DOM Element. (Note: the arguments provided to doSomething() will, however, be different.)

JQuery Plugin - triggering internal functions by callback

Skip to bottom for question
JQuery plugin:
$.fn.myPlugin = function( options ) {
var options = $.extend({
myOption: true,
edit: function() {},
done: function() {}
}, options);
options.edit.call(this);
options.done.call(this);
//plugin guts removed to prevent over complication
return {
edit: function(obj) {
$(obj).closest('#myParent').find('#myInput').autosizeInput(); //plugin to autosize an input
},
done: function(obj) {
$(this).closest('tr').find('td').not('.not').each(function(i) {
//do some things
});
}
}
});
Bear in mind this is a cut down version of my plugin.
Called from page:
$(document).ready(function() {
var myPlugin = $('.editable').myPlugin({
edit: $(this).on('click', '.edit-td', function(e) {
e.preventDefault();
//do some page specific stuff
myPlugin.edit( $(this) ); //call the edit returned function
}),
done: $(this).on('click', '.done-td', function(e) {
e.preventDefault();
//do some page specific stuff
myPlugin.done( $(this) ); //call the done returned function
});
});
});
This works great for the most part, however, what i really want is have functions called from inside my plugin every time a specific callback is triggered - without the need to call from outside the plugin.
I have tried including delegated events in my plugin:
$(this).on('click', '.edit-td', function(e) {
e.preventDefault();
$(this).closest('#myParent').find('#myInput').autosizeInput();
});
$(this).on('click', '.done-td', function(e) {
e.preventDefault();
$(this).closest('tr').find('td').not('.not').each(function(i) {
//do some things
});
});
But when the .edit-td is triggered it propagates and triggers the .done-td event, if i put e.stopPropagation() in the edit-td function (because it has been delegated) edit-td stops firing completely.
And non-delegated method:
$(this).find('.done-td').click(function(e, this) {});
But I can't parse the returned object (this) to the internal function before the internal function has completed. (just comes up undefined or missing formal parameter).
*Skip to here
To avoid the question becoming to localised -
I need to have functions called from inside my
plugin every time a specific callback is triggered.
Without calling it using closures
Something like:
if( $.fn.myPlugin.callback().is('edit') ) {
//fire function
}
I needed to return a function(s) like so:
return {
enable: function(arg) {
//do something
},
disable: function(arg) {
//do something
}
}
That way I can call it from inside my plugin by referencing itself like this:
this.myPlugin().disable();

Using variable for selectors in events

for some reason I need to use a variable as the selector for events in backbone, but I can't figure how to do this :
app.views.Selfcare = Backbone.View.extend({
events: {
click window.parent.document .close : "closeWindow"
},
closeWindow: function() {
//code
}
});
I have to use a different scope and I can't do "click .close" : "closeWindow".
Thx for your help.
I had a look at Backbone.js's source code and found out that if your view's events is a function then the function is called and it's return value is used as the events object.
This means that your code can be changed like this:
app.views.Selfcare = Backbone.View.extend({
events: function() {
var _events = {
// all "standard" events can be here if you like
}
_events["events" + "with variables"] = "closeWindow";
return _events;
},
closeWindow: function() {
//code
}
});
THIS is the interesting part of the source code:
if (_.isFunction(events)) events = events.call(this);
Update:
Example is available on JSFiddle HERE**
I'm not sure that you'll be able to use a variable there. You could use the built-in Events methods (see documentation) to add a custom listener, then add an event listener to window.parent.document to trigger that custom event (use the Events.trigger method).
That said, it would be much easier to decouple this event from Backbone entirely (unless you don't want to do that), and go down the addEventListener route:
app.views.Selfcare = Backbone.View.extend({
initialize: function() {
_.bindAll(this, 'render', 'closeWindow');
if(this.options.clickTarget) {
this.options.clickTarget.addEventListener('click', this.closeWindow, false);
}
},
render: function() {
// Render to the DOM here
return this; // as per Backbone conventions
},
closeWindow: function() {
// Stuff here
}
});
// Usage:
var mySelfcare = new app.views.Selfcare({
clickTarget: window.parent.document
});
I think that should work, although I haven't tested it (and there may be one or two syntactical errors!)

Categories