{% extends "docs/base.html" %}

{% block main %}
{% markdown %}
# Form API Javascript 

## Dependencies
 - `snek.system.form.Form`
 - `snek.system.form.HTMLElement`
 - `snek.system.form.FormInputElement`
 - `snek.system.form.FormButtonElement`

## Usage 
Here is an example with custom validation. 
This example contains a field that checks if user already exists. 
If invalid, it adds an error message which automatically invalidates the field. 
Handling of the error messages will automatically done client side.

Forms are usaly located in `snek/form/[form name].py`.

```python
from snek.system.form import Form, HTMLElement,FormInputElement,FormButtonElement

class UsernameField(FormInputElement):

    @property
    async def errors(self):
        result = await super().errors
        if self.value and await self.app.services.user.count(username=self.value):
            result.append("Username is not available.")
        return result

class RegisterForm(Form):

    title = HTMLElement(tag="h1", text="Register")

    username = UsernameField(
        name="username", 
        required=True,
        min_length=2,
        max_length=20,
        regex=r"^[a-zA-Z0-9_]+$",
        place_holder="Username",
        type="text"
    )
    email = FormInputElement(
        name="email",
        required=False,
        regex=r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$",
        place_holder="Email address",
        type="email"
    )
    password = FormInputElement(
        name="password",
        required=True,
        regex=r"^[a-zA-Z0-9_.+-]{6,}",
        type="password",
        place_holder="Password"
    )
    action = FormButtonElement(
        name="action",
        value="submit",
        text="Register",
        type="button"
    )
```

## Set data 

```python 
# The input structure is in same format as output structure.
# Output structure is the result of await form.to_json()
data = dict(
    username=dict(value="retoor"),
    password=dict(value="retoorded")
)
form.set_user_data(data)

# Check if form is valid.
is_valid = await form.is_valid

# Convert form to a record (kv pairs) to be used for persistance. 
# It does contain an filled uid (UUID4) field already to be used as primary key.
# Default fields:
# - uid (automatically generated, it's an UUID4 wich you can use as private key for database)
# - created_at (automatically generated, it's a string representation of UTC locale)
# - updated_at (execute await form.updated_at.update() before saving to set value)
key_value_values = await form.record 
```

{% endmarkdown %}
{% endblock %}