I am trying to figure out why the following doesn't work.
I am setting a keydown event handler, and then triggering the event. But the handler doesn't detect it.
If anyone can enlighten me!
function onKeyDown(event)
{
alert('keydown');
}
document.addEventListener('keydown', onKeyDown, false);
var keydown = jQuery.Event('keydown', {which:38, keyCode:38});
$(document).keydown();
$(document).trigger(keydown);
jsfiddle: http://jsfiddle.net/4bf3z/
From http://api.jquery.com/trigger/, emphasis added:
Any event handlers attached with .on() or one of its shortcut methods
are triggered when the corresponding event occurs. They can be fired
manually, however, with the .trigger() method. A call to .trigger()
executes the handlers in the same order they would be if the event
were triggered naturally by the user.
So, it works as expected if you attach the handler with jQuery instead of pure javascript:
function onKeyDown(event)
{
alert('keydown');
}
$(document).on('keydown', onKeyDown); // <----
var keydown = jQuery.Event('keydown', {which:38, keyCode:38});
$(document).keydown();
$(document).trigger(keydown);
jQuery’s trigger only triggers jQuery-attached events. Triggering actual DOM events is trickier, and the keyboard events module is still a working draft:
var e = document.createEvent('KeyboardEvents');
e.initKeyboardEvent('keydown');
document.dispatchEvent(e);
The arguments to initKeyboardEvent are on MSDN. Firefox uses initKeyEvent.
Updated jsFiddle
Related
Is there a way to have keyup, keypress, blur, and change events call the same function in one line or do I have to do them separately?
The problem I have is that I need to validate some data with a db lookup and would like to make sure validation is not missed in any case, whether it is typed or pasted into the box.
You can use .on() to bind a function to multiple events:
$('#element').on('keyup keypress blur change', function(e) {
// e.type is the type of event fired
});
Or just pass the function as the parameter to normal event functions:
var myFunction = function() {
...
}
$('#element')
.keyup(myFunction)
.keypress(myFunction)
.blur(myFunction)
.change(myFunction)
As of jQuery 1.7, the .on() method is the preferred method for attaching event handlers to a document. For earlier versions, the .bind() method is used for attaching an event handler directly to elements.
$(document).on('mouseover mouseout',".brand", function () {
$(".star").toggleClass("hovered");
})
I was looking for a way to get the event type when jQuery listens for several events at once, and Google put me here.
So, for those interested, event.type is my answer :
$('#element').on('keyup keypress blur change', function(event) {
alert(event.type); // keyup OR keypress OR blur OR change
});
More info in the jQuery doc.
You can use bind method to attach function to several events. Just pass the event names and the handler function as in this code:
$('#foo').bind('mouseenter mouseleave', function() {
$(this).toggleClass('entered');
});
Another option is to use chaining support of jquery api.
Is there a way to have keyup, keypress, blur, and change events call the same function in one line?
It's possible using .on(), which accepts the following structure: .on( events [, selector ] [, data ], handler ), so you can pass multiple events to this method. In your case it should look like this:
$('#target').on('keyup keypress blur change', function(e) {
// "e" is an event, you can detect the type of event using "e.type"
});
And here is the live example:
$('#target').on('keyup keypress blur change', function(e) {
console.log(`"${e.type.toUpperCase()}" event happened`)
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="target">
If you attach the same event handler to several events, you often run into the issue of more than one of them firing at once (e.g. user presses tab after editing; keydown, change, and blur might all fire).
It sounds like what you actually want is something like this:
$('#ValidatedInput').keydown(function(evt) {
// If enter is pressed
if (evt.keyCode === 13) {
evt.preventDefault();
// If changes have been made to the input's value,
// blur() will result in a change event being fired.
this.blur();
}
});
$('#ValidatedInput').change(function(evt) {
var valueToValidate = this.value;
// Your validation callback/logic here.
});
This is how i do it.
$("input[name='title']").on({
"change keyup": function(e) {
var slug = $(this).val().split(" ").join("-").toLowerCase();
$("input[name='slug']").val(slug);
},
});
You could define the function that you would like to reuse as below:
var foo = function() {...}
And later you can set however many event listeners you want on your object to trigger that function using on('event') leaving a space in between as shown below:
$('#selector').on('keyup keypress blur change paste cut', foo);
The answer by Tatu is how I would intuitively do it, but I have experienced some problems in Internet Explorer with this way of nesting/binding the events, even though it is done through the .on() method.
I havn't been able to pinpoint exactly which versions of jQuery this is the problem with. But I sometimes see the problem in the following versions:
2.0.2
1.10.1
1.6.4
Mobile 1.3.0b1
Mobile 1.4.2
Mobile 1.2.0
My workaround have been to first define the function,
function myFunction() {
...
}
and then handle the events individually
// Call individually due to IE not handling binds properly
$(window).on("scroll", myFunction);
$(window).on("resize", myFunction);
This is not the prettiest solution, but it works for me, and I thought I would put it out there to help others that might stumble upon this issue
$("element").on("event1 event2 event..n", function() {
//execution
});
This tutorial is about handling multiple events.
It's simple to implement this with the built-in DOM methods without a big library like jQuery, if you want, it just takes a bit more code - iterate over an array of event names, and add a listener for each:
function validate(event) {
// ...
}
const element = document.querySelector('#element');
['keyup', 'keypress', 'blur', 'change'].forEach((eventName) => {
element.addEventListener(eventName, validate);
});
If you'd want to mimic adding to more than 1 element:
const elements = document.querySelectorAll('.commonSelector');
['keyup', 'keypress', 'blur', 'change'].forEach((eventName) => {
elements.forEach(element => {
element.addEventListener(eventName, validate);
});
});
Instead of:
$('#element').on('keyup keypress blur change', function(e) {
// e.type is the type of event fired
});
You can use:
$('#element').on('input', function(e) {
// e.type is the type of event fired
});
input is trigerred for keyup keypress blur change events even for paste!
But to prevent multiple triggering:
var a;
var foo = function() {
clearTimeout(a);
a=setTimeout(function(){
//your code
console.log("Runned")
},50);
}
$('textarea').on('blur change', foo);
I am using jQuery this._on() function for binding mouse event and I would like to use event capturing concept in this._on().
this._on($("#myId"), "mousedown", callMouseDown);
callMouseDown: function (e) {
//Mouse down event
},
Anyone can help me, here how to apply event capturing concept (parent to child).
Thanks,
Bharathi.
Use this to access your method.
this._on($("#myId"), "mousedown", this.callMouseDown);
callMouseDown: function (e) {
//Mouse down event
},
UPDATE:
jQuery events does not support event capturing. But it supports event bubbling.
Please check the following link for more information
Why does jQuery event model does not support event Capture and just supports event bubbling
I wonder how do I change the order of events.
Because I have to check when I took a focusOut with a click, if the click was inside the parent div, I can not let it happen the focusOut.
The problem, which is called first event focusOut the click event.
Is it possible to reverse the order of events? (Click - focusOut)?
http://jsfiddle.net/eL19p27L/5/
$(document).ready(function(){
$(".clean").click(function(){
$(".alert").html("");
});
$(document).on({
click: function(e){
$(".alert").append("<p>click</p>");
},
focusin: function(e){
$(".alert").append("<p>focusin</p>");
},
focusout: function(e){
$(".alert").append("<p>focusout</p>");
}
})
});
It would be even better. If I could detect what the event might turn out to generate the fucusout. Hence check if it happened within the parent div, if not a focusIn, it leaves not give a focusOut.
ATT
No, the way you have your event handler set up on a common parent, you can't change the order of the events.
But, you can attach your event handlers to the specific objects you want to watch and then you can see events for that object only.
Or, you can look at the target of the event and see which object is which and you will see that the focusOut event is on a different object than the click event.
You can see the source of the event with e.target.
Example of looking at the object that is the source of the event: http://jsfiddle.net/jfriend00/u5tLhes7/
I'm trying to use event.stopPropagation() within a ReactJS component to stop a click event from bubbling up and triggering a click event that was attached with JQuery in legacy code, but it seems like React's stopPropagation() only stops propagation to events also attached in React, and JQuery's stopPropagation() doesn't stop propagation to events attached with React.
Is there any way to make stopPropagation() work across these events? I wrote a simple JSFiddle to demonstrate these behaviors:
/** #jsx React.DOM */
var Propagation = React.createClass({
alert: function(){
alert('React Alert');
},
stopPropagation: function(e){
e.stopPropagation();
},
render: function(){
return (
<div>
<div onClick={this.alert}>
<a href="#" onClick={this.stopPropagation}>React Stop Propagation on React Event</a>
</div>
<div className="alert">
<a href="#" onClick={this.stopPropagation}>React Stop Propagation on JQuery Event</a>
</div>
<div onClick={this.alert}>
JQuery Stop Propagation on React Event
</div>
<div className="alert">
JQuery Stop Propagation on JQuery Event
</div>
</div>
);
}
});
React.renderComponent(<Propagation />, document.body);
$(function(){
$(document).on('click', '.alert', function(e){
alert('Jquery Alert');
});
$(document).on('click', '.stop-propagation', function(e){
e.stopPropagation();
});
});
React uses event delegation with a single event listener on document for events that bubble, like 'click' in this example, which means stopping propagation is not possible; the real event has already propagated by the time you interact with it in React. stopPropagation on React's synthetic event is possible because React handles propagation of synthetic events internally.
Working JSFiddle with the fixes from below.
React Stop Propagation on jQuery Event
Use Event.stopImmediatePropagation to prevent your other (jQuery in this case) listeners on the root from being called. It is supported in IE9+ and modern browsers.
stopPropagation: function(e){
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
},
Caveat: Listeners are called in the order in which they are bound. React must be initialized before other code (jQuery here) for this to work.
jQuery Stop Propagation on React Event
Your jQuery code uses event delegation as well, which means calling stopPropagation in the handler is not stopping anything; the event has already propagated to document, and React's listener will be triggered.
// Listener bound to `document`, event delegation
$(document).on('click', '.stop-propagation', function(e){
e.stopPropagation();
});
To prevent propagation beyond the element, the listener must be bound to the element itself:
// Listener bound to `.stop-propagation`, no delegation
$('.stop-propagation').on('click', function(e){
e.stopPropagation();
});
Edit (2016/01/14): Clarified that delegation is necessarily only used for events that bubble. For more details on event handling, React's source has descriptive comments: ReactBrowserEventEmitter.js.
It is still one intersting moment:
ev.preventDefault()
ev.stopPropagation();
ev.nativeEvent.stopImmediatePropagation();
Use this construction, if your function is wrapped by tag
Worth noting (from this issue) that if you're attaching events to document, e.stopPropagation() isn't going to help. As a workaround, you can use window.addEventListener() instead of document.addEventListener, then event.stopPropagation() will stop event from propagating to the window.
From the React documentation:
The event handlers below are triggered by an event in the bubbling phase. To register an event handler for the capture phase, append Capture. (emphasis added)
If you have a click event listener in your React code and you don't want it to bubble up, I think what you want to do is use onClickCapture instead of onClick. Then you would pass the event to the handler and do event.nativeEvent.stopPropagation() to keep the native event from bubbling up to a vanilla JS event listener (or anything that's not react).
I was able to resolve this by adding the following to my component:
componentDidMount() {
ReactDOM.findDOMNode(this).addEventListener('click', (event) => {
event.stopPropagation();
}, false);
}
React 17 delegates events to root instead of document, which might solve the problem.
More details here.
You can also refer to my blog.
I ran into this problem yesterday, so I created a React-friendly solution.
Check out react-native-listener. It's working very well so far. Feedback appreciated.
A quick workaround is using window.addEventListener instead of document.addEventListener.
Update: You can now <Elem onClick={ proxy => proxy.stopPropagation() } />
The way i've solved this is by adding an if statement at the callback that check the event.target and if its diferent to the element i expect, then return from the function
// Callback from my own app
function exitResultsScreen(event){
// Check element by ID
if (event.target.className !== sass.div__search_screen){return}
// Executed only when the right elements calls
setShowResults(false)
}
In my case e.stopPropagation() didn't work because child had onChange event, parent onClick. Got insight from another StackOverflow answer
The change and click events are different events.
Meagning:
e.stopPropagation() calling inside onChange won't prevent firing onClick.
Solution to have both onChange or onClick.
I want to do something like this:
function('string', function2(){})
where I leave the to user to write what he wants in the string parameter and than execute function2.
The catch is here: string is an event listener. When the user writes click, I want to call onClick(), when the user writes mouse I want to call onMouseOver and so on.
I have in mind doing something with case, but how can I access all event listeners?
You should use addEventListener.
element.addEventListener("string", function() {}, false);
However, in the case of IE <= 8, you will need to use attachEvent as it does not follow the standard:
element.attachEvent("string", function() {});
Finally, as kybernetikos mentions in his comment, you can then use a simple dictionary to map mouse to mouseover.
If you wish to fire events, you should use dispatchEvent.
If you add the event listeners using the old model (i.e. elem.onclick = function(){ /* */ };), you can use
elem['on' + event]();
Keep in mind that this only fires the event listeners, but doesn't create an event (e.g. it won't bubble).
If you won't to create a event, which fires event listeners added using addEventlistener, and bubbles, and does all things a real event does, you must
Create your event using event constructors: Event or CustomEvent
Fire it with dispatchEvent
See MDN page for more information and examples.
you can use .trigger to do this. Check out this example in jsfiddle. type "dblclick" in the input box.
http://jsfiddle.net/jspatel/Suj4H/1/
<input id="writehere"> </input>
$('#writehere').dblclick(function() {
alert ('dblclick');
});
$('#writehere').bind('keypress', function(e) {
if(e.keyCode==13){
$(this).trigger( $(this).val() );
}
});