long-running promise validations cause UI delays, unpredictable results
See original GitHub issueVersion
v1.5.0-beta.0
Test Case
I believe I’ve uncovered a flaw in the design of this addon around how it handles promise-based validations. Take the following <input > wired up to a changeset:
<input value={{changeset.email}} oninput={{action (mut changeset.email) value="target.value"}}>
Simple scenario. Now imagine you’re validating that email against a remote server, i.e. the promise will take awhile and the duration will of course be variable.
When you set a property on the changeset, it calls its _validateAndSet method. For validations that return promises, the following happens:
- User calls
changeset.set('email', "john@example.com") - Validation returns a promise, which can be as simple as a timeout / sleep to illustrate this issue
- The promise is resolved by
_validateAndSet, anywhere from a few ms to several seconds - The validation result is then passed to
_setProperty _setPropertyactually sets the new value on the changeset, along with any validation error
The entire time this is happening, the input continues to render with the old value because changeset.email has not actually changed yet (not until the end of step 5). So I could type j and then continue typing the rest of the email, but the input will appear to be frozen. Once step 5 finishes (which could be hundreds or thousands of ms), then the field actually updates.
This gets even worse if you have multiple validation requests in-flight, which will probably happen even with debouncing. You’re not actually guaranteed that any of these promises will resolve in the same order they were started, so you can potentially get the joh promise resolving before the jo promise, in which case changeset.email will ultimately be set to jo.
I hope I’m seriously misunderstanding something here because it doesn’t seem like it will be easy to fix 😕
Issue Analytics
- State:
- Created 5 years ago
- Comments:10 (3 by maintainers)

Top Related StackOverflow Question
There is a major problem with this statement! How can the state of the UI be represented in the changeset if it never allows invalid input?
In this situation it would be impossible to enter text if the changeset refuses to set invalid data, would it not? I’m not sure how this would work in ember.
I do see not applying the changes (
execute()) if the changeset is invalid, that makes sense. But to preventchangeset.set()seems very odd and introduces in inconsistency on how Ember handles EmberObjects and how changesets react.Thanks @sukima, that does seem like a suitable workaround!
That being said, I’d still consider it a major bug that the use of promises in validations is essentially guaranteed to produce weird, unpredictable results. It’s primarily an issue if those promises can last longer than the time between keystrokes / value changes, which is exactly the kind of thing that is most likely to pop up in prod and not dev and makes it scarier IMO