BrowserSync / browser-sync

Keep multiple browsers & devices in sync when building websites. https://browsersync.io
https://discord.gg/2d2xUThp
Apache License 2.0
12.18k stars 756 forks source link

I have a fix for React input text 'onChange' events not firing. I need to know where to put it in the code #1336

Open eldrgeek opened 7 years ago

eldrgeek commented 7 years ago

Issue details

When React applications are synced across browsers, most things update properly. But input box onChange events do not trigger properly in the synced instances. The data in the input box is synced, which is great, but 'onChange` is not triggered.

This is because onChange is a synthetic event. If the code programmatically changes the input box by el.value = 'some value' the event is not triggered. It will only trigger if the change comes from within the React framework.

BrowserSync has the necessary information to cause the event to trigger because it delivers correct content to the input element. What it does not do is trigger the synthetic events.

I've created a project on glitch.com here that demonstrates the problem and implements a hackish solution. A description of how to run my hack is below.

The proven solution is to deliver an 'input' event to the input box. I do this on a timer tick: const event = new Event('input', { bubbles: true }); input.dispatchEvent(event); After demonstrating that this fixed the bug, I hooked the browser-sync socket and found that browser-sync sends this message on the text change: [ 'input:text', 9:22 PM { tagName: 'INPUT', index: 0, value: 'f', url: '/' } ]

So a better solution is to watch for this event and then dispatch the above event when it is seen (or after a delay, if there is a race condition).

The best solution is to make this same fix in the 'right place' in browser-sync. But I do not know where that is. I am using the current version. If you advise me where to make the fix, I will prepare a PR with the fix.

Thanks.

For reference:

The method for the fix is from this StackOverflow post

Instructions for running my example:

Steps to reproduce/test case

I've created an example in this gomix.com project. To run it, do the following:

  1. Open this link in two different devices.

  2. You can confirm that scrolling, navigation, clicks in the side panel all sync properly.

  3. If you type (for example) an 'f' in the input box in a browser, it will filter the list of items in that browser. An 'f' reduces the list to just 'football.' The input box in the synced browser will get the changed value, but it does not trigger the onChange handler which causes the update.

  4. If you click the button labeled "Hack?" it will change (in both browsers) to "Hack!" and set up a timer loop that checks the contents of the input box every two seconds; if the input has changed since the last call to the onChange handler, then it will fire the onChange handler. In the browser in which a change is made, the handler will have fired normally, so the hack will have no effect. In the synced browser, the values will be different, so the update routine will run, and the list will be filtered.

I set the timeout to two seconds so that the effect would be clear. I could use something like this with a faster timer as a hack to work around the problem. The better solution would be to deliver the 'input' event to the target of the message from browsersync that updates the input box.

abhi608 commented 7 years ago

Hey! Did you integrate your fix with BrowserSync?

eldrgeek commented 7 years ago

No. You are the only person to reply. I don't know the BrowserSync code enough to know where to insert my change. I notice that I did not include a link to my hack. Here it is

joacim-boive commented 5 years ago

This would be extremly sweet to have implemented as the benefit of using Browsersync with forms in a React app is quite limited now... :(