I made a simple form in Flask using Flask-WTForms where a parent can register itself and his children. The parent can register as many children as he wants, by clicking on the button 'Add child'. WTForms makes this pretty easy to implement by using the FieldList feature.
However, after clicking on the button 'Add child' the page refreshes itself because it makes a request to the server. I want to use an AJAX request to add a child form, so the page doesn't refreshes itself.
I know how to do an AJAX-request, send a response back and add this response to the html page. However, I do not know how to append an entry to the form object and return the page itself (somehow) with the updated form-object. Is that even possible?
My forms:
class ChildForm(FlaskForm):
name = StringField(label='Name child')
age = IntegerField(label='Age child')
class Meta:
# No need for csrf token in this child form
csrf = False
class ParentForm(FlaskForm):
name = StringField(label='Name parent')
children = FieldList(FormField(ChildForm), label='Children')
add_child = SubmitField(label='Add child')
submit = SubmitField()
My routes:
@app.route('/register', methods=['GET', 'POST'])
def register():
form = ParentForm()
if form.add_child.data:
form.children.append_entry()
return render_template('register.html', form=form)
if form.validate_on_submit():
# do something with data
return render_template('register.html', form=form)
register.html:
<form action="{{ url_for('register') }}" method="post" id="parentForm">
{{ form.hidden_tag() }}
{{ form.name.label }} {{ form.name }}
{{ form.add_child }}
{% for childform in form.children %}
{% for field in childform %}
{{ field.label }} {{ field }}
{% endfor %}
{% endfor %}
{{ form.submit }}
</form>
In the below setup a user has a input which specifies how many text areas he will submit on the form (they dynamically appear and disappear) and then can submit it with AJAX.
Python backend
JS frontend and HTML (uses Vue.js and Jquery)
===== edited for comment.
Templating
There is a difference between server side templating, i.e. :
and client side templating, i.e. :
The OP requested:
In that case you need to update your page dynamically using Javascript. Only on a page refresh could the server update its template, whilst the client side Javascript can fetch the data with the AJAX query and then update dynamically. In this case when
form_data.num_items
changes the number oftextareas
increase.I have used Vue in this example since it is a fairly user friendly JS library. But you can also use React or Angular or use plain old JS, but you need to choose one.
Database
The OP made reference to a database:
the only equivelent reference I make to a database is here:
but of course you are free to do with the form data what you please and not necessarily commit anything to the database. In my example based on the number of items that are passed to the list, there are items created.
Summary
If you tolerate page refreshes, then you can add items to the form on the server side each time the user clicks an add button. This is simpler to code, but less efficient since data is repeatedly transferred between client and server and is probably more difficult to maintain.
If you want a smoother, more efficient user experience and more maintainable solution then my example is not the only combination of libraries of course, but they will all operate in a fairly similar way:
i.e:
I think this should work. Barring any typos.
views.py
form.html
members.html
For people who want to use the form in the more rudimentary non-RESTful way there is still the challenge of how to persist the form data correctly server side. If you don't do it right updating existing children in the form will append new children in the db rather than update existing ones. Below I provide two flask views, one for registering, and one for updating the registration. My view for updating the registration works but is a little kludgy. If anyone knows how to write it more elegantly I'd be psyched for some feedback: