Update: As of jQuery 1.4, $.live() now supports focusin and focusout events.
jQuery currently1 doesn't support "blur" or "focus" as arguments for the $.live() method. What type of work-around could I implement to achieve the following:
$("textarea")
.live("focus", function() { foo = "bar"; })
.live("blur", function() { foo = "fizz"; });
1. 07/29/2009, version 1.3.2
Working solution:
(function(){
var special = jQuery.event.special,
uid1 = 'D' + (+new Date()),
uid2 = 'D' + (+new Date() + 1);
jQuery.event.special.focus = {
setup: function() {
var _self = this,
handler = function(e) {
e = jQuery.event.fix(e);
e.type = 'focus';
if (_self === document) {
jQuery.event.handle.call(_self, e);
}
};
jQuery(this).data(uid1, handler);
if (_self === document) {
/* Must be live() */
if (_self.addEventListener) {
_self.addEventListener('focus', handler, true);
} else {
_self.attachEvent('onfocusin', handler);
}
} else {
return false;
}
},
teardown: function() {
var handler = jQuery(this).data(uid1);
if (this === document) {
if (this.removeEventListener) {
this.removeEventListener('focus', handler, true);
} else {
this.detachEvent('onfocusin', handler);
}
}
}
};
jQuery.event.special.blur = {
setup: function() {
var _self = this,
handler = function(e) {
e = jQuery.event.fix(e);
e.type = 'blur';
if (_self === document) {
jQuery.event.handle.call(_self, e);
}
};
jQuery(this).data(uid2, handler);
if (_self === document) {
/* Must be live() */
if (_self.addEventListener) {
_self.addEventListener('blur', handler, true);
} else {
_self.attachEvent('onfocusout', handler);
}
} else {
return false;
}
},
teardown: function() {
var handler = jQuery(this).data(uid2);
if (this === document) {
if (this.removeEventListener) {
this.removeEventListener('blur', handler, true);
} else {
this.detachEvent('onfocusout', handler);
}
}
}
};
})();
Tested in IE/FF/Chrome. Should work exactly as you intended.
UPDATE: Teardowns now work.
This functionality is now included in jQuery core (as of 1.4.1).
live() is jQuery's shortcut to event delegation. To answer your question, see Delegating the focus and blur events.
It's pretty ingenious: for standards compliant browsers he uses event capturing to trap those events. For IE he uses IE's proprietary focusin (for focus) and focusout (for blur) events, which do bubble, allowing traditional event delegation.
I'll leave the porting of it to jQuery as an exercise.
they have been added on jquery 1.4.1 ... now .live() function supports fucus and blur events =) Greetings
Looks like the problem is when checking the event.type it returns "focusin" & "focusout"
$('input').live("focus blur", function(event){
if (event.type == "focusin") {
console.log(event.type);
}else{
console.log(event.type);
}
});
one more addition: this solution does not support more than one parameter.
i tried:
$(el).live("focus blur", function(e) {
if (e.type == "focus") {
etc.
and it only fired the blur event.
nevertheless this solution has been helpful.
Related
Is there a pure JS version of this?
$(document).on('click', 'a[href]', function(event) {
event.preventDefault();
here.change(this);
});
The specific feature I'm looking for is adding event listeners for any link that's created later via JS (AJAX for example).
Modern browsers support matches which makes this a lot easier
document.addEventListener('click', function(event) {
if (event.target.matches('a[href], a[href] *')) {
event.preventDefault();
console.log('works fine')
}
}, false);
document.body.innerHTML = '<span>Click Me!</span><br /><div>not me!</div>';
You could make this more convenient with a simple function
function addEvent(parent, evt, selector, handler) {
parent.addEventListener(evt, function(event) {
if (event.target.matches(selector + ', ' + selector + ' *')) {
handler.apply(event.target.closest(selector), arguments);
}
}, false);
}
Note that closest() is only supported in the latest browsers, there's a polyfill on MDN
This replicates the jQuery behaviour a lot more, and is easier to use, it also sets the value of this correctly
function addEvent(parent, evt, selector, handler) {
parent.addEventListener(evt, function(event) {
if (event.target.matches(selector + ', ' + selector + ' *')) {
handler.apply(event.target.closest(selector), arguments);
}
}, false);
}
/* To be used as */
addEvent(document, 'click', 'a[href]', function(e) {
console.log(this)
});
/* Add a dynamic element */
document.body.innerHTML = '<span>Click Me!</span><br /><div>not me!</div>';
You can attach click event to document. check if event.target .tagName is "A" and if event.target has property .href. It is not clear what expected result of here.change(this) is expected to do from text of Question
function dynamicA() {
var a = document.createElement("a");
a.href = "";
a.textContent = "a";
document.body.innerHTML += "<br>";
document.body.appendChild(a);
}
document.addEventListener("click", function(event) {
event.preventDefault();
if (event.target.tagName === "A" && event.target.href) {
// do stuff
dynamicA();
}
});
<a href>a</a>
I believe this accomplishes what you want:
// for all dom elements on click
document.onclick = function(event) {
var el = event.target; // get what is being clicked on
if(el.hasAttribute('href') && el.tagName == 'a') { // check if it's a link
event.preventDefault();
here.change(this); // what is this?
}
}
Was wondering if there's a javascript .one equivalent? Basically I need to detect when my transform fires but only once, at the moment the transitionend event fires twice which is messing up my transitions. I was hoping to use the event.propertyName but this just reads 'transform' which doesn't help. Example snippet here:
loader.addEventListener("transitionend", function(event) {
console.log(event); // fires twice
//if (event.propertyName === 'transform') {
togglePages(page);
//}
}, false);
You can create one:
function one(element, eventName, callback) {
element.addEventListener(eventName, function handler(event) {
element.removeEventListener(eventName, handler);
callback(event);
});
}
Now you can do:
one(loader, "transitionend", function(event) {
console.log(event);
togglePages(page);
});
You can use a simple control variable:
var didHappen = false;
loader.addEventListener("transitionend", function(event) {
if (!didHappen) {
togglePages(page);
didHappen = true;
}
});
Try removeEventListener.
Example:
loader.addEventListener("transitionend",function transition(event) {
loader.removeEventListener("transitionend", transition, false);
//if (event.propertyName === 'transform') {
togglePages(page);
//}
}, false);
Or
var transition = function (event) {
loader.removeEventListener("transitionend", transition, false);
//if (event.propertyName === 'transform') {
togglePages(page);
//}
};
loader.addEventListener("transitionend", , false);
Is there a polyfill for the IE events mouseenter/mouseleave (or a conversion of the jQuery events) so it can be bound to raw JS events?
I.E. I is there a cross browser way to do this:
node.addEventListener('mouseenter', function() {
...
});
node.addEventListener('mouseleave', function() {
...
});
I know it should be possible custom events using:
var event = new Event('mouseenter');
node.addEventListener('mouseenter', function (e) { ... });
node.dispatchEvent(event);
etc
Ok, seems I figured out how to do it:
http://jsfiddle.net/HXwJH/5/
node.addEventListener('mouseover', function() {
if (!event.relatedTarget || (event.relatedTarget !== this && !(this.compareDocumentPosition(event.relatedTarget) & Node.DOCUMENT_POSITION_CONTAINED_BY))) {
this.dispatchEvent(new Event('mouseenter'));
}
});
node.addEventListener('mouseout', function() {
if (!event.relatedTarget || (event.relatedTarget !== this && !(this.compareDocumentPosition(event.relatedTarget) & Node.DOCUMENT_POSITION_CONTAINED_BY))) {
this.dispatchEvent(new Event('mouseleave'));
}
});
This is really straight forward but I'm still fairly new to JavaScript and just found JSFiddle. I'm trying to find the element with the getElementById() to disable and enable a button. What am I missing?
<form name="frm" >
<div id="chkObj">
<input type="checkbox" name="setChkBx" onclick="basicList.modifyAndEnableButton(this)"></input>
</div>
<div id="Hello">
<input type="button" name="btn" value="Hello"></input>
</div>
</form>
This is a list that I am using to add checkboxes because there is going to be more than one:
var basicList = {
'items': {},
'modifyAndEnableButton': function(obj1) {
var element = document.getElementsByName("btn");
if (obj1.checked == true && element.getAttribute('disabled') == false) {
element.getAttribute('disabled') = true;
this.addRecord(obj2);
} else if (element.getAttribute('disabled') == true) {
if (hasItems == false) {
element.getAttribute('disabled') = false;
}
}
}
};
http://jsfiddle.net/Arandolph0/E9zvc/3/
All browsers support this (see example here):
mySelectedElement.onclick = function(e){
//your handler here
}
However, sometimes you want to add a handler (and not change the same one), and more generally when available you should use addEventListener (needs shim for IE8-)
mySelectedElement.addEventListener("click",function(e){
//your handler here
},false);
Here is a working example:
var button = document.getElementById("myButton");
button.addEventListener("click",function(e){
button.disabled = "true";
},false);
And html:
<button id='myButton'>Hello</button>
(fiddle)
Here are some useful resources:
addEventListener on mdn
The click event in the DOM specification
Click example in the MDN JavaScript tutorial
Benjamin's answer covers quite everything. However you need a delegation model to handle events on elements that were added dynamically then
document.addEventListener("click", function (e) {
if (e.target.id == "abc") {
alert("Clicked");
}
});
For IE7/IE8
document.attachEvent('onclick', function (e) {
if (window.event.srcElement == "abc") {
alert("Clicked");
}
});
You have a Error here
btnRush should be Rushbtn
This is a example of cross browser event's I just made (not tested) )
var addEvent = function( element, type, callback, bubble ) { // 1
if(document.addEventListener) { // 2
return element.addEventListener( type, callback, bubble || false ); // 3
}
return element.attachEvent('on' + type, callback ); // 4
};
var onEvent = function( element, type, callback, bubble) { // 1
if(document.addEventListener) { // 2
document.addEventListener( type, function( event ){ // 3
if(event.target === element || event.target.id === element) { // 5
callback.apply(event.target, [event]); // 6
}
}, bubble || false);
} else {
document.attachEvent( 'on' + type, function( event ){ // 4
if(event.srcElement === element || event.srcElement.id === element) { // 5
callback.apply(event.target, [event]); // 6
}
});
}
};
Steps
Create a function that accepts 4 values ( self explaining )
Check if the browser supports addEventListener
Add event on the element
else add event on the element for older IE
Check that the (clicked) element is = to the passed element
call the callback function pass the element as this and pass the event
The onEvent is used for event delegation.
The addEvent is for your standard event.
here's how you can use them
The first 2 are for dynamically added elements
onEvent('rushBtn', 'click', function(){
alert('click')
});
var rush = document.getElementById('rushBtn');
onEvent(rush, 'click', function(){
alert('click');
});
// Standard Event
addEvent(rush, 'click', function(){
alert('click');
});
Event Delegation is this basically.
Add a click event to the document so the event will fire whenever & wherever then you check the element that was clicked on to see if it matches the element you need. this way it will always work.
Demo
I need to capture an event instead of letting it bubble. This is what I want:
<body>
<div>
</div>
</body>
From this sample code I have a click event bounded on the div and the body. I want the body event to be called first. How do I go about this?
Use event capturing instead:-
$("body").get(0).addEventListener("click", function(){}, true);
Check the last argument to "addEventListener" by default it is false and is in event bubbling mode. If set to true will work as capturing event.
For cross browser implementation.
var bodyEle = $("body").get(0);
if(bodyEle.addEventListener){
bodyEle.addEventListener("click", function(){}, true);
}else if(bodyEle.attachEvent){
document.attachEvent("onclick", function(){
var event = window.event;
});
}
IE8 and prior by default use event bubbling. So I attached the event on document instead of body, so you need to use event object to get the target object. For IE you need to be very tricky.
I'd do it like this:
$("body").click(function (event) {
// Do body action
var target = $(event.target);
if (target.is($("#myDiv"))) {
// Do div action
}
});
More generally than #pvnarula's answer:
var global_handler = function(name, handler) {
var bodyEle = $("body").get(0);
if(bodyEle.addEventListener) {
bodyEle.addEventListener(name, handler, true);
} else if(bodyEle.attachEvent) {
handler = function(){
var event = window.event;
handler(event)
};
document.attachEvent("on" + name, handler)
}
return handler
}
var global_handler_off = function(name, handler) {
var bodyEle = $("body").get(0);
if(bodyEle.removeEventListener) {
bodyEle.removeEventListener(name, handler, true);
} else if(bodyEle.detachEvent) {
document.detachEvent("on" + name, handler);
}
}
Then to use:
shield_handler = global_handler("click", function(ev) {
console.log("poof")
})
// disable
global_handler_off("click", shield_handler)
shield_handler = null;