Forms

JsWeb provides a simple, class-based system for handling form data and validation, inspired by WTForms. It integrates with the templating engine to make rendering forms and displaying errors straightforward.

Creating a Form

To create a form, define a class that inherits from jsweb.forms.Form. Add fields to the form by defining class attributes as instances of Field types (e.g., StringField, PasswordField).

# forms.py
from jsweb.forms import Form, StringField, PasswordField
from jsweb.validators import DataRequired, Email, Length, EqualTo

class RegistrationForm(Form):
    username = StringField('Username', validators=[DataRequired(), Length(min=4, max=25)])
    email = StringField('Email Address', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired(), Length(min=6)])
    confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])

Using Forms in Views

In your view function, create an instance of your form class, passing request.form to it. This populates the form with submitted data. Then, call the validate() method to run all the validators for each field.

# views.py
from .forms import RegistrationForm
from jsweb.response import render, redirect

@app.route('/register', methods=['GET', 'POST'])
def register(req, res):
    form = RegistrationGorm(req.form)
    if req.method == 'POST' and form.validate():
        # Data is valid, access it via form.<field_name>.data
        username = form.username.data
        email = form.email.data
        # ... create user ...
        return redirect('/login')
    
    # If GET request or validation fails, render the form again
    return render(req, 'register.html', {'form': form})

Rendering Forms in Templates

You can easily render the form in your Jinja2 templates. The form object gives you access to each field, its label, and any validation errors.

Crucially, JsWeb's form system integrates with its CSRF protection. You must include the CSRF token in your form by calling {{ form.csrf_token() }}.

<form method="post">
    {{ form.csrf_token() }}  <!-- Important! -->

    <div class="form-group">
        {{ form.username.label }}
        {{ form.username(class="form-control") }}
        {% if form.username.errors %}
            <ul class="errors">
                {% for error in form.username.errors %}
                    <li>{{ error }}</li>
                {% endfor %}
            </ul>
        {% endif %}
    </div>

    <div class="form-group">
        {{ form.password.label }}
        {{ form.password(class="form-control") }}
        {% if form.password.errors %}
            <ul class="errors">
                {% for error in form.password.errors %}
                    <li>{{ error }}</li>
                {% endfor %}
            </ul>
        {% endif %}
    </div>

    <button type="submit">Register</button>
</form>

Calling a field like {{ form.username() }} renders its HTML input tag. You can pass HTML attributes as arguments (e.g., class="form-control").