How can i define my own event in jQuery?
Define and attach your own custom events with .bind():
// make myObject listen for myFancyEvent
$('#myobject').bind('myFancyEvent', function(){
alert('Yow!');
});
...then .trigger() them directly:
$('#myobject').trigger('myFancyEvent');
...or mixed in with other event handlers:
$('#myobject').click( function(){
doSomething();
$(this).trigger('myFancyEvent');
});
You shouldn't have trouble finding a lot of information on the subject. This article is a couple of years old, but still a good overview.
You can throw events like this:
$("#element").trigger("your.event", [ 'Pamela', 'Anderson' ] );
Note that extra parameters should be passed as an array.
How to listen for events:
$("#element").bind("your.event", function(event, firstName, lastName) {
// Callback
});
The "#element" selector can be substituted with document if the event isn't specific for a particular dom node.
jQuery documentation:
Bind
Trigger
Refer to this link.
Here are some code snippet from the article above.
You can trigger custom events on any DOM object of your choosing using jQuery. Just trigger it using the following code:
$("#myelement").trigger('fuelified');
You can subscribe to that event using either bind or live functions in jQuery:
$("#myelement").bind('fuelified',function(e){ ... });
$(".cool_elements").live('fuelified',function(e){ ... });
You can even pass additional data about the event when triggering it and reference it on the listeners end:
$("#myelement").trigger('fuelified',{ custom: false });
$("#myelement").bind('fuelified',function(e,data){ if(data.custom) ... });
The element the trigger has been called on, is available to listener’s callback function as the variable this.
Related
I'm new to backbone. I have been looking it has been used in Saiku. I came across the below line.
Saiku.session.trigger('workspace:new', { workspace: this });
Is 'workspace:new' an event? How does backbone trigger recognize it as an event?
Short answer: yes, workspace:new is an event.
Backbone has several built-in events that you can listen for. But you can also trigger custom events, as this code does. The event is identified by only a string (in this case, "workspace:new"). When you call trigger on an object that inherits from Backbone's Event Module, that event "happens." As a second parameter to trigger, you can pass some data about the event, anything you want accessible from the event handler function.
Then, usually somewhere else, there will be code waiting for that event to happen. That is set up by calling the .on or .listenTo methods.
Here's a basic example: (See it in action on JSBin)
var model = new Backbone.Model();
model.on('my-event', function (data) {
console.log("my-event happened!");
console.log(data);
});
model.trigger('my-event');
model.trigger('my-event', 'some-data');
model.trigger('my-event', { anything: 'works' });
I have a setup theoretically like this [see fiddle -> http://jsfiddle.net/GeZyw/] :
var EventTest = function(element) {
this.element = element;
this.element.addEventListener('click', elementClick);
function elementClick() {
var event = document.createEvent('CustomEvent');
event.initEvent('myevent', false, false);
event['xyz']='abc';
event.customData='test';
console.log(event);
this.dispatchEvent(event);
}
}
var element = document.getElementById('test');
var test = new EventTest(element);
$(document).ready(function() {
$("#test").on('myevent', function(e) {
console.log('myevent', e);
});
});
What I want is to create a CustomEvent in pure Javascript, enrich it with some properties and trigger that event so it can be cached also by a library like jQuery.
As you can see in the fiddle, the CustomEvent is triggered well and it is actually populated with custom properties - but when it reaches jQuery on() the custom properties is gone from the first level. My custom properties is now demoted to e.originalEvent.xyz and so on.
That is not very satisfactory. I want at least my own properties to be at the first level.
Also, in a perfect world, I would like to get rid of most of the standard properties in the dispatched event, so it contained (theoretically optimal) :
e = {
xyz : 'abc',
customData : 'test'
}
Is that possible at all? If so, how should I do it?
I have run into the same issue, couple of months ago, the point is:
When an event is received by jQuery, it normalizes the event properties before it dispatches the event to registered event handlers.
and also:
Event handlers won't be receiving the original event. Instead they are getting a new jQuery.Event object with properties copied from the raw HTML event.
Why jQuery does that:
because it can't set properties on a raw HTML event.
I had decided to do the same, I started to do it with a nasty way, and my code ended up so messy, at the end I decided to use jQuery.trigger solution, and pass my event object as the second param, like:
$("#test").bind("myevent", function(e, myeventobj) {
alert(myeventobj.xyz);
});
var myobj = {"xyz":"abc"};
$("#test").trigger("myevent", myobj);
for more info check this link out: .trigger()
In jQuery plugins, which way do you think it's best to allow a function to be hooked in your plugin - trough triggers, or options (arguments) passed in the plugin function?
$.trigger('myplugin_completed', someData);
$(document).bind('myplugin_completed', function(event, someData){ ... });
vs
myPluginOptions.onComplete(someData);
$('.stuff').myPlugin({onComplete: function(someData){ ... }});
Solution
I think the best solution - at least in the case you described (maybe not in all the possible cases) - is to combine both in the following way:
$('.stuff').myPlugin(/* some options here */);
$('.stuff').trigger('myplugin.completed', someData);
and this line:
$('.stuff').on('myplugin.completed', function(event, someData){
/* callback code */
});
is responsible for binding the event handler. It can be called also when someone passes onComplete callback within options when initializing your plugin (of course selector should be adjusted to meet the one used by the code initializing your pugin).
Summary
To sum up, you could:
create your own event (completed),
use your plugin's namespace for this event / plugin (in this case myplugin),
use .on() function (available and preferred since jQuery 1.7),
if onComplete option is passed to your plugin, there is no problem in binding it within the code initializing the plugin (so from within the plugin, using the .on() function, binding event handler to your event name within your even namespace).
I will vote for the second option, because in this way one can control the onComplete event, and it is binded only to the element. Binding it to documents it is not good, because one can do $(document).unbind(), that unbind all events.
I think both ways are good and none of them has big advantage over another.
For example, jQuery UI use callback for options and event triggers for actual events such as start/stop dragging.
But, by creating event triggers in code you create maybe more flexible way to add more event handlers, without modyfing existing code. I mean when you got callbacks, it goes this way:
{onComplete: function(someData){ action_1; }}
If you need some extra actions you write them into existion function or put functions inside:
{onComplete: function(){ action_1; action_2 }}
or
{onComplete: function(){ action_1; function_2(); }}
function_2(){ action_2 };
For comparison using events it would be like:
$('selector').on('myplugin_completed.myplugin', function_1 })
Extra actions:
$('selector').on('myplugin_completed.myplugin_extra', function_2 })
If you don't need some actions you can unbind only them.
$('selector').off('myplugin_completed.myplugin_extra');
There are differences between them, but usually it depends on particular situation, which one is better;
What i'm trying to do is a combination of a mootools class and raphael. The problem i got is mainly mootools event binding i guess.
I'm trying to append an event to a raphael element (dom node) and when firing the event another class method should be called.
This is no problem when coding without a mootools class. But this (the right) way i have some problems. When binding the events, the raphael element cannot be longer used because "this" now refers to the mootools class.
Please take a look at this code and i guess you will understand what my problem is:
// mootools class
var test = new Class({
...
initPlane: function() {
// just an JSON object array
this.objects = [{"pid":"2","sx":"685","sy":"498","dx":"190","dy":"540"},{"pid":"3","sx":"156","sy":"341","dx":"691","dy":"500"}];
// place the objects on stage and append some events to them
this.objects.each(function(item, idx){
item.gfx = this.gfx.image("assets/img/enemy.png", item.sx, item.sy, 32, 32);
// #### differnt approaches to bind the events. all not working
// first attempt with mootools event
item.gfx.node.addEvent('click', function(e) {
console.log(this.attr('x')); // not working because this is bound to the class i guess
this.info();
}.bind(this));
// second attempt with mootools event
item.gfx.node.addEvent('click', function(e) {
console.log(this.attr('x')); // not working
parent.info(this); // no binding and not working
});
// first attempt with raphael event
item.gfx.click( function(e) {
console.log(this.attr('x')); // works !
this.info(this); // not working because this refers to raphael element.
});
}.bind(this))
},
// this method should be called after click event and output element attribs
info: function(event) {
console.log(event.attr('x'));
},
...
});
your .each is wrong.
Object.each(obj, function(el, key, obj) {
}, bind);
http://mootools.net/docs/core/Types/Object#Object:Object-each
although you actually have this.objects as array, did not notice :)
Array.each(function(el, index) {
}, bind);
when you need this to be bound to element on click, that's fine. just store a copy of this into self and call self.info() instead. alternatively, keep the bind and reference e.target as the trigger element instead, whilst this is your instance
although it may seem 'neater' to try to keep this bound to the class wherever possible, mootools-core devs tend to prefer the var self = this; way as it avoids the extra callback to bind etc (look at the mootools source, very common)
also, say you want to have the click event go to a method directly:
element.addEvent("click", this.info.bind(this));
which will send the event as the 1st argument to info (so reference event.target).
bind can usually apply arguments as well as the scope (depending on the implementation), and that allows you to write function (raphaelObj, node) { ... }.bind(null, this, item.gfx.node) to bind two arguments.
In my JavaScript and Flex applications, users often perform actions that I want other JavaScript code on the page to listen for. For example, if someone adds a friend. I want my JavaScript app to then call something like triggerEvent("addedFriend", name);. Then any other code that was listening for the "addedFriend" event will get called along with the name.
Is there a built-in JavaScript mechanism for handling events? I'm ok with using jQuery for this too and I know jQuery makes extensive use of events. But with jQuery, it seems that its event mechanism is all based around elements. As I understand, you have to tie a custom event to an element. I guess I can do that to a dummy element, but my need has nothing to do with DOM elements on a webpage.
Should I just implement this event mechanism myself?
You have a few options:
jQuery does allow you to do this with objects not associated with the document. An example is provided below.
If you're not already using jQuery on your page, then adding it is probably overkill. There are other libraries designed for this. The pattern you are referring to is called PubSub or Publish/Subscribe.
Implement it yourself, as you've suggested, since this is not difficult if you're looking only for basic functionality.
jQuery example:
var a = {};
jQuery(a).bind("change", function () {
alert("I changed!");
});
jQuery(a).trigger("change");
I would implement such using MVVM pattern with knockjs library.
Just create an element, and use jquery events on it.
It can be just a global variable, doesn't even have to be connected to the DOM.
That way you accomplish your task easily and without any extra libs.
Isn't it possible to bind onchange events in addition to click events? For instance, if addFriend is called and modifies a list on the page, you could bind the change event to then invoke additional functionality.
$('#addFriendButton').click( function() {
// modify the #friendList list
});
$('#friendList').change( function() {
myOtherAction();
});
This is total Host independent, no need for jQuery or dom in this case!
function CustomEvents(){
//object holding eventhandlers
this.handlers_ = {};
}
//check if the event type does not exist, create it.
//then push new callback in array.
CustomEvents.prototype.addEventListner = function (type, callBack){
if (!this.handlers_[type]) this.handlers_[type] = [];
this.handlers_[type].push(callBack);
}
CustomEvents.prototype.triggerEvent = function (type){
//trigger all handlers attached to events
if (!this.handlers_[type]) return;
for (var i=0, handler; handler = this.handlers_[type][i]; i++)
{
//call handler function and supply all the original arguments of this function
//minus the first argument which is the type of the event itself
if (typeof handler === "function") handler.apply(this,arguments.slice(1));
}
}
//delete all handlers to an event
CustomEvents.prototype.purgeEventType = function(type){
return delete this.handlers_[type];
}
test:
var customEvents = new CustomEvents();
customEvents.addEventListner("event A", function(arg){alert('Event A with arguments' + arg);));
customEvents.triggerEvent("event A", "the args");
EDIT added arguments passing