Skip to content

fix(forms): make composition event buffering configurable #15256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

kara
Copy link
Contributor

@kara kara commented Mar 17, 2017

This commit fixes a regression where ngModel no longer syncs letter by letter on Android devices, and instead syncs at the end of every word. This broke when we introduced buffering of IME events so IMEs like Pinyin keyboards or Katakana keyboards wouldn't display composition strings. Unfortunately, iOS devices and Android devices have opposite event behavior. Whereas iOS devices fire composition events for IME keyboards only, Android fires composition events for Latin-language keyboards. For this reason, languages like English don't work as expected on Android if we always buffer. So to support both platforms, composition string buffering will only be turned on by default for non-Android devices.

However, we have also added a COMPOSITION_BUFFER_MODE token to make this configurable by the application, because in some cases, apps might might still want to receive intermediate values. For example, some inputs begin searching behavior based on Latin letters before a character selection is made.

As a provider, this is fairly flexible. If you want to turn composition buffering off, simply provide the token at the top level:

providers: [
   {provide: COMPOSITION_BUFFER_MODE, useValue: false}
]

Or, if you want to change the mode based on locale or platform, you can use a factory:

import {shouldUseBuffering} from 'my/lib';

....
providers: [
   {provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]

Closes #15079.

host: {'(input)': 'onChange($event.target.value)', '(blur)': 'onTouched()'},
// selector: '[ngModel],[formControl],[formControlName]',
host: {
'(input)': '_handleInput($event.target.value)',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the compositionupdate event come into this at all? Does it make sense to listen to that instead of input ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talked in person about this

@robwormald
Copy link
Contributor

LGTM once tests green

@kara kara force-pushed the fix-mobile branch 2 times, most recently from ffee582 to 971a5b5 Compare March 17, 2017 21:53
@kara kara added action: review The PR is still awaiting reviews from at least one requested reviewer and removed state: WIP labels Mar 17, 2017
@kara kara requested review from mhevery and IgorMinar March 17, 2017 22:02
@kara kara requested a review from tinayuangao March 17, 2017 22:56
Copy link
Contributor

@tinayuangao tinayuangao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kara kara force-pushed the fix-mobile branch 3 times, most recently from 5169b41 to b7ce422 Compare March 20, 2017 21:20
@@ -140,7 +143,10 @@ export interface ControlValueAccessor {
export declare class DefaultValueAccessor implements ControlValueAccessor {
onChange: (_: any) => void;
onTouched: () => void;
constructor(_renderer: Renderer, _elementRef: ElementRef);
constructor(_renderer: Renderer, _elementRef: ElementRef, _compositionMode: boolean);
_compositionEnd(value: any): void;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a bit weird that you decided to use _ prefix just for these methods. they are all "private" no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talked in person about this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they must be public because they are used in event bindings. But will it work with @internal? just curious.

@@ -1166,6 +1133,67 @@ export function main() {

});

describe('IME events', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

based on how these tests are written, it is not clear what's the default and that the default works on both android and ios.

is it feasible to change the tests to test this?

@kara kara added the action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews label Mar 20, 2017
@kara kara force-pushed the fix-mobile branch 3 times, most recently from 46d8c3a to acae946 Compare March 21, 2017 00:20
This commit fixes a regression where `ngModel` no longer syncs
letter by letter on Android devices, and instead syncs at the
end of every word. This broke when we introduced buffering of
IME events so IMEs like Pinyin keyboards or Katakana keyboards
wouldn't display composition strings. Unfortunately, iOS devices
and Android devices have opposite event behavior. Whereas iOS
devices fire composition events for IME keyboards only, Android
fires composition events for Latin-language keyboards. For
this reason, languages like English don't work as expected on
Android if we always buffer. So to support both platforms,
composition string buffering will only be turned on by default
for non-Android devices.

However, we have also added a `COMPOSITION_BUFFER_MODE` token
to make this configurable by the application. In some cases, apps
might might still want to receive intermediate values. For example,
some inputs begin searching based on Latin letters before a
character selection is made.

As a provider, this is fairly flexible. If you want to turn
composition buffering off, simply provide the token at the top
level:

```ts
providers: [
   {provide: COMPOSITION_BUFFER_MODE, useValue: false}
]
```

Or, if you want to change the mode  based on locale or platform,
you can use a factory:

```ts
import {shouldUseBuffering} from 'my/lib';

....
providers: [
   {provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]
```

Closes angular#15079.
@kara kara removed the action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews label Mar 21, 2017
@IgorMinar IgorMinar added action: merge The PR is ready for merge by the caretaker and removed action: review The PR is still awaiting reviews from at least one requested reviewer labels Mar 21, 2017
@mhevery mhevery closed this in 5efc860 Mar 21, 2017
sis0k0 added a commit to NativeScript/nativescript-angular that referenced this pull request Jun 8, 2017
sis0k0 added a commit to NativeScript/nativescript-angular that referenced this pull request Jun 9, 2017
asnowwolf pushed a commit to asnowwolf/angular that referenced this pull request Aug 11, 2017
)

This commit fixes a regression where `ngModel` no longer syncs
letter by letter on Android devices, and instead syncs at the
end of every word. This broke when we introduced buffering of
IME events so IMEs like Pinyin keyboards or Katakana keyboards
wouldn't display composition strings. Unfortunately, iOS devices
and Android devices have opposite event behavior. Whereas iOS
devices fire composition events for IME keyboards only, Android
fires composition events for Latin-language keyboards. For
this reason, languages like English don't work as expected on
Android if we always buffer. So to support both platforms,
composition string buffering will only be turned on by default
for non-Android devices.

However, we have also added a `COMPOSITION_BUFFER_MODE` token
to make this configurable by the application. In some cases, apps
might might still want to receive intermediate values. For example,
some inputs begin searching based on Latin letters before a
character selection is made.

As a provider, this is fairly flexible. If you want to turn
composition buffering off, simply provide the token at the top
level:

```ts
providers: [
   {provide: COMPOSITION_BUFFER_MODE, useValue: false}
]
```

Or, if you want to change the mode  based on locale or platform,
you can use a factory:

```ts
import {shouldUseBuffering} from 'my/lib';

....
providers: [
   {provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]
```

Closes angular#15079.

PR Close angular#15256
juleskremer pushed a commit to juleskremer/angular that referenced this pull request Aug 28, 2017
)

This commit fixes a regression where `ngModel` no longer syncs
letter by letter on Android devices, and instead syncs at the
end of every word. This broke when we introduced buffering of
IME events so IMEs like Pinyin keyboards or Katakana keyboards
wouldn't display composition strings. Unfortunately, iOS devices
and Android devices have opposite event behavior. Whereas iOS
devices fire composition events for IME keyboards only, Android
fires composition events for Latin-language keyboards. For
this reason, languages like English don't work as expected on
Android if we always buffer. So to support both platforms,
composition string buffering will only be turned on by default
for non-Android devices.

However, we have also added a `COMPOSITION_BUFFER_MODE` token
to make this configurable by the application. In some cases, apps
might might still want to receive intermediate values. For example,
some inputs begin searching based on Latin letters before a
character selection is made.

As a provider, this is fairly flexible. If you want to turn
composition buffering off, simply provide the token at the top
level:

```ts
providers: [
   {provide: COMPOSITION_BUFFER_MODE, useValue: false}
]
```

Or, if you want to change the mode  based on locale or platform,
you can use a factory:

```ts
import {shouldUseBuffering} from 'my/lib';

....
providers: [
   {provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]
```

Closes angular#15079.

PR Close angular#15256
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 11, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ng4 ngModelChange regression on mobile
7 participants