Skip to content
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

Add submitting state property that is true while onSubmit is pending #449

Merged
merged 44 commits into from
Nov 25, 2018

Conversation

BudgieInWA
Copy link
Contributor

@BudgieInWA BudgieInWA commented Jul 17, 2018

This PR closes #441.

This is my attempt to implement the feature tracked in #441 in uniforms core. I am looking forward to feedback, and if it turns out that this solutions would be acceptable, I can implement validating similarly.

The commit messages provide motivation for the individual changes.

- The successs and failure callback behaviour was not being tested when submitting without `onSubmit`.
- The value passed to the `onSubmit` callbacks was not tested.
A new state property `submitting` is introduced, which is `true` while an onSubmit promise is pending and `false` otherwise.
The presence of `onSubmitFailure` makes it look like it might be ok to let `onSubmit` throw an error (as well as rejecting the promise it returns). If `onSubmit` does throw an error, the form itself could enter an invalid state and the uncaught error message would be mixed up with uniforms implementation, so it would be hard for the end user to debug.
@BudgieInWA BudgieInWA requested a review from radekmie as a code owner July 17, 2018 06:59
@codecov
Copy link

codecov bot commented Jul 17, 2018

Codecov Report

Merging #449 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@          Coverage Diff          @@
##           master   #449   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files         157    157           
  Lines        1404   1414   +10     
=====================================
+ Hits         1404   1414   +10
Impacted Files Coverage Δ
packages/uniforms/src/filterDOMProps.js 100% <ø> (ø) ⬆️
packages/uniforms/src/ValidatedForm.js 100% <100%> (ø) ⬆️
packages/uniforms/src/BaseForm.js 100% <100%> (ø) ⬆️
packages/uniforms-unstyled/src/DateField.js 100% <0%> (ø) ⬆️
packages/uniforms-antd/src/SelectField.js 100% <0%> (ø) ⬆️
packages/uniforms-bootstrap3/src/DateField.js 100% <0%> (ø) ⬆️
packages/uniforms-material/src/SelectField.js 100% <0%> (ø) ⬆️
packages/uniforms/src/JSONSchemaBridge.js 100% <0%> (ø) ⬆️
packages/uniforms-bootstrap4/src/DateField.js 100% <0%> (ø) ⬆️
packages/uniforms-antd/src/DateField.js 100% <0%> (ø) ⬆️
... and 4 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5171be3...056f084. Read the comment docs.

Copy link
Contributor

@radekmie radekmie left a comment

Choose a reason for hiding this comment

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

Two minor things and one bigger one.

Great work with the tests!

packages/uniforms/src/BaseForm.js Outdated Show resolved Hide resolved
packages/uniforms/src/BaseForm.js Show resolved Hide resolved
packages/uniforms/src/filterDOMProps.js Outdated Show resolved Hide resolved
@radekmie radekmie added the Type: Feature New features and feature requests label Jul 17, 2018
@@ -66,7 +66,6 @@ describe('BaseForm', () => {
expect(context.uniforms).toHaveProperty('state', expect.any(Object));
expect(context.uniforms.state).toHaveProperty('changed', false);
expect(context.uniforms.state).toHaveProperty('changedMap', {});
expect(context.uniforms.state).toHaveProperty('submitting', false);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think that this test is still needed (or at least it's a nice to have).

@radekmie
Copy link
Contributor

Besides that last comment, I really like it. You'd like to add the validating state in the same PR, right?

@BudgieInWA
Copy link
Contributor Author

I will be implementing validating too. I'm happy for this PR to be merged to put a lid on the points discussed here, or to keep working here to keep the discussion together.

@radekmie
Copy link
Contributor

So let's work on it here. I'll think about the changelog and documentation.

@radekmie
Copy link
Contributor

Ping @BudgieInWA.

@BudgieInWA
Copy link
Contributor Author

BudgieInWA commented Sep 11, 2018

@radekmie Sorry about the delay and the git history. Here is my crack at validating state.

I think submitting an AutoForm with an async onValidate and onSubmit will go through these states:

  1. submitting: false, validating: true
  2. submitting: true, validating: false
  3. submitting: false, validating: false

I don't know if it would be a better API if it went through these states:

  1. submitting: true, validating: true
  2. submitting: true, validating: false
  3. submitting: false, validating: false

@radekmie
Copy link
Contributor

radekmie commented Sep 19, 2018

Indeed, this is not so good. There's one more thing: should the validating change, if it was not triggered by submit? One can call validate manually, then it should be separate.

I think it should work, by adding submitting: true to Validated#onSubmit, next to validate: true - BaseForm should handle setting down of this flag. It's not completely OK, as they should be independent.

Opinions?

(sorry for the delay)

@BudgieInWA
Copy link
Contributor Author

I think we want to define these flags as follows for easiest use:

  • validating is true while async work is being done and we are expecting a validation result.
  • submitting is true while async work is being done and we are expecting a submission result.

In that case, ValidatedForm#validate should set just validating and ValidatedForm#onSubmit should (atomically) set validating and submitting. If validation fails, it should (atomically) set them both down. If validation succeeds, it should set validating down, then proceed with the submit, which should set submitting down. (We need to add that guarantee to BaseForm#onSubmit.)

I think it's fine that ValidatedForm#onSubmit has this complicated interaction with the submitting flag, because it really is changing what "submit" means.

This seems to line up with your take, so I will start building.

(we're not in a hurry 😄)

@radekmie
Copy link
Contributor

Ping @BudgieInWA.

@BudgieInWA
Copy link
Contributor Author

@radekmie, how's that?

.catch(() => {
// `onSubmit` should never reject, so we ignore this rejection.
})
.finally(() => {
Copy link
Contributor

Choose a reason for hiding this comment

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

If we are after catch, then would be better here.

@@ -33,6 +33,8 @@ const Validated = parent => class extends parent {
]).isRequired
};

// TODO add `uniforms.state.validating` to `childContextTypes`.
Copy link
Contributor

Choose a reason for hiding this comment

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

One more thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is not obvious how this should be done. Unlike the actual state, with getChildContextState, the static childContextTypes is not assembled in this way. What we need is

static childContextTypes = merge(
  { uniforms: { state: { validating: PropTypes.bool.isRequired } } },
  parent.childContextTypes
);

but I don't know of any such merge function. Do we need to store the prop types nested in plain objects as well? Then we can have a shapify function that turns the plain object tree into a PropTypes.shapeOf tree for assignment to childContextTypes and the extending classes can merge the plain objects (like lodash.merge would) before assigning their own childContextTypes.

Or am I missing something simple?

Copy link
Contributor

Choose a reason for hiding this comment

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

There is a way to merge them, but differently - validate it twice. Prop types are just functions, so we can create a new one, which will start with calling the old one.

For now, I'd export an object from the BaseForm, marked as temporary (with comment and underscore prefixed name).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

3640cde is my take on exposing a PropTypes object that can be extended. I'm happy for you to rename and move stuff around, maybe refactor shapify and BaseForm.shapifyPropTypes into a file or util library.

Copy link
Contributor

Choose a reason for hiding this comment

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

Looks good, from the functional level. I'd rather not have shapifyPropTypes at all (but use shapify directly) and put plainChildContextTypes in an export (again, underscored) not to pollute BaseForm.

Should I do it, @BudgieInWA?

@radekmie
Copy link
Contributor

@BudgieInWA it looks great! Just two minor things.

@radekmie
Copy link
Contributor

It took some time, but we finally have it! Thanks again, @BudgieInWA!

@radekmie radekmie merged commit 51da666 into vazco:master Nov 25, 2018
static childContextTypes = parent.shapifyPropTypes(plainChildContextTypes);
static childContextTypes = {
...parent.childContextTypes || {},
uniforms: childContextTypes
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is awkward because parent.childContextTypes.uniforms is replaced with BaseForm.childContextTypes.uniforms (through childContextTypes) no matter what parent is. That is why BaseForm.plainChildContextTypes was a part of BaseForm (export __childContextTypesBuild is still better than BaseForm.shapifyPropTypes).

Copy link
Contributor

Choose a reason for hiding this comment

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

I know. There’s a small chance, that it happen not to be the case. Anyway, I’m sure it’s not really important, as the new context API doesn’t have this problem (and I’m thinking about it more and more....).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Feature New features and feature requests
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Track "submitting" state and make it available in the context
2 participants