I have the following Javascript code (with jQuery) on my web page -- the user types into a text field and the application does one thing if there's a value in the field and something else if the field is empty (because the user was pressing the delete or backspace key). The code that I have looks like this:
$('input#textInput').keyup( function(event) {
if($(this).val()) {
console.log('non-empty string in the text field');
}
else {
console.log('no text in the text field');
}
}
The problem is that it looks like the callback function executes before the character appears in the text field. So if the field is empty and I press the p key, what seems to occur is the keydown, keypress, and keyup events are generated, the keyup callback function gets executed and 'no text in the text field' gets logged, and then the 'p' character appears in the text field, which isn't what I want.
Does anyone know how I can execute a callback on any of the key events and access the value that would appear in the text field?
You could set a timeout:
$('input').keyup(function() {
var inp = this;
setTimeout(function() {
console.log(inp.value);
}, 0);
});
The input event should do roughly what you want. It fires after the value changes and is supported on most modern browsers.
https://developer.mozilla.org/en-US/docs/Web/Events/input
Related
I want to automate the login process on a website.
This website login page has a username <input> field with id="username", and type="email", and a password <input> field with id="pwd", and type="password", and a submit button <input> field with id="login", and type="submit".
This website has some built-in JavaScript that handle the keyboard keydown/keyup/input events, they validate the entered characters in the username input field, so that the entered characters must be of xxx#xxx format before initiating the login request.
In my script, I first tried this using jQuery:
$("#username").val("me#hotmail.com");
$("#pwd").val("ticket");
$("#login")[0].click();
This can correctly populate the username field with "me#hotmail.com", but the problem with this approach is the validation code in the built-in script does not get triggered, thus the login failed.
Then I tried these by simulating entering these characters, "a#h":
$('#username').trigger(jQuery.Event('keydown', {KeyCode: 97}));
$('#username').trigger(jQuery.Event('keyup', {KeyCode: 97}));
$('#username').trigger(jQuery.Event('keydown', {KeyCode: 64}));
$('#username').trigger(jQuery.Event('keyup', {KeyCode: 64}));
$('#username').trigger(jQuery.Event('keydown', {KeyCode: 104}));
$('#username').trigger(jQuery.Event('keyup', {KeyCode: 104}));
I can see that these events get triggered successfully by adding event listeners on this field,
$("#username" ).on( "keydown", function(e) { console.log(' key downed: ' + (e.which || e.KeyCode ) ); });
$("#username" ).on( "keyup", function(e) { console.log(' key upped: ' + (e.which || e.KeyCode ) ); });
I can see the log messages, then I removed the above listeners, because they would overwrite the website built-in event handlers on this input field.
When I ran the above code, I can NOT visually see "a#h" in the input although these events get triggered successfully based on the log messages, and the login still failed.
I was testing this on the Chrome browser, I opened the Chrome debugging tools, and enabled Keyboard/keydown/keyup events breakpoint in the "Event Listener Breakpoints" pane. But when I ran the code, those breakpoints did not break, so the built-in validation code did not execute, thus the login still failed.
My question is this:
How do I code the event triggering logic, so that when those events get triggered, the website built-in event handler could be executed, plus, I can visually see those entered characters in the uesrname input field, just as if the computer has been hacked, and you are watching the hacker entering characters into the input field in real-time.
I searched google and came up with the following from other relevant StackOverflow answers:
https://stackoverflow.com/a/2220234/5076162 by Max Shawabkeh
https://stackoverflow.com/a/17881330/5076162 by Paul S.
I take no credit for their work, only that I merged the two methods with a little bit on ingenuity. So please up vote their work before you accept my answer.
Working jsfiddle example: Test Typed automatically
jQuery.fn.simulateKeyPress = function (character) {
// Internally calls jQuery.event.trigger
// with arguments (Event, data, elem). That last arguments is very important!
jQuery(this).trigger({ type: 'keypress', which: character.charCodeAt(0) });
};
jQuery(document).ready(function ($) {
// Bind event handler
$('textarea').keypress(function (e) {
//alert(String.fromCharCode(e.which));
console.log(String.fromCharCode(e.which));
var initialVal = $(this).text();
var newVal = initialVal.toString() + String.fromCharCode(e.which);
$(this).text(newVal);
console.log("New Value: " + newVal);
//String.fromCharCode(e.which)
});
// Simulate the key press
$('textarea').on('focus', function(e) {
//this could have been done with a for loop or the jQuery $.each() method by utilizing strings and arrays.
$(this).simulateKeyPress('t');
$(this).simulateKeyPress('e');
$(this).simulateKeyPress('s');
$(this).simulateKeyPress('t');
});
$('textarea').focus();
});
There's a .checkValidity() API on HTML5 form fields you can use for this purpose. Fill it in with .val() as you were, and the call the checkValidity method on the raw DOM node to trigger the browser's built-in handling. More info: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Forms_in_HTML
I tried these at Chrome console:
document.getElementById("i0116").value = "h#hotmail.com"
document.getElementById("i0118").value = "123456"
document.getElementById("i0116").checkValidity();
document.getElementById("idSIButton9").click();
Although, checkValidity() returns true, the keydown/up events handler in the site script are still not triggered, the login still failed, it reports error "Please enter your phone number or your email address in the format someone#example.com".
There has to be a way I can programmatically simulate key presses in the input to trigger the validation script.
The site I'm testing is https://login.live.com, the username input has a default overlay of "Email or phone" text on it.
document.getElementById("i0116").value = "h#hotmail.com" would just overlap "Email or phone" with another layer of text "h#hotmail.com" into the input field.
Open "https://login.live.com/" in Chrome, you will see what I mean.
I have a checkout form where a zipcode is needed. I need this zipcode to get a LocationID. The zipcodes are in 0000XX format but i just need the first 4 digits. Now i have made a (global) javascript to get the locationID trough ajax.
The only problem is that now im using a keyup function that is activated when someone types in a zipcode. But i want it to be activated when a user has typed in something and clicks on another field. how can i do this ?
$('#deliveryzip').bind('keyup change', function(){
//Get zip
var zip = $('#deliveryzip').val();
//Strip first 4 chars from input
//check if 4 chars are integer
//if all ok do ajax...
//Get locationID from zipcode
$.post(jssitebaseUrl+'/ajaxFile.php',{"zip":zip,"action":"getLocInfo"},function(response){
if(response == "ok"){
alert(response);
//If return is ok..
var show = true;
}
});
if(show){
$('#locInfo').show();
} else {
$('#locInfo').hide();
}
return false;
});
Instead of listening to the keyup event, why don't you just listen to the change event?
$('#deliveryzip').on('change', function(){....});
The change event fires when an input field changed and once it looses focus (e.g. through the user clicking on another element). See http://msdn.microsoft.com/en-us/library/ie/ms536912(v=vs.85).aspx for more info (from Microsof) and here the documentation from Mozilla https://developer.mozilla.org/en-US/docs/Web/Reference/Events/change
You can use onBlur function : http://www.w3schools.com/jsref/event_onblur.asp
The onblur event occurs when an object loses focus.
Onblur is most often used with form validation code (e.g. when the user leaves a form field).
Tip: The onblur event is the opposite of the onfocus event.
With jQuery : on( "blur", handler )
Change 'keyup change' to blur
Blur is essentially the opposite of focus
Documentation here
I have the following input element on my page:
<input class="input" name="custom_fields[new]" placeholder="Enter placeholder" type="text">
I have a Twitter Flight event listener on this element that looks like this:
this.on('keyup', {
inputsSelector: this.updateViewInputs
});
Which triggers this method:
this.updateViewInputs = function(ev) {
var isDeletionKeycode = (ev.keyCode == 8 || ev.keyCode == 46);
// Remove field is user is trying to delete it
if (isDeletionKeycode && this.shouldDeleteInput(ev.target.value, this.select('inputsSelector').length)) {
$(ev.target.parentNode).remove();
}
// Add another field dynamically
if (this.select('lastInputsSelector')[0] && (ev.target == this.select('lastInputSelector')[0]) && !isDeletionKeycode) {
this.select('inputsContainer').append(InputTemplate());
}
// Render fields
that.trigger('uiUpdateInputs', {
inputs: that.collectInputs()
});
}
And finally triggers uiUpdateInputs:
this.after('initialize', function() {
this.on(document, 'uiUpdateInputs', this.updateInputs)
});
this.updateInputs = function(ev, data) {
// Render all inputs provided by user
this.select('inputListSelector').html(InputsTemplate({ inputs: data.inputs }));
}
All of this functionality works as expected on Chrome and Firefox. Users can type into the input and see the page change in 'real time'. Users also get additional fields that they can enter text into and see the page change.
The issue in question arises when using Safari, as a user enters text into the described input field the text in the input field becomes highlighted (selected) and when they enter the next character all the content is replaced with that single character. This results in the user not being able to enter more than 1 or 2 characters before having them all replaced by the next entered character.
I have tried several approaches to fix this problem but none have worked, they include:
Using a setTimeout to delay the code run on the keyup event
Using Selection to try to disable the selection of the text using collapseToEnd.
Using click,focus,blur events to try to remove the selection from the entered text
Triggering a right arrow key event to try to simply move the cursor forward so they user does not delete the selected text
Using setInterval to routinely remove selections made by the window
I am very confused why this is happening and I am wondering if this is a bug in webkit with Flight. I see no issue with the Firefox or Chrome versions of this page. Thanks for any help!
This seems to be an issue with certain versions of Safari. When listening for the keyup function in javascript it will automatically select all of the text in the box and subsequently delete it all when the next key is typed. To prevent this from happening call preventDefault on the event object that is passed to the keyup function.
this.on('keyup', function(e) {
e.preventDefault()
});
I have an input element in this jsfiddle: http://jsfiddle.net/stevea/DLe3a/9. If I enter Return after putting something in the field I trigger the change handler and pick up and display the value fine:
$(function() {
$('input#fname').change(function(e) {
$('div#firstName').append(this.value);
});
But what if the user forgets to hit return and closes down the page? I want to come back, in that case, when I sense the page shutting down, and pull out what was entered into the Input field without a Return.
Can I do that? In the jsfiddle I have a button and its handler. Assuming the button click is shutting down the page, how would I respond to the button click to get the value sitting in the input field?
Thanks
Try this sir
$(function() {
$("#fname").change(function(e) {
$("#firstName").append(this.value)
});
$("#getInput").click(function (e) {
});
});
To detect if the page is closing, use the .unload() event
$(window).unload(function() {
var input = $('#fname').val();
});
I believe that you want to do some code when the window is pre-closed.
Here is some sample code: jsDiddle
$('#fname').change(function () {
$('#firstName').append(this.value);
});
window.onbeforeunload = function (e) {
var e = e || window.event;
// get input #fname
$('#firstName').append($('#fname').val());
// do something you want before the window closes
// show confirm message (optional) - if you don't want show message, return '';
//IE & Firefox
if (e) {
e.returnValue = 'You have some unfilled inputs!';
}
// For Safari
return 'You have some unfilled inputs!';
};
The problem isn't detecting a page closing down. The problem is to capture an Input field's content when something external happens before the user enters Return. But after playing around with it more, at this jsfiddle - http://jsfiddle.net/stevea/bT54M/3/ - it turns out that there really is no problem. If you're in the middle of entering text into an Input field and you do something external, like hitting the Get Input button in the jsfiddle above, the change event for the Input is triggered automatically and this.value is what you've entered so far. So the bottom line is that you don't need to hit Return when you're done. Just about anything you do outside of the Input (probably anything that blurs the Input focus) triggers the Input change event.
$(function() {
$('input#fname').change(function(e) {
debugger;
$('div#firstName').append(this.value);
});
$('#getInput').click(function() {
debugger;
$('div#firstName').append(this.value);
});
});
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');
}
})
});