want to create a password field where I want to check for capsLock on/off on keystroke. Once a user enters a value in smallcase and try to another field want to validate the password value. Thus want to use onkeypress for every key pressed and then onblur at the end.
But the problem I am facing is every time onkeypress is checked onblur is also executed.
<input type="password" size=50 id='r5PswFld' name="name" value="" onkeypress="checkCapsLock(event)" onblur=chkPsw(this.id) >
can anyone help me how to attain this.
thanks in advance...
better if I am able to do this using only javascript/html/css I me no other technologies like jquery...
This event is getting fired because you in checking the other checkbox input, you are blurring focus away from the current control.
Attach the onblur at the start your checkCapsLock(event) :
document.getElementById("r5PswFld").onblur = function(chkPsw(this.id)'){};
If you find yourself having to perform an action that will focus away, detach it:
document.getElementById("r5PswFld").onblur = function(){};
Next time you fire checkCapsLock it will reacttach if you need to. You could then also remove the onblue attribute completely from your code.
That said, be careful of any onblur validation. If is obtrusive (like an alert) then it could quickly get very frustrating for the user.
EDIT
In repose to the comment below, I thought I'd correct for the problem of other blur bindings. I'll use jQuery for preference.
The correct solution would look something like:
function MyBlurFunc(){
chkPsw(this.id);
}
To bind:
$("#r5PswFld").blur(MyBlurFunc);
To unbind
$("#r5PswFld").unbind('blur', MyBlurFunc);
Unfortunately, onblur will get called whenever focus is left from the field, meaning if you open some sort of message box informing the user of having capslock on, you're removing focus and thus trigger the onblur event.
An alternative might be to activate a flag which you assign to be true prior to opening a message box so that in the case in which you enter chkPsw, you can ignore it.
In other words:
var flgEventsOff = false;
function checkCapsLock(event) {
if (fieldValueIsUpper) {
flgEventsOff = true;
alert('Please turn off capslock!');
flgEventsOff = false;
}
}
function chkPsw(id) {
if(!flgEventsOff) {
// Validate password
}
}
No, the blur event won't be executed the same time a keyPress event is fired. I assume you have an alert() statement within your checkCapsLock() event handler, which causes the loss of focus.
Why would you not just change it to lowecase on the onblur event before it validates?
Related
I have a form with two input elements that are somewhat intertwined. In element#1 (element #2 is right after element#1 in the tabindex order), once the user tries to leave that field, I run an ajax call to check if the value entered is already in the database and if so, use the javascript confirm dialog to ask the user a question. The second element, upon gaining focus, automatically pops up a modal window with choices the user can make. I am using Jquery.
I would like to run the "Does this data exist" ajax call as soon as the user leaves the first element. the Blur event seemed to be what I wanted as this existing data check is needed whether the user made a change or not.
My problem using blur, though, is that its handler runs AFTER the first element loses focus and focus jumps to element#2. So, the blur handler from element #1 pops up the confirm screen at the same time element #2's focus handler pops up the choices modal and I now have 2 popups open at the same time.
I would like to give the user the chance to answer the question in the confirmation alert before the choices for the element#2 pop up.
Is there a Jquery event similar to blur, but that runs just BEFORE focus is actually lost? Or, is there a way to prevent the next element from gaining focus until the blur handler from the first element completes?
Trying to stop propagation or preventDefault() in the Blur handler does nothing because the focus on element#2 has already happened before the blur handler runs.
I've tried setting the tabindex of element#2 to -1 and then programmatically focusing on that element when needed, but tabbing away from this element becomes a problem, and reverse tabbing skips it (jumping straight to element#1) - I still want that element in tabindex ordering, but just don't want it to gain focus until element#1 completes its handler that needs to run when it loses focus.
I have tried setting status variables as well but when I add code to handle the transition between the two elements, I end up with similar issues and it presents additional edge cases complexity. I've also tried messing with mousedown and keydown events and trying to prevent the default processing, but that added significant complexity and room for error as well.
Any ideas would be welcome. Thank you.
This solution is a bit of a hack, but accomplishes your goal. The trick is to place what amounts to a "no-op" element that accepts the focus on blur. Then controlling the tab after the AJAX request.
Upon each "blur" event, we test to ensure we capture the correct <input> element (I'll leave those details to you).
After the AJAX request has completed, then focus on the next <input>.
For this demo, type 2 in the second input, then tab. I added a short delay so you can see that it works.
$("input").on('blur', function(e){
if(this.value == 2) {
console.log("do ajax request");
setTimeout((function(){
$(this).next().next('input').focus();
}).bind(this), 500);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input tabindex="1" />
<input tabindex="2" />
<div tabindex="3"></div>
<input tabindex="3" />
Would something like this do the trick?
Have a variable that indicates if it's okay to show the second popup
let allowSecondPopup = true;
Have a variable that indicates whether showing the second popup was postponed
let secondPopupPostponed = false;
Set the variable when the first input receives focus
$("#input1").on("focus", fuction () {
allowSecondPopup = false;
});
Send ajax on blur
$("#input1").on("blur", function () {
//$("#input1").disabled(true);
//$("#input2").disabled(true);
$.post("https://example.com", { }, fuction (response) {
if (secondPopupPostponed) {
// Only show second popup after the ajax-call has finished
showSecondPopup();
allowSecondPopup = true;
secondPopupPostponed = false;
}
});
});
And when the second input receives focus, check the variable
$("#input2").on("focus", fuction () {
if (allowSecondPopup) {
showSecondPopup();
} else {
// We're still waiting for the ajax-call to complete.
// When the ajax-call completes, the callback will show the second popup.
secondPopupPostponed = true;
}
});
So, I have a simple question and I actually already wrote it in the title. :) But I will repeat it one more time, just to be completely clear. And the questions is:
Is there a way to know if "blur" was called by "element.blur()" or if it was "actual" blur? By saying "actual" I mean, clicking on some random area to make input lose focus, or by clicking TAB. :)
Of course. You should attach the blur event to the specific element you want.
An example would be:
<input id="myInput" type="text" />
function handleBlur(event){
console.log(event.target); // outputs: <input id="myInput" type="text">
}
document.getElementById('myInput').addEventListener('blur', handleBlur);
This function will only be called when blur event occurs for that input only. Nevertheless, you could use event.target to see the element that triggered the blur event.
EDIT:
Tested only on Chrome, but the following achieves what you are requesting.
<input id="myInput" type="text" />
function handleBlur(event){
if(event.sourceCapabilities !== null){
console.log('blur by user');
}
else{
console.log('blur programmatically')
}
}
var elem = document.getElementById('myInput');
elem.addEventListener('blur', handleBlur);
elem.focus();
elem.blur();
Try it online on jsfiddle.
Since each browser handles event differently though, my suggestion is to trigger a different, custom event to handle this case.
ooooo there's 2 different types of blur, one is an event called blur or onBlur for jQuery users which is for 'out of focus' basically the user clicks it and then clicks somewhere else. That's onBlur. Another is blur the CSS filter value for the filter property.
So! There's a few ways to see if an element is 'out of focus' one is like this:
var blur = true;//we start off not focused
element.addEventListener('blur', function() {
blur = true;
});
element.addEventListener('focus', function() {
blur = false;
});
So basically the above is "If it's not focused we are blured, if we are out of focus we blur". (Feel I'm making this more complicated to understand?). Try using element.blur() and element.focus() in the console and see what happens!
Another method is simply to check that the active element (focused element) is not your element.
document.getActiveElement.id !== element.
In jQuery there is a :focus prop you can use in the selector like so $('element:focus') which is also handy for :checked to get a checked radio button $('input[type="radio"]:checked')
Unfortunately though I don't think there's a way to see if another tab has been click. There probably is a way but in my experience, I had previously made a JS clock which I added to the title which appears as the tab's name. It didn't update when the tab was not opened so I think there's probably some more voodoo to look at to run your JS when the page is not in focus
I have a search field that triggers an autocomplete search while typing. I have it trigger on keyup. This works perfectly in most browsers, but in Firefox on Android, this does not work. It seems like the keyup event is not triggered while typing. This only happens if word suggestions is turned on in the Android keyboard settings.
I see on Google search that the autocomplete search works there for the same setup, so it is obviously possible to do. I wonder how? Is it a special event I need to listen to for this to work?
Additionally I have tried to listen to the events change, keydown and keypress, but none is triggered.
HTML:
<input type="text" id="searchField"
autocomplete="off" spellcheck="false" autocorrect="off" />
jQuery event binding:
$('#searchField').keyup(function (e) {
var searchValue = $(this).val();
searchApi._executeAutocomplete(searchValue);
});
Note:
Sometimes, the key event is triggered, which is typically hitting a key that is not resulting in the process of forming a word. The most obvious here is Enter, which always triggers. Another is Space, which triggers because no word contain a space since space is the definition of a word completed. Backspace triggers if the the last character deleted was not within a word. This means it triggers if you just deleted the last remaining letter of a word (so it is the start of the field, or cursor following a space), but not if you deleted some characters at the end of a word where the cursor is still immediately following a letter. Basically, the key event is not triggered if the key press results in some kind of word suggestion from the keyboard app.
As a side note, I can say that everything works fine in Chrome on the same device.
You can use the input event instead, that worked for me in Firefox on Android.
You could bind event handlers to both input and keyup events for backwards compatibility, but in most modern browsers this will fire both:
$('#searchField').bind('input keyup', function(e){
var searchValue = $(this).val();
searchApi._executeAutocomplete(searchValue);
});
Example here:
http://jsfiddle.net/JQ928/3/
I found a solution in this answer to another question. The question was a basically "duplicate the text I write dynamically into another part of the page". The answer was including support for catching changes by non-keyboard actions, like pasting text using mouse. It was solved by starting a sniffer on focus in the text field that checks if the value has changed using setInterval(...). It clears the timer on blur.
This solved my problem which was basically that the key events didn't trigger, as well as the "paste by mouse" issue that I didn't realize was a problem until I found this answer...!
This works, but I'm not sure I am totally happy with this solution, because it uses a sniffer. I would be more happy with using some sort of event that is triggered on value change no matter what the cause of the change is. Using the change event would not work, as that is not triggered until focus leaves the field.
Trough the fact that Firefox on Android doesn't trigger key-events, but also triggers the input-event some kind of weird, (like if you press one key two events get triggerd, and it also triggers the input-event if you leave the input) I had to write my own event:
(function($){
var $event = $.event,
$special = $event.special.fennecInput = {
setup: function(){
$(this).on('input',$special.handler);
},
teardown: function(){
$(this).off('input',$spceial.handler);
},
handler: function(event) {
var context = this,
args = arguments,
dispatch = function() {
event.type='fennecInput';
$event.dispatch.apply(context,args);
};
if($(context).val() != $(context).attr('data-fennecInput-oldval')){
dispatch();
$(context).attr('data-fennecInput-oldval',$(context).val());
}
}
};
})(jQuery);
this event gets only triggered if an input-event happens that changes the value, so it doesn't execute events unnecessary.
Ok, so we all know that onChange is used to execute javascript code on a select statement when the option changes. However, if you change a select statement using the arrow keys, the onChange event is not called. Is there a way around this? Please help! I'm OCD I know.
--EDIT 1--
Just tested this in IE and arrow keys do work. Apparently it's just Chrome. ** Goes to check firefox
-- Edit 2 --
Tested in Firefox and realized just before an answer below talked about the onBlur action being required for the change. So the answer here is:
Internet Explorer recognizes onChange events from the keyboard as well as clicking on them.
Firefox and Chrome both require key events to be followed by blur event in order to call onChange.
Now normally, I don't like Internet Explorer, because it's a piece of garbage... But I think I... unfortunately, have to say they got that one right.
My understanding as to the reasoning for the blur event on chrome and firefox is to save resources, but I disagree with that. I feel it should follow the literal interpretation of the command onChange... Sigh... I suppose I'm probably wrong somehow, though.
I would suggest you to write the required code in Key Up event to capture the Key press and and also check for Key Code. Hope this helps
Scrolling through a select box is not considered a change. The change happens when you blur() the select and the new option value is applied to the select element.
Coming back to this, it appears that since the asking of this question, Chrome now fires onChange after key events. Firefox appears to still wait for onblur. http://jsfiddle.net/2aQBN/
$(document).ready(function() {
$("#test").on("change", function() {
console.log("Changed.");
});
});
W3C Specification appears to suggest using an input event instead.
When the input event applies, any time the user causes the element's
value to change, the user agent must queue a task to fire a simple
event that bubbles named input at the input element.
However, no input event appears to fire in Chrome or Firefox for the select element. (Just input elements.)
Test demonstrating the current value vs the last onchange value.
http://jsfiddle.net/teynon/MpyHK/5/
Firefox will change the value onmouseover. The key change will change the value as well. However, the onchange hasn't fired. If the form submits while the user has the select menu open, the currently highlighted option is submitted.
From W3C:
If the multiple attribute is absent, and the element is not disabled,
then the user agent should allow the user to pick an option element in
its list of options that is itself not disabled. Upon this option
element being picked (either through a click, or through unfocusing
the element after changing its value, or through a menu command, or
through any other mechanism), and before the relevant user interaction
event is queued (e.g. before the click event), the user agent must set
the selectedness of the picked option element to true and then queue a
task to fire a simple event that bubbles named change at the select
element, using the user interaction task source as the task source.
There is a LONG discussion at https://bugzilla.mozilla.org/show_bug.cgi?id=126379 about this with many people asking for the arrow keys to work. (And some defending the onchange approach.)
Some users have suggested that the W3C is flat out wrong in the specification for the select element's change event. Instead suggesting we propose changes to the specification for how we expect the select's onchange functionality to work.
The current functionality is clearly not intuitive to a large number of people based solely on the number of bug reports. (Mozilla has 40 marked as duplicates.)
This is a pretty dirty hack, but you can force the the change event to fire by doing this:
element.addEventListener('keyup', function(evt){
evt.target.blur();
evt.target.focus();
}, false);
So you'd register an event listener for change as well, and that function would get called when the user presses a key on the <select> via the code above.
You may want to scope this only to Firefox, but AFAIK you'd have to use UA sniffing for that so it's up to you if that's acceptable.
Source
I'm thinking about something like this (to not trigger event if value wasn't changed):
select.keydown(function(){
var _this = $(this);
var _val = $(this).val();
setTimeout(function(){
if(_this.val() !== _val){
_this.trigger("change");
}
}, 1);
});
Here's a realization of this request. For brevity only showing the code. See https://github.com/ida/skriptz/blob/master/js/fields/select/selection_changed.js for long explanations in comments.
function addSelectionChangedListener(selectionEle, onChangeDoWithEle) {
var selectedIndex = null
function onChangeEvent(eve) {
// If selection-change was caused of an option's click-event:
if(eve.explicitOriginalTarget.tagName.toLowerCase() == 'option') {
// We want to trigger passed event-handler:
onChangeDoWithEle(eve.target)
}
}
function onKeyEvent(eve) {
// Key-event is keydown, remember current selectedIndex:
if(eve.type == 'keydown') {
selectedIndex = eve.target.selectedIndex
}
// Key-event is keyup, if selection changed, trigger passed handler:
else if(selectedIndex != eve.target.selectedIndex) {
onChangeDoWithEle(eve.target)
}
}
selectionEle.onchange = function(eve) onChangeEvent(eve)
selectionEle.onkeydown = function(eve) onKeyEvent(eve)
selectionEle.onkeyup = function(eve) onKeyEvent(eve)
}
This is driving me nuts. Its a tough one to explain but I'll have a go.
I have one input text field on the front page of my site. I have coded a keydown event observer which checks the keyCode and if its ENTER (or equiv), itll check the input value (email). If the email is valid and unique in the DB itll submit the form. Basic stuff, or so you would think.
If I type my email address in the field and hit enter, it works fine in all browsers. However, if I type the first couple of letters, and then use the arrow keys to select the email from the history dropdown box (hope you know what I mean here), and then press enter the result is different. The value of the form field is being captured as just the couple of letters I typed, and therefore the validation is failing. It seems that when I press the enter key to "select" the email from the history dropdown, the browser is interrupting that as if I was typing.
In Chrome and Safari it works as it should. As it should means that when you press enter to "select" the email from the history dropdown, all it does is puts that email address into the text box. Only on the second ENTER key press does it then trigger the event observer, and the email is validated.
Hope somebody can shed some light on why this is happening... My gut feeling is its a browser thing and will be something I cant fix.
Thanks
Lee
EDIT:
To add clarification to my question let me add that Im using the "keydown" event to capture the moment when the enter key is pressed. I have tried the "keyup" event and this solved my problem above, but then I cant seem to stop the form submitting by itself. The "keyup" event triggers AFTER the default behaviour, therefore its not the right choice for this.
FURTHER EDIT:
Thank you again, and btw, your English is excellent (in response to your comment about bad English).
I have changed my event handler from this:
$("emailInputBox").observe("keydown", function(event) {
return submitViaEnter(event, submitSignupFormOne);
});
to this:
$("emailInputBox").observe("keydown", function(event) {
setTimeout(submitViaEnter.curry(event, submitSignupFormOne),0);
});
submitViaEnter:
function submitViaEnter(event, callback) {
var code = event.keyCode;
if (code == Event.KEY_RETURN) {
event.stop();
return callback(event);
}
return true;
}
Seems to work but the problem now is that the browser is permitted to carry out the default action before running the submitViaEnter function which means the form is being submitted when I hit ENTER.
Answer to the original question
Yeah, it's a Gecko bug (not Mac-specific though).
The last part of this comment contains the description of the work-around: use the time-out.
[edit] since you asked for the clarification of the bug
When you press Enter and the auto-complete is active, Firefox (erroneously) first fires the page's key handler, then the browser's internal key handler that closes the autocomplete popup and updates the text area value, while it arguably should just fire it at the autocomplete popup and only let the page know the textbox value changed.
This means that when your key handler is called, the autocomplete's handler hasn't run yet -- the autocomplete popup is still open and the textbox value is like it was just before the auto-completion happened.
When you add a setTimeout call to your key handler you're saying to the browser "hey, run this function right after you finished doing stuff already in your P1 to-do list". So the autocomplete's handler runs, since it's already in the to-do list, then the code you put on a time-out runs -- when the autocomplete popup is already closed and the textbox's value updated.
[edit] answering the question in "Further edit"
Right. You need to cancel the default action in the event handler, not in the timeout, if you want it to work:
function onKeyPress(ev) {
if (... enter pressed ...) {
setTimeout(function() {
... check the new textbox value after letting autocomplete work ...
}, 0);
// but cancel the default behavior (submitting the form) directly in the event listener
ev.preventDefault();
return false;
}
}
If you still wanted to submit the form on Enter, it would be a more interesting exercise, but it doesn't seem you do.
ok sorted it. Thanks so much for your help. It was the curry function that I was missing before. I was trying to work on the event inside the scope of the setTimeout function.
This works below. The submitViaEnter is called from the eventobserver and responds to the keyDown event:
function submitViaEnter(event, callback) {
var code = event.keyCode;
if (code == Event.KEY_RETURN) {
event.stop();
setTimeout(callback.curry(event),0);
// return callback(event);
// return false;
}
return true;
}
Stopping the default action inside the eventObserver meant that no characters could be typed. So I stuck inside the if ENTER key clause.