A ChromeOS device puts up a virtual keyboard when you select in an input.
Inside my angular component I have an input
control bound to a property:
<input type="text" ng-model="$ctrl.searchText" />
I want this to work via a touch screen. If I click in the control, the touch screen keyboard appears.
I press the touch keys and the letters appear in the input, but the set searchText
method doesn't get called until the text box loses focus.
If I plug in a USB keyboard and enter text, the set searchText
method gets called with every new character. It just fails with the onscreen touch keyboard.
I tried setting different options using ngModelOptions:
<input type="text" ng-model="$ctrl.searchText" ng-model-options="{updateOn: 'keyup keydown default blur click touch touchup touchdown'}" />
This does not change the behavior.
http://embed.plnkr.co/bIwMp88BB8gNHFenayfz/
I notice some things that are different about the chrome onscreen keyboard:
keyup
event fires with the key
value sets to unidentified.compositionstart
, compositionupdate
, but seems to be flakey around the compositionend
event.When I enter the 'a' key via the keyboard, the following events are fired:
| Event type | data | Input Field |
|-------------------|------|-------------|
| keydown | | '' |
| keypress | | '' |
| beforeinput | 'a' | '' |
| input | 'a' | 'a' |
| keyup | | 'a' |
When I enter the 'a' key using the touch screen, the following events are fired. These are the same events, but with the added compositionstart
, compositionupdate
events.
| Event type | data | Input Field |
|-------------------|------|-------------|
| keydown | | '' |
| compositionstart | | '' |
| beforeinput | 'a' | '' |
| compositionupdate | 'a' | '' |
| input | 'a' | 'a' |
| keyup | | 'a' |
It needs to fire the compositionend
event. But it doesn't!
The composition
events are very significant in the angular code. The relevant code is in input.js, where it defers any handling until the compositionend
event:
// In composition mode, users are still inputting intermediate text buffer,
// hold the listener until composition is done.
// More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
if (!$sniffer.android) {
var composing = false;
element.on('compositionstart', function() {
composing = true;
});
// Support: IE9+
element.on('compositionupdate', function(ev) {
// End composition when ev.data is empty string on 'compositionupdate' event.
// When the input de-focusses (e.g. by clicking away), IE triggers 'compositionupdate'
// instead of 'compositionend'.
if (isUndefined(ev.data) || ev.data === '') {
composing = false;
}
});
element.on('compositionend', function() {
composing = false;
listener();
});
}
//....
var listener = function(ev) {
// ...
if (composing) return;
// ...
}
I have submitted this as a defect to google:
Entering character with on-screen keyboard fails to trigger 'compositionend' event
The quick answer: add the attribute autocorrect='off'
to the input element.
https://bugs.chromium.org/p/chromium/issues/detail?id=818881
Here is the response from the chrome development team:
This is by design. Same behavior on Android with Android keyboard apps. The composition text in the case in the video recording is "a" with the underline effect. "compositionend" event will appear after the underlined text is committed by, e.g. SPACE key.
In your application, if you don't want IME/VK to set composition text in your input field, please set the attribute "autocorrect=false" [sic] to the input element or content editable element.