Javascript has three events for key presses, keyup, keypress and keydown.
For some reason Sencha Touch only supports they keyup event. I want to catch the event (probably keydown or keypress) before it changes the value in the textfield. Catching the keydown event would make this possible, also it should be a lot faster. With keyup the effect is a bit slow.
Finally the goal is to allow the user to only enter number and add decimal and thousand separators automatically. That's currently possible with the keyup event, but slow. As a user you can see the text changing and then being changed again.
My code for adding the keydown event to the textfield:
initialize: function()
{
this.down('textfield[name=amountTotal]').onkeydown
= MyApp.app.getController('MyController').handleInput;
}
I've checked that when this code executes the textfield is found and the controller function does hold the correct function that I want to execute. I've also added the function to my view file.
Yet it won't reach my handleInput function.
I know Sencha does not support other events, but this should be possible with just pure Javascript.
You almost got it.
initialize: function() {
var textfield = this.down('textfield[name=amountTotal]');
textfield.bodyElement.dom.onkeydown = MyApp.app.getController('MyController').handleInput;
}
Fiddle: https://fiddle.sencha.com/#fiddle/caj
Related
Wondering if someone out there can shed some light on how to properly use element.triggerHandler() for the paste and keypress events inside of an angularjs unit test.
I have two directives, one for limiting the ability of a user to continue firing keypress events in an element once a length limit has been reached. The second is to prevent the user from pasting text into an element if the length of the text would exceed a limit.
See the following plunker for a full example including my failing tests: https://plnkr.co/edit/5Yyv2cnn3dRKzsj2Lj61?p=preview
For the paste test I know I'm not using the correct syntax but have been unable to find how to properly do this. Any suggestions?
element.triggerHandler('paste', 'astring')
For the keypress test, I believe I'm firing the event correctly but it doesn't seem to be updating the value of the element (retrieved using element.val())
Been stuck on this for a bit, any help would be greatly appreciated. Thanks!
Let's us start with a short breakdown of what might happen (really up to the browser implementation) when a user presses and releases the 1 key with the focus on an input:
Event keydown is fired
Event keypress is fired
Value of input is changed to 1 and event input is fired
Event keyup is fired
There is no way in JS to actually simulate a user pressing a key. What you can simulate are the things that (usually) happen when a user does so, for example the steps above.
The triggerHandler function executes all handlers bound with jQuery for the specified event type on the specific element.
So using triggerHandler with keypress will not simulate a user pressing a key, it will only fire the event, like step 2 above. The value will not be changed, since that happens in another step.
Now, one would think that in your tests for the limitKeypressLength directive, you can simply simulate the first part of step 3 above yourself (just setting the value manually):
for (var i = 0; i < 10; i++) {
element.triggerHandler({type: 'keypress', keyCode: 49});
element.val(element.val() + '1');
}
expect(element.val()).toBe('1111111111');
element.triggerHandler('keypress', {which: 49});
element.val(element.val() + '1');
expect(element.val()).toBe('1111111111');
This will not work however, since even if the eleventh keypress event is caught in your directive, the code below will still execute and update the value.
The basic functionality of the limitKeypressLength directive is to listen on the keypress event and either call event.preventDefault or not based. This is what you want to test.
For example:
// Set value to something longer than allowed
element.val('123456789123456789');
// Create the event
var e = jQuery.Event('keypress', {
keyCode: 49
});
// Create a spy
spyOn(e, 'preventDefault');
// preventDefault should not have been called yet
expect(e.preventDefault).not.toHaveBeenCalled();
// Trigger the event
element.triggerHandler(e);
// Assert that preventDefault has been called
expect(e.preventDefault).toHaveBeenCalled();
Demo: https://plnkr.co/edit/ktmcBGSuTdMnvqVRlkeQ?p=preview
Now you can as easily test for when the elements value is set to equal/below the allowed value.
Basically the same goes for the limitPasteLength directive, since its purpose is also to call preventDefault based on a condition, only that there is some additional mocking to do.
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.
I'm wondering if there's a way to capture the iPhone's virtual keyboard's done button event, using JavaScript?
Basically, I just want to be able to call a JS function when the user clicks done.
I was unable to track the 'done' button being clicked. It didn't register any clicks or keypresses. I had to addEventListeners for change, focusout and blur using jquery (because the project already was using jquery).
You need to do some kind of this:
$('someElem').focusout(function(e) {
alert("Done key Pressed!!!!")
});
It worked for me, hope it will help you as well.
After searching and trying this solution
basically is say:
document.addEventListener('focusout', e => {});
tested on IPhone 6s
This question is kinda old, but I've found a hacky way recently to make this working.
The problem with the 'blur', 'focusout' events is that they fire even if user just tapped outside the input/textarea, and did not press the 'Done' button, in my case, UI should behave differently depending on what exactly have happened.
So to implement it, I've done the next thing:
After showing the keyboard (the input received the focus), add click handler on the window via the addEventListener function. When user clicks on the window, remember the timestamp of the click in the variable (let's call it lastClick = Date.now())
In the blur event handler, set a timeout for 10-20 ms to allow other events happening. Then, after the timeout, check if the blur event happened in a time difference lower for example than 50-100 ms than the lastClick (basically Date.now() - lastClick < 50). If yes, then consider it as a 'Done' button click and do corresponding logic. Otherwise, this is a regular 'blur' event.
The key here is that tapping on keyboard controls (including Done button) does not trigger the click event on the window. And the only other way to make keyboard hide is basically tap on other element of the page and make the textarea lose focus. So by checking when the event happened, we can estimate whether that's a done button click or just blur event.
The answer by oron tech using an event listener is the only one that works cross platform.
document.getElementById("myID").addEventListener("focusout", blurFunction);
function blurFunction() { // Do whatever you want, such as run another function
const myValue = document.getElementById("myID").value;
myOtherfunction(myValue);
}
"Change" event works fine
document.querySelector('your-input').addEventListener('change',e=>
console.log('Done button was clicked')
);
attach a blur event to the text box in question. The done fire will fire this event.
The done key is the same as the enter key. So you can listen to a keypress event. I'm writing this using jQuery and i use it in coffee script so I'm trying to convert it back to js in my head. Sorry if there is an error.
$('someElem').bind("keypress", function(e){
// enter key code is 13
if(e.which === 13){
console.log("user pressed done");
}
})
I'm building a site that after the page is loaded, needs to listen for a particular keyboard string.
The event I am interested in is actually a scanner scanning an object, but it presents to the site as keyboard input, of the form ~XXX~.
I see jQuery has a keypress() event that you can bind to a particular object.
But how can I listen for general keyboard input, after $(document).ready?
Try this:
$(function() {
$(window).keypress(function(e) {
var key = e.which;
//do stuff with "key" here...
});
});
See it in action on jsFiddle
I've done this before. There are many other things to worry about besides how to handle keypress events.
Your scanner probably sends the input wrapped by a start and end characters. I would create a ScanReader object that attaches to the keypress event. Once it detects the start character, it starts accumulating the presses until the end character is detected.
To prevent it from getting confused with the user typing, the keypresses should be relatively close (in time) to each other, you need to test it out and see what a good number of ms between keypresses is. Fast typers can type as fast as 50ms in between key presses.
How can I reliably detect all events that cause the the value of an HTML select to change, while that element still has the focus?
For regular mouse input, either the click or change event works fine. For keyboard input (and for mouse input using the scroll wheel), however, the change event doesn't fire until focus is lost. I get around this by using the keyup event for keyboard changes (and ignoring the mouse wheel problem) but find my code is littered with a lot of stuff like this:
$(".my-select").keyup(handleSelect).change(handleSelect);
function handleSelect() {
var $this = $(this);
// don't process keyup events that don't result in change
if ($this.data('old-val') == $this.val()) { return; }
$this.data('old-val', $this.val());
// ... other stuff ...
}
Is there a simpler pattern/recipe that solves this problem (jQuery or straight JavaScript)?
"change" doesn't fire until the element loses focus, by design. What you're doing may be the only way to solve this. You can also look at selectedIndex as well as value.
As Diodeus said, the change event is fired when the element loses focus. But you could check if the pressed key is the enter key and then call your function. And I think hardly anybody uses the mouse wheel to change the value of a select box...