Agility.js + jQueryUI, pass parameters to event handlers in controller - javascript

The Agility.js documentation seems to say pretty clearly that Agility objects can accept any valid jQuery event type:
Usual DOM events such as click, dblclick, mouseenter, etc are supported through
jQuery's event API. Please consult jQuery's API for a list of events supported.
But in the docs and in all other examples I've seen, all the controller functions bound to events take no parameters. For example, the following snippet is taken straight out of the online docs:
var button = $$({msg:'Click me'}, '<button data-bind="msg"/>', {
'click &': function() {
this.model.set({msg:"I've been clicked!"});
}
});
$$.document.append(button);
Here the lambda attached to the click event obviously is parameterless. This works OK for ordinary jQuery events, but to use jQueryUI events, each event function has associated data. For example, if I want to use Draggable and Droppable widgets, the drop() function is called on the Droppable to indicate that a Draggable has been dropped onto it, and I need the parameters to drop(event, ui) to figure out which Draggable it was.
Is there any way to declare my controller event handlers so that I can get access to those parameters? Alternatively, is there some other way to do what I'm trying to do? Not getting any information about an event on a controller other than "it fired" seems like a real shortcoming here. I'm not even sure it is possible to extend Agility so that it can handle events other than the standard DOM ones, although I don't see any reason why it shouldn't be, from my reading of the code.
Agility does provide a trigger() function for client code to fire events, which allows for parameters other than the event type. I thought of wiring that up to the jQueryUI event somehow, but I don't see quite how. More to the point, why can you even pass parameters to trigger() if controllers can't see them?

That the example does not show it is unfortunate, but that doesn't mean the argument is not there.
var button = $$({msg:'Click me'}, '<button data-bind="msg"/>', {
'click &': function(jqEvent) {
this.model.set({msg:"I've been clicked!" + jqEvent.target.nodeName});
}
});
$$.document.append(button);
When in doubt just include a console.log(arguments) in your event handlers and see for yourself. You will get the same arguments jQuery gives you.
If you experiment with .trigger() and extra params you will find that there are no surprises there, either.

Related

Using jQuery .on() for all events

Is it considered bad practice to use jQuery's .on() event handler for every event?
Previously, my code contained script like this:
$('#cartButton').click(function(){
openCart();
});
However I've recently started using InstantClick (a pjax jQuery plugin).
Now none of my scripts work. I understand why this is happening, but I cannot wrap my code with the InstantClick.on('change', function(){ tag as this means my code starts to repeat itself. For example, clicking on the cart button will run the openCart() function many times. So to get around this, I'm changing all my functions to something like this:
$(document).on('click', '#cartButton', function(){
openCart();
});
I'm curious as to whether this will increase loading times and cause excess strain. Is it bad practice to use the on() event handler for every event in my code?
It's not bad practice at all..
.on is the preferred method for handling all events, and using .click is just a shortcut that gets passed to the .on method anyway..
If you check out here (unminified source for jquery 2.1.0): https://code.jquery.com/jquery-2.1.0.js
Here are a couple notes:
search for this line: on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
This is the function definition for the on method and just shows you what the code is doing..
also search for this line: jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick "
Th code below this line is mapping all the directly callable shortcuts (like click) and shows you that they are just mapping to the 'on' method.
Hope this helps!!!
No it is not a bad practice to use .on(), actually if you check the source of the .click() function, you'll see that it actually calls .on().
But... Instead of creating an anonymous function, you should simply do this, which would be cleaner, and slightly faster:
$(document).on('click', '#cartButton', openCart);
and
$('#cartButton').click(openCart);

'click' event disappears in Backbone.View after using Quicksand

There is a 'View' in the model with the event click. After using the Quicksand effects plug-in for jQuery, the objects loose their event handlers. I have tried to add the listener for the event with standard methods in backbone.js:
events: {
"click .objContact" : "openChat"
}
and the same tools jQuery delegate:
var self=this;
this.$el.delegate('.objContact','click', function(){
self.openChat();
});
and live:
var self=this;
this.$el.find('.objContact').live('click', function(){
self.openChat();
});
but the click event disappears.
What could be the problem? And how do I solve it?
UPD: Calling 'Quicksand' is in Backbone.Router (subject to change is obtained directly by means of jQuery, not Backbone), so changes are not handled in Backbone.View
UPD 2: The problem is solved in the following way - by moving the handling of the click event from the View-model to View-collection. And treated with live (did not work in on)
Simple Answer: instead of linking the function to the link with the classic ajax method that is
$('a.oldJqueryClass').click(function(){....
you need to make that function standalone, declaring a new function
function myfunction(params) {alert(params);}
than in the link you call that with the old school way:
Click here
In this way the cloned element will contain itself the call to the function and you can forget about restoring the dom integrity broken by the cloning of quicksand.
I did it in my project, it works fine.
Do a call to delegateEvents() after the related DOM entries have changed or become overwritten. In a traditional Backbone app this is typically done in the render method, but you probably need for figure out when and where quicksand does it's magic (I do not know anything about it), and call delegateEvents that will reactivate the events for the current elements in the DOM.

First plugin, how can I make it live for dynamically generated content

http://blog.jeremymartin.name/2008/02/building-your-first-jquery-plugin-that.html
Based on this tutorial, I created my first plugin and made some modifications.
But, the plugin doesn't work for dynamically generated content when I load new content on the site.
I have no idea how to go about making it live. The events are already using .on but the building of the pluggin doesn't work.
Here is the jsFiddle: http://jsfiddle.net/bT4dH/13/
I know I could call the plugin everytime I add content dynamically, but as that gets messy very quickly, I would prefer to avoid it, and integrate it directly into the plugin.
I was starting to try this:
$(document).on('DOMNodeInserted', function (e) {
if (e.target.classname === 'JS_postShrinker') {
$(e.target).shrinker(options);
}
});
But it doesn't work
UPDATE
Please ignore the DOMNodeInserted, I was just trying it. How do people in general make plugins live? I have the same problem with:
http://code.google.com/p/jquery-watermark/
http://unwrongest.com/projects/elastic/
And many more...
You can simply make it live by using .on() in a bit different way, with delegation. The documentation explains it in detail.
$(closeParent).on(event, selectorForElement, handler);
All you have to do is to choose a parent that you surely know will be part of the DOM when you attach the handler. In the worst case, you can choose body.
Then you attach the handler on this element, and specify the selector for the child elements (that can be inserted into the DOM at any time). The handler will run whenever the event is fired on any of the child elements matching the selector. This method makes use of event bubbling in a very clever way.
EDIT: Of course this will only work for event handling. If you need to initialize your elements when they are added to the DOM (resizing, decorating, etc.), you better call the plugin every time this happens. This is how most plugins work. The DOMNodeInserted event is not cross-browser and deprecated, like all Mutation events, so you should not use it.
There is an extra parameter (selector) to delegate the event on it:
$(document).on('DOMNodeInserted',"." + opts.clickZoneClass, function (e) {
if (e.target.classname === 'JS_postShrinker') {
$(e.target).shrinker(options);
}
});

jQuery - append/replace event listeners (when event handlers are not known)

I tried to find an answer to my problem, but was not successful - apologies if the answer is very obvious:). Here is the premise of the issue I am trying to solve.
I have lots of UI elements (buttons, hyperlinks etc) that have native events attached to them (eg, clicking a link executes a function)
I do not have access to those event listeners, nor I know what functions/handlers need to be Invoked
I would like to do a generic function which would:
o transverse thru DOM, find the UI elements like button or hyperlink, and attach additional listeners to it that would execute the same handlers/functions (eg, I want to attach “touchend” listeners that would execute the same handlers/functions as “click” event)
Is there a way for me to somehow find out what event handler(s) is(are) used for a particular UI element, and then append the new listener for same handler via .on() method?
Hiya even though your quandary is bit open ended, hope this helps your cause :)
Read this - Things you may not know about JQuery = http://james.padolsey.com/javascript/things-you-may-not-know-about-jquery/
You can access all event handlers bound to an element (or any object) through jQuery’s event storage:
// List bound events:
console.dir( jQuery('#elem').data('events') );
// Log ALL handlers for ALL events:
jQuery.each($('#elem').data('events'), function(i, event){
jQuery.each(event, function(i, handler){
console.log( handler.toString() );
});
});
// You can see the actual functions which will occur
// on certain events; great for debugging!
P.S. - I would recommend to know your DOM better but above should help. B-)

difference between jQuery.live and jQuery.delegate

I have read some post about why do not use jQuery.live() and I want to check if I got it:)
When I call $("body").delegate('element','click', function);
Is it the same as $(element).live('click', function) ?
In case of normal behaviour..According to the post there are some stopPropagation and performance boons, but is the main difference that live bind everytime to body element, while delegate can bind to another one?
One important difference is that ".live()" will actually build up the jQuery element list for the initial selector, even though the ".live()" function itself only needs the selector string. That means that if the selector is somewhat expensive, the code to set up the handler will go running all over the DOM for no good reason. The ".delegate()" call does not do that.
Really I don't see any reason that new code should use ".live()"; it was sort-of an architectural mistake and should eventually die quietly.
Nettuts has a screencast just to explain this: Quick Tip: The Difference Between Live() and Delegate()
Quote from the site:
// Live(), introduced in 1.3, allows for the binding
// of event handlers to all elements that match a
// selector, including those created in the future.
// It does this by attaching the handler to the document.
// Unfortunately, it does not work well with chaining.
// Don't expect to chain live() after calls like
// children().next()...etc.
$("li").live("click", function() {
$(this).parent().append("<li>New Element</li>");
});
// Delegate, new to version 1.4, perhaps should have been a complete
// replacement for Live(). However, that obviously
// would have broken a lot of code! Nonetheless,
// delegate remedies many of the short-comings
// found in live(). It attaches the event handler
// directly to the context, rather than the document.
// It also doesn't suffer from the chaining issues
// that live does. There are many performance benefits
// to using this method over live().
$('#items').delegate('li', 'click', function() {
$(this).parent().append('<li>New Element</li>');
});
is the main difference that live bind everytime to body element, while delegate can bind to another one?
Yes, exactly. Let's say you have a table that you add and remove rows from, and you want to handle clicks on those rows (or links or buttons within the rows). You could use live for that, but then the event has to bubble all the way down to the body level and let's face it, it feels a bit like a global variable. If you use delegate on the table element instead, you remain more targeted, isolated from other things going on on the page. delegate is a more modular, contained version of live.
Since the .live() method handles events once they have propagated to the top of the document, it is not possible to stop propagation of live events. Similarly, events handled by .delegate() will always propagate to the element to which they are delegated; event handlers on any elements below it will already have been executed by the time the delegated event handler is called.
The short of it is that .live runs at the document level and .delegate runs on whatever element you specify. Why does it make a difference? If you have a mousemove event (or several) bound using .live, jQuery will execute code every time you move your mouse anywhere on the page to see if your callback function should run. This is extremely inefficient and is the reason for having .delegate. .delegate functions only run when the even originates inside of the dom node you specify. If, for example, you said $('ul#myUL').delegate(...), then jQuery would only check to see if the code should run when the event originated from within ul#myUL

Categories