Change event precedence with JQuery - javascript

I have the following html code:
<input type="text" id="theInput" value=""/>
Click me
I want to detect when the input changes and perform an operation in this case, but ONLY when the user has not clicked in the link. I have tried this:
$('#theLink').live('click', function(){
alert('click');
});
$('#theInput').live('change', function(){
alert('change');
});
However change is always executed before click when the value in the input changed, due to Javascript event precedence rules, and therefore only "change" message is displayed.
I would like it to display change only if the input value changed and the user exited the input clicking in any other place instead of the link. In that last case I would like to display click.
The example is here.
I use jQuery 1.6.4.

As far as I know, the click event fires after the blur and change events in every browser (have a look at this JSFiddle). The order of blur and change is different across browsers (source: Nicholas Zakas).
To solve your problem, you could listen to click events on the document and compare the event's target with #theLink. Any click event will bubble up to the document (unless it is prevented).
Try this:
var lastValue = '';
$(document).click(function(event) {
var newValue = $('#theInput').val();
if ($(event.target).is('#theLink')) {
// The link was clicked
} else if (newValue !== lastValue) {
// Something else was clicked & input has changed
} else {
// Something else was clicked but input didn't change
}
lastValue = newValue;
});
JSFiddle: http://jsfiddle.net/PPvG/TTwEG/

Both events will fire but in your example the alert in the onchange event handler fired when the onmousedown event occurs will stop the onmouseup event required for the onclick event to fire. Using console.log will show both events firing.
http://jsfiddle.net/hTqNr/4/

Ok, now i got it, you could do
$('#theLink').live('click', function(e){
alert('click');
});
$('#theInput').live('change', function(e){
//Check if the change events is triggerede by the link
if(e.originalEvent.explicitOriginalTarget.data === "Click me"){
//if this is the case trigger the click event of the link
$('#theLink').trigger("click");
}else{
//otherwise do what you would do in the change handler
alert('change');
}
});
Fiddle here http://jsfiddle.net/hTqNr/19/

why you dont pick the value of input box. you have to store initial value of input box on ready function
initialvalue= $('#theInput').val();
then compare the value
$('#theLink').live('click', function(){
var newvalue =$('#theInput').val();
if(newvalue!=initialvalue) {
//do something
}
});

Related

Detecting the event that causes focus of HTML span tag

I need to determine the event that causes the focus of an HTML span tag. The span tag is a glyhpicon from bootstrap v3.
Right now, I have a .focus() event handler attached to the span tag to catch when the focus occurs but I can't figure out how to tell if the focus was caused by a click or a tab.
HTML tag: <span class="glyphicon glyphicon-ok-circle col-xs-6"></span>
Jquery:
$("span").focus(function (e) {
var event = "click" //This "event" var is the event that caused the focus
if(event == "click"){
//do something
}else{
//if not a click event, do something else
}
});
Do I use the eventData(e) parameter to detect this?
So far, I haven't been able to find the property that shows what caused the focus inside the eventData(e) parameter. The "originalEvent" property only returns "focus" and not what caused it.
Edit: The answer in Differentiate between focus event triggered by keyboard/mouse doesn't fulfill my question. That user is trying to find whether a click or keyboard event occurs on a jquery "autocomplete" element. I need to find the event that causes the focus on a span tag... not an input tag. The ".focus()" event of the element occurs before all other events.
Answer: Check my post below.
$('span').on('focus', function(e){
$( 'span' ).mousedown(function() {
alert( "focus using click" );
});
$(window).keyup(function (e) {
var code = (e.keyCode ? e.keyCode : e.which);
if (code == 9) {
// Using tab
}
});
});
I appreciate everyone's feedback! The answer suggested in the comments helped to partially solve the problem. However, I can't give full credit because it didn't fully answer the question.
The answer suggested in the link was to create a "click" and "keypress" event to update a flag that would be checked on the ".focus()" event to determine the source of how it was triggered. My scenario was more complex. The ".focus()" event occurs before a "click()" event... so the flags wouldn't trigger until after the focus has already occurred and passed. The answer also suggested using a "setTimeout()" to make the focus event wait.. which I found unnecessary in my conclusion.
Conclusion
After some research, it was apparent that a ".mousedown()" event occurs before the ".focus()" event. Using the binded flags listed in the suggested answer above, I created the code below to solve my problem.
$(document).bind('mousedown', function () { isClick = true; }).bind('keypress', function () { isClick = false; });
$("span").focus(function () {
if (isClick) {
//Focused by click event
} else{
//Focused by keyboard event
}
});
I also noticed during research that ".bind()" has been deprecated in Jquery v3.0... so I will be switching my code to read:
$(document).mousedown(function () { isClick = true; }).keypress(function () { isClick = false; });
$("span").focus(function () {
if (isClick) {
//Focused by click event
} else{
//Focused by keyboard event
}
});
Please add any comments/suggestions/optimizations as a comment to my answer! Would love to hear other input.

How to tell what triggered jQuery focus()?

I have an input field and a button. It is necessary that when the button is clicked the input field gets focus.
I need the behaviour to be slightly different depending on whether the input field was focused manually by the user or if it was focused due the button being clicked.
It seems this would be relatively simple, but I couldn't come up with a solution so far. Any ideas very welcome.
$("button").click(function() {
target_input = $("input");
target_input.focus();
});
$("input").focus(function() {
// if focus done manually by user
// do something
// if focus done via button
// do something else
});
Here is a solution that uses no extra variables, instead it checks the event.
$("button").click(function() {
target_input = $("input");
target_input.focus();
});
$("input").focus(function(e) {
// if focus done manually by user
// do something
// if focus done via button
// do something else
if(e.originalEvent.relatedTarget){
// only from button events
}
// here is from all events
});
this e.originalEvent.relatedTarget will return null if we didn't use the button to originate the focus.
remember to add e to the function.
You should be able to use Event.isTrusted for this:
The isTrusted read-only property of the Event interface is a boolean
that is true when the event was generated by a user action, and false
when the event was created or modified by a script or dispatched via
dispatchEvent.
$("input").focus(function(e) {
if(e.isTrusted) {...} else {...}
});
As noted in the comments, neither IE nor Safari like this.
This works without global variables and it is cross-browser working solution:
$('button').click(function () {
$(this).prev('input').focus()
})
$('input').click(function (e) { // yes, listen to click instead
// original event exists only if input was clicked directly
if (e.originalEvent) {
console.log('manually triggered')
}
})
<div style="background-color: yellow;">
<input type="text">
<button>Focus input</button>
<br>
<input type="text">
<button>Focus input</button>
</div>
<script src="https://unpkg.com/jquery"></script>

jQuery - detect change event triggered programmatically

I have a jQuery change event for when a user changes a given SELECT element. However the event may also be triggered by a third party script. What I want to do is detect whether the event was triggered programmatically or by the user.
I have tried the accepted solution in this question Check if event is triggered by a human
But note the JSFiddle in this answer is for a click event rather than a change event.
To demonstrate I amended the fiddle and created this one: http://jsfiddle.net/Uf8Wv/231/
If you try this in latest Firefox or Chrome, you will see that the alert human is being shown even when the event was triggered programmatically.
I have tried event.originalEvent.isTrusted but that doesn't work in all browsers. Can anyone help?
I have added mouseenter and mouseleave events. The idea is that it's a human if the click coincided with a mousepointer being over the element. See:
http://jsfiddle.net/Uf8Wv/232/
$("#try").mouseenter(function(event) {
mouseover = true;
});
// ... etc.
I can't think of any other way.
You can find some vague difference between click and emulated click using this code:
$(document).on('change', "#try", function (event) {
//some difference appear in the next line
console.log(event.delegateTarget.activeElement);
//no difference
if (event.originalEvent === undefined) {
alert('not human')
} else {
alert(' human');
}
event.delegateTarget = null;//doesn't help
});
$('#click').click(function (event) {
$("#try").click();
});
Click on the checkbox logs <input id="try" type="checkbox">.
Click on the button logs <button id="click">.
But...
Run $("#try").click(); from console before any clicks logs <body> and after the click result of the last click.
Generally JS can always fake any client event. So isTrusted is never trusted.
You can listen to the click event as well, and modify a variable. The change event seems indeed to be quite similar wheter it's a real click or a script triggered click, but the click on #try event won't be the same. And since click is triggered before change, you have time to set a switch.
Like this for example:
var realClick;
$("#try").change(function(event) {
console.log('change')
if (!realClick) {
alert('not human')
} else {
alert(' human');
}
});
$("#try").click(function(event) {
console.log('click')
// originalEvent is one way, but there will be many differences
if (event.originalEvent) {
realClick = true;
} else {
realClick = false;
}
});
// Since this is called from outside, better not put
// any controls here.
$('#click').click(function(event) {
$("#try").click();
});
http://jsfiddle.net/2xjjmo09/3/
What really worked for me is:
if ((event.originalEvent.isTrusted === true && event.originalEvent.isPrimary === undefined) || event.originalEvent.isPrimary === true) {
//Hey hooman it is you
//Real CLick
}
Tested with jQuery version 3.5
You can easily detect whether the click event on the button is actually triggered by mouse click or not. By doing,
$('#click').click(function(ev) {
if (ev.which !== undefined && ev.button !== undefined) {
$("#try").click();
}
});
Here's the Fiddle
Note: Beware of either ev.which or ev.button could result in 0 on some browser for left-click.
You can check for if event.srcElement (which is source element on which event is triggered) is equal to event.currentTarget something like:
$("#try").change(function(event) {console.log(event,event.target,event.currentTarget,event.srcElement)
if (event.currentTarget=== event.srcElement) {
alert(' human')
} else {
alert(' not human');
}
});
Fiddle: http://jsfiddle.net/Uf8Wv/234/

Stop onclick method running with jQuery

I have a button similar to below
<button id="uniqueId" onclick="runMethod(this)">Submit</button>
What I'm trying to do is stop the runMethod from running, until after I've done a check of my own. I've tried using the stopImmediatePropagation function, but this doesn't seem to have worked. Here's my jQuery:
$j(document).on('click', '#uniqueId', function(event) {
event.stopImmediatePropagation();
if(condition == true) {
// continue...
} else {
return false;
}
return false;
});
Note: runMethod basically validates the form, then triggers a submit.
What you want to do, especially in the way that you want to do it, requires a some sort of workaround that will always be a bit fiddly. It is a better idea to change the way the button behaves (e.g. handle the whole of the click event on the inside of the jQuery click() function or something along those lines). However I have found sort of a solution for your problem, based on the assumption that your user will first hover over the button. I am sure you can extend that functionality to the keyboard's Tab event, but maybe it will not work perfectly for mobile devices' touch input. So, bear in mind the following solution is a semi-complete workaround for your problem:
$(document).ready(function(){
var methodToRun = "runMethod(this)"; // Store the value of the onclick attribute of your button.
var condition = false; // Suppose it is enabled at first.
$('#uniqueId').attr('onclick',null);
$('#uniqueId').hover(function(){
// Check your stuff here
condition = !condition; // This will change to both true and false as your hover in and out of the button.
console.log(condition); // Log the condition's value.
if(condition == true){
$('#uniqueId').attr('onclick',methodToRun); // Enable the button's event before the click.
}
},
function(){
console.log('inactive'); // When you stop hovering over the button, it will log this.
$('#uniqueId').attr('onclick',null); // Disable the on click event.
});
});
What this does is it uses the hover event to trigger your checking logic and when the user finally clicks on the button, the button is enabled if the logic was correct, otherwise it does not do anything. Try it live on this fiddle.
P.S.: Convert $ to $j as necessary to adapt this.
P.S.2: Use the Javascript console to check how the fiddle works as it will not change anything on the page by itself.
Your problem is the submit event, just make :
$('form').on('submit', function(e) {
e.preventDefault();
});
and it works. Don't bind the button click, only the submit form. By this way, you prevent to submit the form and the button needs to be type button:
<button type="button" .....>Submit</button>
Assuming there's a form that is submitted when button is clicked.
Try adding
event.cancelBubble();
Hence your code becomes:
$j(document).on('click', '#uniqueId', function(event) {
// Don't propogate the event to the document
if (event.stopPropagation) {
event.stopPropagation(); // W3C model
} else {
event.cancelBubble = true; // IE model
}
if(condition == true) {
// continue...
} else {
return false;
}
return false;
});
Your code is mostly correct but you need to remove J:
$(document).on('click', '#uniqueId', function(event) {...
You also need to remove the onClick event from the inline code - there's no need to have it there when you're assigning it via jQuery.
<button id="uniqueId">Submit</button>

jQuery bind to keyup only, not focus

This seems like a simple thing but google hasn't turned up anything for me:
How can I bind to a text / value change event only, excluding an input gaining focus? Ie, given the following:
$(function(){
$('input#target').on('keyup', function(){
alert('Typed something in the input.');
});
});
...the alert would be triggered when the user tabs in and out of an element, whether they actually input text or not. How can you allow a user to keyboard navigate through the form without triggering the event unless they input/change the text in the text field?
Note: I'm showing a simplified version of a script, the reason for not using the change event is that in my real code I have a delay timer so that the event happens after the user stops typing for a second, without them having to change focus to trigger the event.
Store the value, and on any key event check if it's changed, like so:
$(function(){
$('input#target').on('keyup', function(){
if ($(this).data('val')!=this.value) {
alert('Typed something in the input.');
}
$(this).data('val', this.value);
});
});​
FIDDLE
Simply use the .change event.
Update: If you want live change notifications then do you have to go through the keyup event, which means that you need to program your handler to ignore those keys that will not result in the value being modified.
You can implement this with a whitelist of key codes that are ignored, but it could get ugly: pressing Del results in the value being changed, unless the cursor is positioned at the end of the input in which case it does not, unless there happens to be a selected range in the input in which case it does.
Another way which I personally find more sane if not as "pure" is to program your handler to remember the old value of the element and only react if it has changed.
$(function() {
// for each input element we are interested in
$("input").each(function () {
// set a property on the element to remember the old value,
// which is initially unknown
this.oldValue = null;
}).focus(function() {
// this condition is true just once, at the time we
// initialize oldValue to start tracking changes
if (this.oldValue === null) {
this.oldValue = this.value;
}
}).keyup(function() {
// if no change, nothing to do
if (this.oldValue == this.value) {
return;
}
// update the cached old value and do your stuff
this.oldValue = this.value;
alert("value changed on " + this.className);
});
});​
If you do not want to set properties directly on the DOM element (really, there's nothing wrong with it) then you could substitute $(this).data("oldValue") for this.oldValue whenever it appears. This will technically have the drawback of making the code slower, but I don't believe anyone will notice.
See it in action.
This will do it, set a custom attribute and check against that:
$('input').focus(function(){
$(this).attr('originalvalue',$(this).val());
});
$('input').on('keyup',function(){
if($(this).val()===$(this).attr('originalvalue')) return;
alert('he must\'ve typed something.');
});
Be wary of events firing multiple times.
Here is another version that plainly tests if the input field is empty.
If the input is empty then the action is not performed.
$(function(){
$(selector).on('keyup', function(){
if ($(this).val()!='') {
alert('char was entered');
}
})
});

Categories