WTForms error handling with seamless user experience

513 views Asked by At

I'm new to WTForms, and from what I've learned so far, I find the validation error handling a bit tricky.

First off, I can't implement the native HTML <input required >;

Secondly, when the form failed validation, I have to rerender the page template where the form is at, and if my form is placed on bottom of a page, the user will see the page 'refreshed' and have no idea what is going on.

Does anyone have suggestions on how to integrate WTForms more seamlessly? Any comments, resources, urls, code samples are welcomed, thanks!

Here are some of my related codes:

# /forms.py
from wtforms import Form, BooleanField, StringField, PasswordField, validators

class RegistrationForm(Form):
    email = StringField('Email Address', [
        validators.required(),
        validators.Email(message='Please enter a valid email address'),
        validators.length(min=6, max=35)
    ])
    password = PasswordField('New Password', [
        validators.required(),
        validators.DataRequired(),
        validators.length(min=6, max=35)
    ])

# /views.py
from flask import Flask, Blueprint, flash, render_template, redirect, request, url_for
from forms import RegistrationForm, LoginForm

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
    form = RegistrationForm()
    context = {
        "form": form
    }
    if request.method == 'POST' and form.validate():
        submitted_form = request.form
        return redirect('/welcome')
    else:
        return render_template('form.html', context = context)

# /form.html
<form class="form" action="" method="POST" name="register">
  {% for field_name, field_errors in context.reg_form.errors|dictsort if field_errors %}
    {% for err in field_errors %}
      <li class="error">{{ context.reg_form[field_name].label }}: {{ err }}</li>
    {% endfor %}
   {% endfor %}

   <ul class="form-fields center">
     <li class="form-field">
     {{ context.form.email(class='email', placeholder='email') }}
     </li>
     <li class="form-field">
     {{ context.form.password(class='password', placeholder='password') }}
     </li>
   </ul>
</form>
2

There are 2 answers

1
CESCO On BEST ANSWER

As far as I understand, WTForm will always have to refresh the page in order to show the errors. I worked this out is by letting the front-end to validate the form for me. Do not know if it possible on your case, but I've used AngularJS to do the trick. It's quite easy, not a single line of code is required if you need simple validation like email format, password length and etc, it's all done by html attributes. You can even disable the submit button until your form is ready to go. Check out this CodePen

You can scroll to the bottom to the page using this, if still needed:

var objDiv =     document.getElementById("your_div");
objDiv.scrollTop = objDiv.scrollHeight

If you need a more robust solution, you might come up with a API that return true or false to whatever field you want to validate. Then make angular make a http request to check it as you type, this way you are 100% sure you form is going to validate. But depending on what you are checking, you might expose a security hole. There is an excellent blog post about this on Ng-Newsletter

0
doru On

For a better experience with forms in Flask you should use the Flask-WTF extension. Install it:

$ pip install flask-wtf

import it

from flask.ext.wtf import Form

and use it along with wtforms module.

.py file:

from flask.ext.wtf import Form
from wtforms import StringField, SubmitField
from wtforms.validators import Required

class NameForm(Form):
    name = StringField('What is your name?', validators=[Required()])
    submit = SubmitField('Submit')

.html file:

<form method="POST">
{{ form.name.label }} {{ form.name() }}
{{ form.submit() }} #this is your submit button
</form>