Slate: 'change' event is not triggered on Android

Created on 2 Nov 2019  路  22Comments  路  Source: ianstormtaylor/slate

Do you want to request a _feature_ or report a _bug_?

Bug

What's the current behavior?

In Chrome browser on Android (7, 8, 9 versions) a 'change' event isn't triggered at all or only when space or enter was pressed. Instead of this, an 'input' event is triggered.
Slate 0.47.8, slate-react 0.22.9.
Demo: https://codesandbox.io/s/slate-android-issue-ibyks
In the demo you can see that there is no console.log on 'change' event but it should be. And there is console.log on 'input' event on Android.

What's the expected behavior?

A 'change' event should be triggered each time user types or removes a character (as it works in desktop browsers and on iOS).

In current implementation it's impossible to get a correct value of editor on Android. Do you have an idea in which part of Slate code it can be located?

Most helpful comment

@joshmanders To solve this a new model to treat composition is needed. That would require some change in Slate and almost a rewrite of the Android support. This is will be needed for a while unless a new model is worked on.

As of right now I'm working on that new model but it isn't ready yet, and isn't integrated to Slate yet. Even with that new model, whether all inputs happen at the end of a composition or not will depend on how Slate handles update, rendering and composition thogether.

All 22 comments

@gracicot has a branch where he fixed it. But it is not in master yet. The branch.

Hi @SilverDY ,
Thanks for info! I've tried this branch but it still doesn't work: 'change' event is not triggered correctly when I add/remove characters but 'input' event is called instead.

@Dmitry2703 Hm... you are right. I checked it again and found that onChange works only if I start the change in the middle of a word. If I change from the end of the word I get your problem. Did this check using that branch and "Composition" page.

I saw that bug before. It's a problem with the composition manager's connect function. It failed to connect properly when initializing but it was intermittent for me and I never quite knew why it happenend.

Delaying the initialization made it work all the time but doing that risks missing mutation events. I did not tried to fix it since it only happened in my sandbox _sometimes_ and not any other apps. Since it also did not happened in the example page, I assumed this was a problem on my side only.

It has been happening for months for us and in our case onChange is never triggered at all after updating to latest versions (even pressing space). You can reproduce it on official examples here https://www.slatejs.org/#/plugins. Word count is never updated on Android as the value is never really updated (I assume).

@davidosomething If I get you right. This branch fixes this behavior and the space button starts working. But we still have a problem with triggering onChange after any input (without pressing space/enter).

@SilverDY Okay I just tried and it definitely fixes it on space/enter.

Delaying the initialization made it work all the time but doing that risks missing mutation events

@gracicot , what do you actually mean by delaying the initialization? To set timeouts to observer.connect() in onComponentDidMount and onComponentDidUpdate in AndroidPlugin?

@Dmitry2703 yes. With my tests, calling window.requestAnimationFrame was fixing the problem, at the cost of missing input. This is not a good solution. I was able to reproduce the issue on desktop, but not in a isolated example.

A symptom that happen every time is editor.findDOMNode([]) returning null. I still don't know why it happen yet.

@gracicot thanks for info

@Dmitry2703 do u have any progress?

@victorpavlenko unfortunately, no... I saw that @gracicot made several fixes for Android (thanks a lot!) but an issue with 'change' event isn't still resolved.

@thesunny
I would like to ask u why u made this line?
last.domNode = null

And it鈥檚 also possible that you are more likely to see why last.node is never reset, and is always equal to domSelection.anchorNode, because of this, applyDiff is not called and onChange does not work.

last.node = domSelection.anchorNode

@victorpavlenko Could you be more specific? Where is this line of code and under what situation are you seeing it execute that you'd like me to provide more info into?

I wrote the code but it's been a while so I'll need to have my memory jogged.

I deep dived a little bit and found a few things.

  1. When the observer calls connect in onComponentDidMount, editor.findDOMNode([]); returns null because the contentRef is null. So nothing is observed. I fixed this by adding observer.connect(); in onCompositionStart()
  function onCompositionStart() {
    observer.connect();
    observer.onCompositionStart();
  }
  1. flushControlled was undefined for me. I found out it was related to my version of React. In the latest version of React 16.11 they have added a flag https://github.com/facebook/react/blob/master/packages/react-dom/src/client/ReactDOM.js#L183 stopping you from getting ReactDOM.unstable_flushControlled. Downgrading to React 16.10.2 gives you access to ReactDOM.unstable_flushControlled and fixes the problem.

After doing both of those things, I was getting the 'change' event in Android again

Hi @benawad ,
I tried your solution on Android 7 and 9 with composition example but it seems that 'change' event is still fired only after pressing space or enter...
Which versions of slate and slate-react are you using?

@Dmitry2703 this is normal to a certain extent. The Android plugin only update the document when a composition ends, including the selection and entered text. You can see the composition in Android, denoted by an underline on a word.

@gracicot hmm, ok. But still I think it's an incorrect behavior. If user changes some letters in a word without pressing space or enter than I can't detect this changes and save them...

Has anyone figured out how to work around the space/enter issue? Seems weird to require the user to end their input with a space/enter on Android just for Slate to work correctly.

@joshmanders To solve this a new model to treat composition is needed. That would require some change in Slate and almost a rewrite of the Android support. This is will be needed for a while unless a new model is worked on.

As of right now I'm working on that new model but it isn't ready yet, and isn't integrated to Slate yet. Even with that new model, whether all inputs happen at the end of a composition or not will depend on how Slate handles update, rendering and composition thogether.

Hey, there are lots of open Android-related issues that are out of date with the latest 0.50 release because the codebase was completely rearchitected. We'll need to figure out how to have proper support for Android going forward based on beforeinput events somehow. I'm tracking this in https://github.com/ianstormtaylor/slate/issues/3112, so I'm going to close this in favor of that one.

If it cannot be implemented simply in core with beforeinput we'll likely need to have a separate plugin for android support be created, because it's too much of a departure from all of the other simpler logic in core and very hard for me to test or respond to issues. Using a separate plugin should be possible now as the newest version simplifies a lot of the internals.

Thank you for understanding.

I am using slate 47 and it's working perfectly on desktop and iOS devices but onChange is not triggering on Android devices. I would greatly appreciate any suggestion. Thanks.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

varoot picture varoot  路  3Comments

ezakto picture ezakto  路  3Comments

ianstormtaylor picture ianstormtaylor  路  3Comments

AlexeiAndreev picture AlexeiAndreev  路  3Comments

gorillatron picture gorillatron  路  3Comments