I want to be able to listen to <input type="number" /> step UP (increment) and step down events with jQuery. (currently I can only understand how to listen to change event)
For input type="number", you can use the change event, but will possibly have more cases to handle and create some clutter. I broke it down, I recommend using the "mouseup" event for the increment feature (which will mainly be used from pc) But if the user uses a device instead, I would use the event 'keyup' since the increment feature will not appear and the user will have an on-screen keyboard instead. The change event will listen for both.
For example :
$(".counter").bind('mouseup', function () {
if($(this).val() == undefined || $(this).val() == "")
return; /* Exit dont bother with handling this later, if its not needed leave. */
/* Important Check against integers and not strings. */
/* Comparing against arrays will give unexecpted behavior, size is different then the value. */
var newVal = parseInt($(this).val());
var oldVal = parseInt($(this).data('old-value'));
if (oldVal < newVal) {
alert('incrementing');
}
else{
alert('decrementing');
}
$(this).data('old-value', $(this).val());
});
$(".counter").bind('keyup', function () {
/* Similar logic */
});
I use "bind" instead of "on" or the by method "change" since "on" is a shorthand for bind.
JSFiddle Demo
There is no event for up and down. You can use change event
$(".counter").change(function () {
alert($(this).val());
})
DEMO
You can try something like, You can store previous value and compare with currently value and identify up or down
$(".counter").change(function () {
if ($(this).data('old-value') < $(this).val()) {
alert('Alert up');
} else {
alert('Alert dowm');
}
$(this).data('old-value', $(this).val());
})
DEMO
I'm not sure if there is a listener of the stepUp and StepDown but you can externalize the PLUS and LESS buttons of the input number using:
document.getElementById("myNumber").stepUp(5); //increase the value +5
document.getElementById("myNumber").stepDown(5); // decrease the value -5
So you can finally achieve your objective!
Reference: https://www.w3schools.com/jsref/met_number_stepup.asp
NOTE: Be aware that IE11 and EDGE doesn't implement stepUp / stepDown. On my case I just remove the + and - icon and leave only the input number field. Hope EDGE die soon...
I know this is a relatively old question but, came across it in my search.
In case anyone comes here looking for the answer to this on a custom element triggering the stepUp() or stepDown() like me and not wanting to use jQuery, the below should help:
On the element handling the click to trigger the stepUp()/stepDown(), add this (and change the elements to whatever relation they have to each other):
onclick="this.elementToStepDown.stepDown();this.elementToStepDown.dispatchEvent(new Event('change'))"
Fuller example:
<input class="input--hide_controls" id="number_of_ducks" type="number" value="7" step="1"/>
<div class="increment" onclick="this.parentNode.querySelector('input').stepUp();this.parentNode.querySelector('input').dispatchEvent(new Event('change'))"><i class="im im-plus"></i></div>
Or, extract it out and put it in a JS function that does the same and call that onclick:
let increment = (element) => {
element.stepUp();
element.dispatchEvent(new Event('change'))
}
let decrement = (element) => {
element.stepDown();
element.dispatchEvent(new Event('change'))
}
Then listen out for the 'change' event on the input.
There's no specific event for up and down. Your closest bet is to use the change event. You might also take a look at the oninput event but I am not sure it is supported by all browsers:
$('#myinput').on('input', function() {
});
You should do this:
var $counter = $("your_counter");
var number = $counter.val();
$counter.change(function () {
if($counter.val() > number)
alert('up');
else
alert('down');
number = $counter.val();
});
Here is the demo: http://jsfiddle.net/6bb8S/
html
<input type="number" data-number="0" class="counter" value="0" />
you need to put the same value in the data-number and in the value
jquery
$(document).on('change', '.counter', function() {
//get number of input
var number = $(this).attr("data-number");
//console.log(number);
if($(this).val() > number){
alert('up');
}else{
alert('down');
}
//set number of input for the next step
$(this).attr("data-number", $(this).val());
});
https://jsfiddle.net/maicon_card/46hdm8pj/
works with multiple inputs
Related
GOAL:
When a user types character in a text box, make a button appear. When the user clears the text box using the backspace key but holds down that key for a few extra seconds, hide the button instantly.
ISSUE:
If a user types in a single character, and uses the backspace to remove it—by holding down the backspace key a few extra seconds—there is a delay before the button is hidden. This only happens when the user typed only one character and then held down the the backspace key without letting go. If instead the user typed multiple characters, and then held down the backspace key until the textbox was empty, there was no delay in hiding the button.
<input type="text" id="tbox"></text>
<button type="button" id="btn" style="display:none;">push me</button>
$('#tbox').on('keydown keypress keyup',function(){
if($('#tbox').val() !== '') {
$('#btn').css({'display':'block'});
} else {
$('#btn').css({'display':'none'});
}
});
JSFIDDLE:
http://jsfiddle.net/odkut0dh/
A little walkthrough the situation :
Assuming that <input> value is "x" and you type backspace :
- When the keydown event fires the input's value is still "x".
- When the keypress fires, it still "x".
If you don't release the key :
__ keydown fires again, after some delay, depending on os I guess value is now "".
__ keypress fires again, value is still "".
__ When you release the key, keyup fires, value is "".
If you do release the key :
__ keypress fires directly, value is "".
The solution For IE10+ is to use the input event which will fire when the textEditable element's content has changed or, as suggested by #Mayhem, the change event, which won't even listen for key inputs and has a better browser support than input
$('#tbox').on('input change',function(e){
if($('#tbox').val() !== '') {
$('#btn').css({'display':'block'});
} else {
$('#btn').css({'display':'none'});
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="tbox"></text>
<button type="button" id="btn" style="display:none;">push me</button>
As i've aleady made comments on this one, did a quick google and came across this post which might make it a little easier.. Detect all changes to a <input type="text"> (immediately) using JQuery
So i put it into a fiddle here for you to test: Slight Modded Version
The HTML
<input type="text" value="Some Value" id="text1" />
<button id="btn1">Click Me</button>
The JS
$('#text1').each(function() {
var elem = $(this);
elem.data('oldVal', elem.val());
elem.bind("propertychange change click keyup input paste", function(event){
if (elem.data('oldVal') != elem.val()) {
if (elem.val().length == 0 ) {
$("#btn1").hide();
} else {
$("#btn1").show();
}
elem.data('oldVal', elem.val());
}
});
});
As i dont have to much time to break this code down into sections... By the looks of it.. You dont need the elem.data... Just the bind event...
... ah seems i decided to shorten the code for you...
http://jsfiddle.net/z2ew3fqz/3/
Using the same HTML...
Shortest version i could make from the example given above
The HTML
<input type="text" value="Some Value" id="text1" />
<button id="btn1">Click Me</button>
The JS
$('#text1').bind("propertychange change click keyup input paste", function(event){
if ($(this).val().length == 0 ) {
$("#btn1").hide();
} else {
$("#btn1").show();
}
});
I've quickly tested this on chrome.. mouse/function keys all seem to affect it correctly... Other browsers i'll leave upto the OP to test.. Let me know if any issues in a particular browser..
IE10 seems to be the min support for this .. IE9 might be able to have a js prototype done.. But how important is this for support in your project? to support IE<10?
The Problem is that $('#tbox').val(); is not empty ('') when backspace is pressed. So You have to delay the value check.
When you press down the key, the first thing what happend is that the keydown event is fired, then after that the key action will be performed on the input field.
$('#tbox').on('keydown keypress keyup',function(){
setTimeout(function () {
if($('#tbox').val() !== '') {
$('#btn').css({'display':'block'});
} else {
$('#btn').css({'display':'none'});
}
},0);
});
You can prevent repeating keydown by control it on key up by an global variable:
var allow = true;
$(document).on('keydown', function(e) {
if (e.repeat != undefined) {
allow = !e.repeat;
}
if (!allowed) return;
allowed = false;
if($('#tbox').val() !== '') {
$('#btn').css({'display':'block'});
} else {
$('#btn').css({'display':'none'});
}
});
$(document).keyup(function(e) {
allowed = true;
});
I want to run a function when a user edits the content of a div with contenteditable attribute. What's the equivalent of an onchange event?
I'm using jQuery so any solutions that uses jQuery is preferred. Thanks!
2022 update
As pointed out in the comments, this doesn't answer the question asked, which wanted the equivalent of the change event rather than the input event. However, I'll leave it here as is.
Original answer
I'd suggest attaching listeners to key events fired by the editable element, though you need to be aware that keydown and keypress events are fired before the content itself is changed. This won't cover every possible means of changing the content: the user can also use cut, copy and paste from the Edit or context browser menus, so you may want to handle the cut copy and paste events too. Also, the user can drop text or other content, so there are more events there (mouseup, for example). You may want to poll the element's contents as a fallback.
UPDATE 29 October 2014
The HTML5 input event is the answer in the long term. At the time of writing, it is supported for contenteditable elements in current Mozilla (from Firefox 14) and WebKit/Blink browsers, but not IE.
Demo:
document.getElementById("editor").addEventListener("input", function() {
console.log("input event fired");
}, false);
<div contenteditable="true" id="editor">Please type something in here</div>
Demo: http://jsfiddle.net/ch6yn/2691/
Here is a more efficient version which uses on for all contenteditables. It's based off the top answers here.
$('body').on('focus', '[contenteditable]', function() {
const $this = $(this);
$this.data('before', $this.html());
}).on('blur keyup paste input', '[contenteditable]', function() {
const $this = $(this);
if ($this.data('before') !== $this.html()) {
$this.data('before', $this.html());
$this.trigger('change');
}
});
The project is here: https://github.com/balupton/html5edit
Consider using MutationObserver. These observers are designed to react to changes in the DOM, and as a performant replacement to Mutation Events.
Pros:
Fires when any change occurs, which is difficult to achieve by listening to key events as suggested by other answers. For example, all of these work well: drag & drop, italicizing, copy/cut/paste through context menu.
Designed with performance in mind.
Simple, straightforward code. It's a lot easier to understand and debug code that listens to one event rather than code that listens to 10 events.
Google has an excellent mutation summary library which makes using MutationObservers very easy.
Cons:
Requires a very recent version of Firefox (14.0+), Chrome (18+), or IE (11+).
New API to understand
Not a lot of information available yet on best practices or case studies
Learn more:
I wrote a little snippet to compare using MutationObserers to handling a variety of events. I used balupton's code since his answer has the most upvotes.
Mozilla has an excellent page on the API
Take a look at the MutationSummary library
non jQuery quick and dirty answer:
function setChangeListener (div, listener) {
div.addEventListener("blur", listener);
div.addEventListener("keyup", listener);
div.addEventListener("paste", listener);
div.addEventListener("copy", listener);
div.addEventListener("cut", listener);
div.addEventListener("delete", listener);
div.addEventListener("mouseup", listener);
}
var div = document.querySelector("someDiv");
setChangeListener(div, function(event){
console.log(event);
});
I have modified lawwantsin 's answer like so and this works for me. I use the keyup event instead of keypress which works great.
$('#editor').on('focus', function() {
before = $(this).html();
}).on('blur keyup paste', function() {
if (before != $(this).html()) { $(this).trigger('change'); }
});
$('#editor').on('change', function() {alert('changed')});
Two options:
1) For modern (evergreen) browsers:
The "input" event would act as an alternative "change" event.
https://developer.mozilla.org/en-US/docs/Web/Events/input
document.querySelector('div').addEventListener('input', (e) => {
// Do something with the "change"-like event
});
or
<div oninput="someFunc(event)"></div>
or (with jQuery)
$('div').on('click', function(e) {
// Do something with the "change"-like event
});
2) To account for IE11 and modern (evergreen) browsers:
This watches for element changes and their contents inside the div.
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
var div = document.querySelector('div');
var divMO = new window.MutationObserver(function(e) {
// Do something on change
});
divMO.observe(div, { childList: true, subtree: true, characterData: true });
const p = document.querySelector('p')
const result = document.querySelector('div')
const observer = new MutationObserver((mutationRecords) => {
result.textContent = mutationRecords[0].target.data
// result.textContent = p.textContent
})
observer.observe(p, {
characterData: true,
subtree: true,
})
<p contenteditable>abc</p>
<div />
Here's what worked for me:
var clicked = {}
$("[contenteditable='true']").each(function(){
var id = $(this).attr("id");
$(this).bind('focus', function() {
// store the original value of element first time it gets focus
if(!(id in clicked)){
clicked[id] = $(this).html()
}
});
});
// then once the user clicks on save
$("#save").click(function(){
for(var id in clicked){
var original = clicked[id];
var current = $("#"+id).html();
// check if value changed
if(original != current) save(id,current);
}
});
This thread was very helpful while I was investigating the subject.
I've modified some of the code available here into a jQuery plugin so it is in a re-usable form, primarily to satisfy my needs but others may appreciate a simpler interface to jumpstart using contenteditable tags.
https://gist.github.com/3410122
Update:
Due to its increasing popularity the plugin has been adopted by Makesites.org
Development will continue from here:
https://github.com/makesites/jquery-contenteditable
Non JQuery answer...
function makeEditable(elem){
elem.setAttribute('contenteditable', 'true');
elem.addEventListener('blur', function (evt) {
elem.removeAttribute('contenteditable');
elem.removeEventListener('blur', evt.target);
});
elem.focus();
}
To use it, call on (say) a header element with id="myHeader"
makeEditable(document.getElementById('myHeader'))
That element will now be editable by the user until it loses focus.
In Angular 2+
<div contentEditable (input)="type($event)">
Value
</div>
#Component({
...
})
export class ContentEditableComponent {
...
type(event) {
console.log(event.data) // <-- The pressed key
console.log(event.path[0].innerHTML) // <-- The content of the div
}
}
To avoid timers and "save" buttons, you may use blur event wich fires when the element loses focus. but to be sure that the element was actually changed (not just focused and defocused), its content should be compared against its last version. or use keydown event to set some "dirty" flag on this element.
Here is the solution I ended up using and works fabulously. I use $(this).text() instead because I am just using a one line div that is content editable. But you may also use .html() this way you dont have to worry about the scope of a global/non-global variable and the before is actually attached to the editor div.
$('body').delegate('#editor', 'focus', function(){
$(this).data('before', $(this).html());
});
$('#client_tasks').delegate('.task_text', 'blur', function(){
if($(this).data('before') != $(this).html()){
/* do your stuff here - like ajax save */
alert('I promise, I have changed!');
}
});
You need to use input event type
Demo
HTML
<div id="editor" contenteditable="true" >Some text here</div>
JS
const input = document.getElementById('editor');
input.addEventListener('input', updateValue);
function updateValue(e) {
console.log(e.target);
}
know more
The onchange event doesn't fires when an element with the contentEditable attribute is changed, a suggested approach could be to add a button, to "save" the edition.
Check this plugin which handles the issue in that way:
Creating a quick and dirty jQuery contentEditable Plugin
Using DOMCharacterDataModified under MutationEvents will lead to the same. The timeout is setup to prevent sending incorrect values (e.g. in Chrome I had some issues with space key)
var timeoutID;
$('[contenteditable]').bind('DOMCharacterDataModified', function() {
clearTimeout(timeoutID);
$that = $(this);
timeoutID = setTimeout(function() {
$that.trigger('change')
}, 50)
});
$('[contentEditable]').bind('change', function() {
console.log($(this).text());
})
JSFIDDLE example
I built a jQuery plugin to do this.
(function ($) {
$.fn.wysiwygEvt = function () {
return this.each(function () {
var $this = $(this);
var htmlold = $this.html();
$this.bind('blur keyup paste copy cut mouseup', function () {
var htmlnew = $this.html();
if (htmlold !== htmlnew) {
$this.trigger('change')
}
})
})
}
})(jQuery);
You can simply call $('.wysiwyg').wysiwygEvt();
You can also remove / add events if you wish
A simple answer in JQuery, I just created this code and thought it will be helpful for others too
var cont;
$("div [contenteditable=true]").focus(function() {
cont=$(this).html();
});
$("div [contenteditable=true]").blur(function() {
if ($(this).html()!=cont) {
//Here you can write the code to run when the content change
}
});
For me, I want to check the input is valid or not.
If valid, then update, Otherwise show an error message and keep the value as same as before.
Skill: When you edit done, usually, it will trigger the blur event.
Example
<span contenteditable="true">try input somethings.</span>
<script>
const elem = document.querySelector(`span`)
let oldValue = elem.innerText
elem.onkeydown = (keyboardEvent) => {
if (keyboardEvent.key === "Enter") {
elem.blur() // set focusout
}
}
elem.onblur = (e) => {
const curValue = elem.innerText
if (curValue === oldValue) {
return
}
if (curValue.length <= 50) { // 👈 Input your conditions.
// 👇 fail
elem.innerText = oldValue
// (Optional) Add error message
elem.insertAdjacentHTML("beforeend", `<span style="margin-left:5px;color:red">error length=${curValue.length}. Must greater than 50. undo to the previous value.</span>`)
const errMsg = elem.querySelector(`span`)
setTimeout(() => errMsg.remove(), 3500) // wait 3.5 second, and then remove it.
return
}
// 👇 OK, update
oldValue = curValue
}
</script>
Check this idea out.
http://pastie.org/1096892
I think it's close. HTML 5 really needs to add the change event to the spec. The only problem is that the callback function evaluates if (before == $(this).html()) before the content is actually updated in $(this).html(). setTimeout don't work, and it's sad. Let me know what you think.
Based on #balupton's answer:
$(document).on('focus', '[contenteditable]', e => {
const self = $(e.target)
self.data('before', self.html())
})
$(document).on('blur', '[contenteditable]', e => {
const self = $(e.target)
if (self.data('before') !== self.html()) {
self.trigger('change')
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I want to be able to listen to <input type="number" /> step UP (increment) and step down events with jQuery. (currently I can only understand how to listen to change event)
For input type="number", you can use the change event, but will possibly have more cases to handle and create some clutter. I broke it down, I recommend using the "mouseup" event for the increment feature (which will mainly be used from pc) But if the user uses a device instead, I would use the event 'keyup' since the increment feature will not appear and the user will have an on-screen keyboard instead. The change event will listen for both.
For example :
$(".counter").bind('mouseup', function () {
if($(this).val() == undefined || $(this).val() == "")
return; /* Exit dont bother with handling this later, if its not needed leave. */
/* Important Check against integers and not strings. */
/* Comparing against arrays will give unexecpted behavior, size is different then the value. */
var newVal = parseInt($(this).val());
var oldVal = parseInt($(this).data('old-value'));
if (oldVal < newVal) {
alert('incrementing');
}
else{
alert('decrementing');
}
$(this).data('old-value', $(this).val());
});
$(".counter").bind('keyup', function () {
/* Similar logic */
});
I use "bind" instead of "on" or the by method "change" since "on" is a shorthand for bind.
JSFiddle Demo
There is no event for up and down. You can use change event
$(".counter").change(function () {
alert($(this).val());
})
DEMO
You can try something like, You can store previous value and compare with currently value and identify up or down
$(".counter").change(function () {
if ($(this).data('old-value') < $(this).val()) {
alert('Alert up');
} else {
alert('Alert dowm');
}
$(this).data('old-value', $(this).val());
})
DEMO
I'm not sure if there is a listener of the stepUp and StepDown but you can externalize the PLUS and LESS buttons of the input number using:
document.getElementById("myNumber").stepUp(5); //increase the value +5
document.getElementById("myNumber").stepDown(5); // decrease the value -5
So you can finally achieve your objective!
Reference: https://www.w3schools.com/jsref/met_number_stepup.asp
NOTE: Be aware that IE11 and EDGE doesn't implement stepUp / stepDown. On my case I just remove the + and - icon and leave only the input number field. Hope EDGE die soon...
I know this is a relatively old question but, came across it in my search.
In case anyone comes here looking for the answer to this on a custom element triggering the stepUp() or stepDown() like me and not wanting to use jQuery, the below should help:
On the element handling the click to trigger the stepUp()/stepDown(), add this (and change the elements to whatever relation they have to each other):
onclick="this.elementToStepDown.stepDown();this.elementToStepDown.dispatchEvent(new Event('change'))"
Fuller example:
<input class="input--hide_controls" id="number_of_ducks" type="number" value="7" step="1"/>
<div class="increment" onclick="this.parentNode.querySelector('input').stepUp();this.parentNode.querySelector('input').dispatchEvent(new Event('change'))"><i class="im im-plus"></i></div>
Or, extract it out and put it in a JS function that does the same and call that onclick:
let increment = (element) => {
element.stepUp();
element.dispatchEvent(new Event('change'))
}
let decrement = (element) => {
element.stepDown();
element.dispatchEvent(new Event('change'))
}
Then listen out for the 'change' event on the input.
There's no specific event for up and down. Your closest bet is to use the change event. You might also take a look at the oninput event but I am not sure it is supported by all browsers:
$('#myinput').on('input', function() {
});
You should do this:
var $counter = $("your_counter");
var number = $counter.val();
$counter.change(function () {
if($counter.val() > number)
alert('up');
else
alert('down');
number = $counter.val();
});
Here is the demo: http://jsfiddle.net/6bb8S/
html
<input type="number" data-number="0" class="counter" value="0" />
you need to put the same value in the data-number and in the value
jquery
$(document).on('change', '.counter', function() {
//get number of input
var number = $(this).attr("data-number");
//console.log(number);
if($(this).val() > number){
alert('up');
}else{
alert('down');
}
//set number of input for the next step
$(this).attr("data-number", $(this).val());
});
https://jsfiddle.net/maicon_card/46hdm8pj/
works with multiple inputs
NEW Fiddle: http://jsfiddle.net/martinnormark/jBZfs/14/ - new isolated example. See how the change event is not fired for Amount 2! **
I have a jQuery plugin for formatting a number in a currency format, as you type.
You can see it in action in this fiddle: http://jsfiddle.net/martinnormark/Rv4Ug/1/
The problem is, if you enter a value of at least 4 digits (causing the need to thousand separator: 1178 becomes 1,178), the change event dies. As long as you stay below 4 digits, not causing a new format, the change event is fired.
In the fiddle, try to enter 12, then 123. You should see a text reading 'change event raised'. And then enter 1234 - and the change event is not fired.
This will have something to do with the manipulation of the input element's value in a keyup event handler:
$this.on("keyup.autoformatcurrency", function(event) {
if ($.inArray(event.keyCode, keyCodes) > -1) {
formatCurrency($(this), true);
}
});
And the formatCurrency function:
function formatCurrency($this, setCaretPosition) {
var rawValue = $this.val(),
floatValue = Globalize.parseFloat(rawValue);
if ($.isNumeric(floatValue)) {
var formattedValue = Globalize.format(floatValue, settings.formatString),
caretPosition = 0;
if (setCaretPosition) {
caretPosition = $this.caret().end + (formattedValue.length - rawValue.length);
}
$this.val(formattedValue);
if (setCaretPosition) {
$this.caret(caretPosition, caretPosition);
}
}
}
(for full source, see the file on Github: https://github.com/martinnormark/jquery-format-currency/blob/master/src/jquery.formatcurrency.js )
The question is, if there's a way to make sure the change event will be fired?
UPDATE - Current state in browsers
Chrome: Change event fired, if number is below 4 digits.
Safari, IE: Change event is never fired, as long the value is set programmatically. Enter letters instead of numbers will trigger the change event.
Firefox: Works!
Opera: Works!
The easiest way would be, to trigger the change event from within the keyup function:
$this.on("keyup.autoformatcurrency", function(event) {
if ($.inArray(event.keyCode, keyCodes) > -1) {
formatCurrency($(this), true);
$(this).change();
}
});
I'm using jquery ui autocomplete and want to decipher between focus events triggered by keyboard interaction and mouse interaction. How would I go about this?
$('input').autocomplete({
source: function(request, response) {
...
},
focus: function(event, ui) {
// If focus triggered by keyboard interaction
alert('do something');
// If focus event triggered by mouse interaction
alert('do something else');
}
});
Thanks
The only way I can think of doing this is to have a handler listen in on the keypress and click events, and toggle a boolean flag on/off. Then on the focus handler of your input, you can just check what the value of your flag is, and go from there.
Probably something like
var isClick;
$(document).bind('click', function() { isClick = true; })
.bind('keypress', function() { isClick = false; })
;
var focusHandler = function () {
if (isClick) {
// clicky!
} else {
// tabby!
}
}
$('input').focus(function() {
// we set a small timeout to let the click / keypress event to trigger
// and update our boolean
setTimeout(focusHandler,100);
});
Whipped up a small working prototype on jsFiddle (don't you just love this site?). Check it out if you want.
Of course, this is all running off a focus event on an <input>, but the focus handler on the autocomplete works in the same way.
The setTimeout will introduce a bit of lag, but at 100ms, it might be negligible, based on your needs.
You should actually be able to determine this from the event-Object that is passed into the focus-event. Depending on your code structure this might be different, but there is usually a property called originalEvent in there, which might be nested to some depth. Examine the event-object more closely to determine the correct syntax. Then test on mousenter or keydown via regular expression. Something like this:
focus: function(event, ui){
if(/^key/.test(event.originalEvent.originalEvent.type)){
//code for keydown
}else{
//code for mouseenter and any other event
}
}
The easiest and most elegant way I've found of achieving this is to use the "What Input?" library. It's tiny (~2K minified), and gives you access to the event type both in scripts:
if (whatInput.ask() === 'mouse') {
// do something
}
...and also (via a single data attribute that it adds to the document body) styles:
[data-whatinput="mouse"] :focus,
[data-whatinput="touch"] :focus {
// focus styles for mouse and touch only
}
I particularly like the fact that where you just want a different visual behaviour for mouse / keyboard it makes it possible to do that in the stylesheet (where it really belongs) rather than via some hacky bit of event-checking Javascript (though of course if you do need to do something that's not just purely visual, the former approach lets you handle it in Javascript instead).
The first thing that comes to mind is that you can find the position of the mouse and check to see if its within the position of the element
Use this to store the position of the element:
var input = $('#your_autocompleted_element_id'),
offset = input.offset(),
input_x = offset.top,
input_y = offset.left,
input_w = input.outerWidth(),
input_h = input.outerHeight();
Then use this to find absolute position of the mouse within the window:
var cur_mx, cur_my;
$(document).mousemove(function(e){
cur_mx = e.pageX;
cur_my = e.pageY;
});
Then in your autcomplete setup:
focus: function(event, ui) {
// mouse is doing the focus when...
// mouse x is greater than input x and less than input x + input width
// and y is greater than input y and less than input y + input height
if (cur_mx >= input_x && cur_mx <= input_x + input_w && cur_my >= input_y && cur_my <= input_y + input_h) {
// do your silly mouse focus witchcraft here
} else {
// keyboard time!
}
}
This can be handled using mousedown event, see my example below.
this.focusFrom = 'keyboard' =>
onFocus = () => {
if (this.focusFrom === 'keyboard') {
// do something when focus from keyboard
}
}
handleMouseDown = () => {
this.focusFrom = 'mouse';
}
handleOnClick = () => {
this.focusFrom = 'keyboard';
}