Skip to content

Form component #792

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
insin opened this issue Feb 8, 2015 · 5 comments
Closed

Form component #792

insin opened this issue Feb 8, 2015 · 5 comments

Comments

@insin
Copy link
Contributor

insin commented Feb 8, 2015

If react-router had a <Form> component (which would be to <form> as <Link> is to <a>), what could it do to make it simpler to implement form submission and - in particular - isomorphic form submission?

The obvious-seeming bit is that it could hook up onSubmit for you to call preventDefault() and slurp all the form data out via form.elements into an object which represents what would be submitted by a regular form submission.

If it's a GET form, it could then trigger a transition (to a named actionTo or to route, with the resolved URL set as the rendered <form>'s action?) with the data as query parameters.

The above functionality would completely negate the need for the onSubmit handler in in the mega demo form component, which seems like a good start that's worth having.


As background to the design questions I'm about to ask, the additional bits I'm grappling with in isomorphic-lab are:

  • Isomorphic POST forms
  • Using the same route handler for both GET (display form) and POST (validate form, call API, display any API errors or redirect on success) parts of submitting a form
  • Performing validation prior to submission and only triggering a transition to do the POST part when valid, as a progressive enhancement when JavaScript is available.
  • Avoiding reflecting POSTed data back to the user in the URL, where possible.

I am currently displaying a flash of POSTed data back to the user in the query string on submission by faking a POST transition to the same route:

this.transitionTo(
  this.makeHref('addReply'),
  {},
  assign({_method: 'POST'}, form.data)
)

For redisplay of a form with errors, I currently have an ugly hack which. To avoid displaying the POSTed data back to the user in the query string, I do this in willTransitionTo:

if (res.clientError) {
  if (env.CLIENT) {
    // Update the form with validation errors received from the API
    events.emit(AddReply.ERRORS_EVENT, ErrorObject.fromJSON(res.body))
    transition.abort()
  }
  else {
    // Re-render with user input + validation errors from the API
    transition.abort(new Render(`/forums/topic/${params.id}/add-reply`, {
      initialData: query
    , initialErrors: res.body
    }))
  }
}

An EventEmitter is used on the client to pass errors from willTransitionTo to the currently mounted form component, while on the server my Express middleware takes the Render object, re-runs the routers and passes the additional object's properties as extra props to the <Handler>.


Design Questions

POST data

Regular POST data:

  1. is never displayed to the user in the query string
  2. isn't bookmarkable
    1. BUT can be sent again by refreshing the page if there was no redirect

The current arguments passed to willTransitionTo represent things which (if provided) can be seen in the URL. I feel like this should not be the case with POST data.

Is it feasible to add another argument for one-shot data which isn't represented in the URL to be passed to transition hooks?

What about the behaviour in 2i? If the ability to pass POST data to a transition is added, should 2i be written off as a loss? I assume any attempt to emulate (e.g. confirm() in a transition) is beset with all sorts of cross-platform/device concerns.

(more to follow later!)

@nelix
Copy link

nelix commented Feb 9, 2015

I think this is a pretty cool idea, although you could simply make a set of components backed with some actions and a store to take care of all this. react-router-forms.
I have been going the other direction and using json-schema to generate my forms from models.

@insin
Copy link
Contributor Author

insin commented Feb 10, 2015

@nelix I'm more interested in the part where you've either done a regular form submission, or you have validated data to submit and how you do that with a route handler (which falls outside the scope of how you actually ended up rendering the form and getting data out of it), how you subsequently redisplay the form (or add additional validation errors you didn't or couldn't check on the client before attempting to submit) and how you do all of this in an isomorphic app friendly manner without having to serialise everything through the query string at some point.

@insin
Copy link
Contributor Author

insin commented Feb 12, 2015

To demonstrate why I'm not keen on having to use query params for all data passing. I've added some basic client side (data presence) and faux server-side (dupe name checking) validation to the mega demo example, plus a "sensitive" field:

Try to add a duplicate name - now whatever you put for the PIN field is part of your browser history.

@insin
Copy link
Contributor Author

insin commented Feb 12, 2015

Here's a version which adds and uses the ability to associate a one-time payload object with a location change to both pass POST form data to a willTransitionTo and to pass props for the route handler back from the resulting redirect when the form is invalid according to the faux server validation:

Changes to react-router and the react-router-form component:I'm playing with:

@ryanflorence
Copy link
Member

if there's a sweet implementation of this somewhere I can imagine including it into the repo officially, but closing for now.

@lock lock bot locked as resolved and limited conversation to collaborators Jan 24, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants