I develop website on Flask and AngularJS. I need to send a form whith AJAX using AngularJS but it requires a custom attribute for input field. For example I have a form in Jinja2 template:
<form method="post" action="/">
{{ form.hidden_tag() }}
{{ form.name(placeholder="Name") }}
</form>
So how can I add an attribute from AngularJS lets say "ng-model" for my "name" field?
Thanks for your help!
WTForms is a Python library that provides flexible web form rendering. You can use it to render text fields, text areas, password fields, radio buttons, and others. WTForms also provides powerful data validation using different validators, which validate that the data the user submits meets certain criteria you define.
WTForms are really useful it does a lot of heavy lifting for you when it comes to data validation on top of the CSRF protection . Another useful thing is the use combined with Jinja2 where you need to write less code to render the form. Note: Jinja2 is one of the most used template engines for Python.
From version 0.9. 0, Flask-WTF will not import anything from wtforms, you need to import fields from wtforms. If your form has multiple hidden fields, you can render them in one block using hidden_tag() .
StringField (default field arguments)[source]¶ This field is the base for most of the more complicated fields, and represents an <input type="text"> .
Dashes are not permitted in Python identifiers, and only Python identifiers can be used as keyword_argument=value
pairs in a call.
But you have several options to work around that here; you can pass in the ng-
prefixed options in a **kwargs
mapping, have the Meta
class you use for the form translate _
to -
for ng_
attributes, or use a custom widget to do the same translation.
With **kwargs
you can pass in arguments that are not Python identifiers, as long as they are strings. Use that to render your form fields:
{{ form.name(placeholder="Name", **{'ng-model': 'NameModel'}) }}
You can put the same information in the render_kw
mapping on the field definition:
class MyForm(Form):
name = StringField(u'Full Name', render_kw={'ng-model': 'NameModel'})
and it'll be used every time you render the field; render_kw
is added to whatever arguments you pass in when you render, so:
{{ form.name(placeholder="Name") }}
would render both placeholder
and ng-model
attributes.
As of WTForm 2.0, the Meta
class you attach to your form is actually asked to render fields with the Meta.render_field()
hook:
import wtform.meta
class AngularJSMeta:
def render_field(self, field, render_kw):
ng_keys = [key for key in render_kw if key.startswith('ng_')]
for key in ng_keys:
render_kw['ng-' + key[3:]] = render_kw.pop(key)
# WTForm dynamically constructs a Meta class from all Meta's on the
# form MRO, so we can use super() here:
return super(AngularJSMeta, self).render_field(field, render_kw)
Either use that directly on your form:
class MyForm(Form):
Meta = AngularJSMeta
name = StringField(u'Full Name')
or subclass the Form
class:
class BaseAngularJSForm(Form):
Meta = AngularJSMeta
and use that as the base for all your forms:
class MyForm(BaseAngularJSForm):
name = StringField(u'Full Name')
and now you can use this is your template with:
{{ form.name(placeholder="Name", ng_model='NameModel') }}
You could subclass the widget of your choice with:
class AngularJSMixin(object):
def __call__(self, field, **kwargs):
for key in list(kwargs):
if key.startswith('ng_'):
kwargs['ng-' + key[3:]] = kwargs.pop(key)
return super(AngularJSMixin, self).__call__(field, **kwargs)
class AngularJSTextInput(AngularJSMixin, TextInput):
pass
This translates any keyword argument starting with ng_
to a keyword argument starting with ng-
, ensuring the right HTML attributes can be added. The AngularJSMixin
can be used with any of the widget classes.
Use this as a widget
attribute on your field:
class MyForm(Form):
name = StringField(u'Full Name', widget=AngularJSTextInput())
and again you can use ng_model
when renderig your template:
{{ form.name(placeholder="Name", ng_model='NameModel') }}
In all cases the attributes will be added as placeholder="Name" ng-model="NameModel"
in the rendered HTML:
<input id="name" name="name" ng-model="NameModel" placeholder="Name" type="text" value="">
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With