jQuery Delegate not binding like I want it to - delegates

Using jQuery 1.7
I'm having trouble binding a Click event to some dynamically loaded content.
I've looked around, tried .live, .delegate and .on, and I just can't get it to work.
This is my code:
$(".fileexplorer_folderdlg").delegate(".delete", "click", function () {
console.log("Hello world!");
});
The thing is, .fileexplorer_folderdlg is dynamically loaded. If I use .fileexplorer (not dynamically loaded), it works, but I have more elements with the .delete class that I do not wish to bind to (and neither element classes can be renamed or changed for various reasons).
I also tried using .fileexplorer_folderdlg .delete as the .delegate selector, didnt work either!
Of course I could just add another unique class to the elements I wish to bind to, but this really should work, right?

I believe this would work:
$(document).on('click', '.delete', function() {
if ($(this).closest('.fileexplorer_folderdlg').length) {
console.log('hello, world!');
}
});
or even just:
$(document).on('click', '.fileexplorer_folderdlg .delete', function() {
console.log('hello, world!');
});
As you've found, you can't bind on .fileexplorer_folderdlg because it's dynamic. You therefore need to bind on some static element that will contain that element at some point in the future.
Instead, this binds on the document (but will unfortunately fire for every single click on the document thereafter).
EDIT by Jeff
Although the code above did not work, modifying it a bit did the job, although not the most desirable solution.
$(document).on('click', '.delete', function () {
if($(this).closest(".fileexplorer") != null)
console.log("Thanks for your help!");
});
It works, but this event is fired for all other .delete classes, of which there are many. What I do not understand though, is why using .fileexplorer_folderdlg .delete did not work!

Related

Dojo.query foreach accessing element value

I'm a newbie in Dojo framework, so I hope my question is not really dumb.
I have a link in my web page :
Delete
The variable "index" is well defined, no issue with that.
Then, I've written this piece of code to add an action to the onclick event on my link and a JS function to call before the submit :
dojo.query("a[name=supprimerEnfant_name]").forEach(function(element) {
Spring.addDecoration(new Spring.AjaxEventDecoration({
formId: "form_id",
elementId: element.id,
event: "onclick",
beforeSubmit: function(){
jsFunctionToCall(element.value);
},
params: { _eventId: "deleteEvent", fragments:"frag"}
}))
});
In my jsFunctionToCall, I can get the element.id (checked and it's OK) but the element's value is null and I can't figure out why.
I'm probably missing something important, could you help me with that ?
Thanks in advance.
You should be aware that element.value only works with elements where it's part of the DOM, defined by W3C. So, if you look at the HTMLInputElement interface (used by form elements), you will see that it clearly has a property called value, referencing to the the value of the element.
However, the same is not true for an HTMLAnchorElement. This means the proper way to retrieve the value of the value attribute, is by selecting the attribute itself, using the getAttribute() function or by using the the dojo/dom-attr Dojo module.
For example:
require(["dojo/query", "dojo/dom-attr", "dojo/domReady!"], function(query, domAttr) {
query("a").forEach(function(element) {
console.log(element.id);
console.log(domAttr.get(element, "value")); // This will work
});
});
Demonstration: JSFiddle
The dojo query will return the domNode references always. Anyhow, the anchor element is a HTML element. So, this is nothing to do with Dojo and lets see whats wrong with the JS part.
The "value" is not a standard attribute of anchor element. So, the additional attributes need to be accessed using "getAttribute" method.
i.e. in your case,
element.getAttribute('value')

How to handle custom jQuery events in Meteor?

In Metor 0.3.5, when all events were jQuery events, I was able to use use jQuery UI Draggable and then handle the drag & dragstop events using a Metor event map:
Template.game.events['dragstop .card'] = function (e) {
//stuff
};
But I just read this in the Meteor mailing list:
In 0.3.6, event maps no longer depend on jQuery
And sure enough, the above technique no longer seems to work – my dragstop handler isn't called at all now.
I'd greatly appreciate any advice as to how to achieve the same effect in 0.3.6.
Nowadays, you can simply use body events to accomplish this the "Meteor" way:
Template.body.events({
'dragstop #somedivid': function(e) {
// Do stuff
}
});
Custom jQuery events can be bound with plain old jQuery, bypassing event maps altogether:
$(function () {
$('body').on('dragstop', '.card', function (e) {
//stuff
});
});
Remember to use jQuery's on function to bind the handlers, since template elements are not necessarily included in the DOM at all times.

jQuery — trigger a live event only once per element on the page?

Here's the scenario
$("p").live('customEvent', function (event, chkSomething){
//this particular custom event works with live
if(chkSomething){
doStuff();
// BUT only per element
// So almost like a .one(), but on an elemental basis, and .live()?
}
})
Here's some background
The custom event is from a plugin called inview
The actual issue is here http://syndex.me
In a nutshell, new tumblr posts are being infnitely scrolled via
javascript hack (the only one out there for tumblr fyi.)
The inview plugin listens for new posts to come into the viewport, if the top of an image is shown, it makes it visible.
It's kinda working, but if you check your console at http://.syndex.me check how often the event is being fired
Maybe i'm also being to fussy and this is ok? Please let me know your professional opinion. but ideally i'd like it to stop doing something i dont need anymore.
Some things I've tried that did not work:
stopPropagation
.die();
Some solutions via S.O. didnt work either eg In jQuery, is there any way to only bind a click once? or Using .one() with .live() jQuery
I'm pretty surprised as to why such an option isnt out there yet. Surely the .one() event is also needed for future elements too? #justsayin
Thanks.
Add a class to the element when the event happens, and only have the event happen on elements that don't have that class.
$("p:not(.nolive)").live(event,function(){
$(this).addClass("nolive");
dostuff();
});
Edit: Example from comments:
$("p").live(event,function(){
var $this = $(this);
if ($this.data("live")) {
return;
}
$this.data("live",true);
doStuff();
});
This one works (see fiddle):
jQuery(function($) {
$("p").live('customEvent', function(event, chkSomething) {
//this particular custom event works with live
if (chkSomething) {
doStuff();
// BUT only per element
// So almost like a .one(), but on an elemental basis, and .live()?
$(this).bind('customEvent', false);
}
});
function doStuff() {
window.alert('ran dostuff');
};
$('#content').append('<p>Here is a test</p>');
$('p').trigger('customEvent', {one: true});
$('p').trigger('customEvent', {one: true});
$('p').trigger('customEvent', {one: true});
});
This should also work for your needs, although it's not as pretty :)
$("p").live('customEvent', function (event, chkSomething){
//this particular custom event works with live
if(chkSomething && $(this).data('customEventRanAlready') != 1){
doStuff();
// BUT only per element
// So almost like a .one(), but on an elemental basis, and .live()?
$(this).data('customEventRanAlready', 1);
}
})
Like Kevin mentioned, you can accomplish this by manipulating the CSS selectors, but you actually don't have to use :not(). Here's an alternative method:
// Use an attribute selector like so. This will only select elements
// that have 'theImage' as their ONLY class. Adding another class to them
// will effectively disable the repeating calls from live()
$('div[class=theImage]').live('inview',function(event, visible, visiblePartX, visiblePartY) {
if (visiblePartY=="top") {
$(this).animate({ opacity: 1 });
$(this).addClass('nolive');
console.log("look just how many times this is firing")
}
});
I used the actual code from your site. Hope that was okay.

Adding handler to form inside div, in the future

I am using the following code to direct the results from a form to a specific div.
$(window).load(function () {
$("#form1").submit(function() {
$.post($(this).attr("action"), $(this).serialize(), function(html) {
$("#resultsDiv").html(html);
});
return false; // prevent normal submit
});
});
How can I apply this (or any) handler to future forms that may be created within an updated div ( with new yet to created content inserted into the div at some point in the future)?
I have looked at the .on but I do not see an event for the updating or reloading of a div.
I have tried adding a similar function to the above, but replacing (window) with ("#thefutureDivID"), but no luck.
The best place to add the handler is right after you know the element exists. So, right after this line:
$("#resultsDiv").html(html);
you can add your code that references $("#thefutureDivID").

Event removal in Mootools, and syntax of event addition

So I have been adding my events thusly:
element.addEvent('click', function() {
alert('foobar');
});
However, when attempting to remove said event, this syntactically identical code (with "add" switched to "remove") does not work.
element.removeEvent('click', function() {
alert('foobar');
});
I assume this is because the two functions defined are not referenced the same, so the event is not technically removed. Alright, so I redefine the event addition and removal:
element.addEvent('click', alert('foobar'));
element.removeEvent('click', alert('foobar'));
Which works great, except now when the page loads, the click event is fired even before it's clicked!
The function is removed, though, which is great......
update: when you do .addEvent('type', function(){ }) and .removeEvent('type', function(){ }), even though the functions may have the same 'signatures', they are two separte anonymous functions, assigned on the fly. function 1 is !== to function 2 - hence there is no match when MooTools tries to remove it.
to be able to remove an exact handler, o:
function handler(){ ... }
el.addEvent('click', handler);
// .. later
el.removeEvent('click', handler);
Internally, events are actually a map of keys to functions in element storage. have a look at this fiddle i did a while back for another SO question - http://www.jsfiddle.net/mVJDr/
it will check to see how many events are stacked up for a particular event type on any given element (or all events).
similarly, removeEvent looks for a match in the events storage - have a look on http://jsfiddle.net/dimitar/wLuY3/1/. hence, using named functions like Nikolaus suggested allows you to remove them easily as it provides a match.
also, you can remove events via element.removeEvents("click") for all click events.
your page now alerts because you pass on alert as the function as well as execute it with the params 'foobar'. METHOD followed by () in javascript means RUN THE METHOD PRECEDING IT IMMEDIATELY, NOT LATER. when you bind functions to events, you pass the reference (the method name) only.
to avoid using an anonymous function and to pass argument,s you can do something like:
document.id('foobar').addEvent('click', alert.bind(this, 'foo'));
as bind raps it for you, but removing this will be even more complicated.
as for event delegation, it's:
parentEl.addEvents({
"click:relay(a.linkout)": function(e, el) {
},
"mouseover:relay(li.menu)": function(e, el) {
}
});
more on that here http://mootools.net/docs/more/Element/Element.Delegation#Element:removeEvent
keep in mind it's not great / very stable. works fine for click stuff, mouseenter is not to be used delegated, just mouseover - which means IE can fire mouseout when it should not. the way i understand it, it's coming improved in mootools 2.0
edit updating to show an example of bound and unbound method within a class pattern in mootools
http://www.jsfiddle.net/wmhgw/
var foo = new Class({
message: "hi",
toElement: function() {
return this.element = new Element("a", {
href: "http://www.google.com",
text: "google",
events: {
"click": this.bar.bind(this), // bind it
"mouseenter": this.bar // unbound -> this.element becomes this
}
});
},
bar: function(event) {
event.stop();
// hi when bound to class instance (this.message will exist)
// 'undefined' otherwise.
console.log(this.message || "undefined");
}
});
document.id(new foo()).inject(document.body);
the mouseenter here will be unbound where this will refer to the default scope (i.e the element that triggered the event - the a href). when bound, you can get the element via event.target instead - the event object is always passed on to the function as a parameter.
btw, this is a slightly less familiar use of class and element relation but it serves my purposes here to illustrate binding in the context of classes.
assig the function to a variable and use the same reference to add and remove the event.
if you use an anonymous function you will get to different references
var test = function(){ alert('test: ' + this.id); }
$('element').addEvent('click', test);
...
$('element').removeEvent('click', test);
addEvent : Attaches an event listener to a DOM element.
Example -
$('myElement').addEvent('click', function(){
alert('clicked!');
});
removeEvent : Works as Element.addEvent, but instead removes the specified event listener.
Example -
var destroy = function(){ alert('Boom: ' + this.id); } // this refers to the Element.
$('myElement').addEvent('click', destroy);
//later...
$('myElement').removeEvent('click', destroy);
This means when you add an event with a eventhandler not an anonymous function if you than remove the event than it will be removed.

Resources