Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/mercmobily/hot-form

Powerful steroid injection for iron-form: auto-save, auto-load, validation, and more
https://github.com/mercmobily/hot-form

form forms validation webcomponents

Last synced: about 2 months ago
JSON representation

Powerful steroid injection for iron-form: auto-save, auto-load, validation, and more

Awesome Lists containing this project

README

        

[![Published on webcomponents.org](https://img.shields.io/badge/webcomponents.org-published-blue.svg)](https://www.webcomponents.org/element/mercmobily/hot-form)

(Note: if you use this element, you should also consider using [hot-network (GitHub)](https://github.com/mercmobily/hot-network) [hot-network (WebComponents)](https://www.webcomponents.org/element/mercmobily/hot-network)

Imagine you are using Polymer, you have a **record on your database, and want to save it** using a web form. **You follow tutorials**, and you find that everything works as expected: you make up a form (it could be an iron-form), you run it, and the record appears. **You think this is a success** -- until you put this form in the real world and discover that **all those tutorials were lying. They were showing you that something with pedals and two wheels will move faster -- but failed to show you that in order to ride it you also need breaks, lights, a helmet;** yes, they are all props. But yes, **you always need them**.

Ask yourself these questions:

* Do you need to load data from the server before showing the form?
* Do you want to overwrite a record (PUT with an existing ID), or create a new one (POST, no ID) or create a record with an arbitrary ID (PUT with a new ID)? Do you realise that you will need POST or PUT calls?
* Do you want to render ALL input fields _automatically_ disabled while the form is being submitted?
* Do you want to highlight the problem fields if the form is NOT a success?
* Do you want to submit the form when the user presses ENTER on a paper-input widget?
* Do you want to refresh the data with the saved info coming back from the server after saving?
* Do you want to display messages to the user?
* Do you want to have fields in a form that won't actually get submitted?

If the answer is yes, and you are coding this each time from scratch, then maybe you should consider using a decorator element that does _all_ of this for you. **Welcome to `hot-form`**.

Imagine you have a form like this:





Click!

Here is what it does, and how.

## Invalidate fields based on server response

The server normally responds either with an OK status (200, 201, etc.) or with an error status. In case of errors, the server normally will tell you what the problem was, and which fields were affected. Unless you enjoy repeating code, you want the "invalidation" to happen automaticallty.

If the server returns errors (for example 422), `hot-form` will expect a JSON object back from the server like so:

{"message":"Unprocessable Entity","errors":[{"field":"name","message":"Not good!"}]}

This will cause `hot-form` to set the field named `name` as `invalid`, with the invalid message set as `Not good!`.

**NOTE**: in some cases, the actual submitting field is a hidden one, whereas the UI input field is only used for input. In such a case, you can assign the `vname` property to the UI field, which will get the error message in case the server responds with one.

## Emit events so that other widgets can display messages

The element will fire the following messages:

* `user-message-info`. Fired when a form is submitted. `e.detail` will have `{ message: msg }`. The default message is `Saving...`, and it can be changed by setting `submit-message`.
* `user-message-success`. Fired when a successful response is received. `e.detail` will have `{ message: msg }`. The default message is `Success!`, and it can be changed by setting `success-message`.
* `user-message-error`. Fired when an error response is received. `e.detail` will have `{ message: msg }`. The default message will depend on the `error` field returned by the server. If the `error` field isn't there, the defaut message is `Error!` and it can be changed by setting `default-error-message`.

These events will bubble up. So, you can put elements that listen to them, and display these messages to the user.

## Make the right request to the server (PUT or POST), based on `record-id`

If `record-id` is set, the element will make sure that the `request` object used by the `iron-ajax` form is manipulatd before sending it, so that the `action` attribute is changed to `/original/url/:recordId` (with `:recordId` appended), and the method used by `iron-ajax` is `PUT`. This means that the element can be used to make spefific PUT calls on specific records, based on `recordId`. For example:






Active?
Click!

When the form is submitted, `PUT /stores/polymer/57902ef29b880cd678a3d7a9` will actually be called.

### Modifiers for GET and PUT requests

In some cases, you might want the PUT request to use slightly different URLs:

* `no-record-id-append`: when running the PUT request, it will not append the record ID. This is useful when the server alreayd knows the record ID based on the session (e.g. while fetching the user's record)

* `put-suffix`: in some cases, the server might expect an extra path when putting data. It's rare, but it does happen. Whatever is in `put-suffix` will be added to the PUT URL. In the example above, setting `put-suffix` to '/extra` would turn the put into `PUT /stores/polymer/57902ef29b880cd678a3d7a9/extra`.

## Load of record with an AJAX call, pre-setting corresponding form values

If `record-id` is set, the element will make a GET AJAX call to the `action` URL (in the example above, `GET /stores/polymer/57902ef29b880cd678a3d7a9` fetching the current record's value. It will also pre-set the form's value to
match those returned by the server.

Record autoload will happen automatically when `record-id` is set; it can be turned off with the skip-autoload attribute (in case values are already available from a cache, but you still want `hot-form` to _save_ them).

**Note**: the response must be a JSON record, where each field's key corresponds to the element's `name` attribute. In the example above, a valid JSON in return would be:

{
"name":"Tony",
"surname":"Mobily",
"age":40,
"active":false,
"id":"57902ef29b880cd678a3d7a9",
}

This means that you can create your form, _and_ know that the existing record's value are already set.

Just like `put-suffix`, you can define a `get-suffix` parameter which will be appended to GET (preload) requests.

Finally, you can set `preload-url` if the URL used to preload data is different to the one used in the form itself as `action`.

## Reset form when response arrives, or set values based on returned values

When getting the response after issuing a POST request (no `record-id` appended), the form is automatically reset. This can be changed with the `action-after-post-response` attribute, that can be set to `set`, `reset` (the default) or `none`.

When getting the response after issuing a PUT request (with `record-id` appended to the request), the form is automatically set to the values that came back from the server. This means that if the server did any manipulation to the data, the form will display the correct, current information. This can be changed with the `action-after-put-response` attribute, that can be set to `set` (the default), `reset` or `none`.

## Binding to the `info` property

When the data loader is used, _and_ when a record is successfully submited to the server with `actionAfterPostResponse` or `actionAfterPostResponse` being equals to `set`, the following things will happen (in this order):

* Any form field with an attribute `name` matching a property key in the JSON will have its value set to what the server returned for that property key.

* The `info` variable in `hot-form` is assigned, key-by-key, to whatever returned from the server. This variable will `notify` for changes. Binding `info` with the variable you preset your fields with will ensure that after a successful AJAX submission the `info` is kept in sync with what's on the database.

Here are two use cases.

### Field visibility

Sometimes, you want to be able to see what was returned by the form's AJAX call. This is useful when a field's visibility depends on information on the database.
For example, you might have a button tha says "Send email reminder", but only if the email is set.
For this purpose, you can bind a variabl to `info`, which allows 2-way binding.
For example:

Send reset password email






Save!



As you can see, `paper-button` is disabled if `info.email` is not there. However, since the element's `info` property is bound to `hot-form`'s `info` property, when `hot-form` assigns values to `info`, `info.email` will be set to the email property returned by the AJAX call and `{{_empty(info.email)}}` will be set accordingly.

### Having pre-sets from extra info from the DB

Imagine that you have a `my-picker` form element which act as a autocomplete input form (based on paper-input); assume that `my-picker` which accepts a `value` property (as its value) representing the ID of the picked record and also a `search-string` property which represents the description field of the picked record.

Assuming that the database will return _both_ the contact ID and the `contactIdShownValue`, this will work:



Save!


When the form is loaded or submitted, `my-picker` will have _both_ its value and its actual input field set properly. (This is assuming that the query to `/stores/contacts` will return both the `contactId` key and the `contactIdShownValue` key, probably using a JOIN in SQL)

## Sane submission when pressing "enter" or clicking the submit button

This element allows you to automatically submit form when you press enter on a `paper-input` field, or when clicking on the button marked as `type=submit`.

Yes, you have to do these things by hand normally (!). Every time. Just wrap your form with hot-form, and you won't have to worry about it.


...

If you want to disable "submit by pressing enter", just add `no-enter-submit` to `hot-form`.


...

If you don't want to submit the form with a button automatically, just avoid setting a paper-button as `type=submit`.

## Do not submit specific fields

Sometimes, you need to have input fields in the form, and yet not submit those values. For example, you might have a "country" field that is actually an auto-complete field, which in turns will set the country's ID as an input field.
Every input field must have a name -- for example, if they don't they won't reset.
For this use case, just prefix "local" fields (not to be submitted) with `_`. THe following example is a typical use case: the country ID will depend on what was picked by hot-autocomplete; prefixing the paper-input's name with `_` will prevent the field `country` to be submitted.

Country code: {{pickedCountry.id}}



## Set an object's keys when the response arrives

Sometimes, you want to be able to see what was returned by the form's AJAX call. This is useful when a field's visibility depends on information on the database.
For example, you might have a button tha says "Send email reminder", but only if the email is set.
For this purpose, you can bind a variabl to `info`, which allows 2-way binding.
For example:


Send reset password email






Save!



As you can see, `paper-button` is disabled if `info.email` is not there. However, since the element's `info` property is bound to `hot-form`'s `info` property, when `hot-form` assigns values to `info`, `{{_emptyString(info.email)}}` will actually work (since the element's `info.email` will be set to the email value returned by the AJAX call).

As well as setting the `info` property, when a response is received (from preloading or saving), hot-form will also set all elements with matching name with the received response. If you don't want fields to be set, add the `skip-set` attribute to it.

## Emit event before submission

Before submitting the form, hot-form will emit a `iron-form-presubmit` event. Note that this is fires _way before_ `iron-form`'s `iron-form-presubmit` event, which is fired when the form is already serialised and ready to be sent over the wire. `iron-form-presubmit` is fired before running `submit()` on the `iron-form` itself. This is handy for example in case you want to re-enable some fields (so that they are serialised) while they were read-only (or disabled) on the form, so that their values are included in the form's serialisation.