3

In my flask application I have to draw a form multiple times on the same page. This leads to the problem where I have multiple input fields with the same id on the page. E.g.:

class ChannelForm(flask_wtf.Form):
     name = StringField('name')

together with this template:

<form>
    {{ form.name }}
</form>
...
<form>
    {{ form.name }}
</form>

lead to two input elements with the same id:

<input id="name" name="name" value="" type="text">

Is there an official way to disable adding the id attribute?

Georg Schölly
  • 124,188
  • 49
  • 220
  • 267

3 Answers3

4

Quick n' dirty:

I've found that the following works well: instead of using the field directly, I wrap them in a jinja macro:

{% macro render_field(field) %}
<label>
    <span>{{ _field.label.text }} </span>
    {{ field(id=False, **kwargs) }}
</label>
{% endmacro %}

which can be used like this:

{% from "_formhelpers.html" import render_field %}
{{ render_field(form.name) }}

The trick here is to pass id=False when rendering the field.

using the meta object:

_Auto = object()
class NoIdAttributeMeta(DefaultMeta):
    """
    Surpresses rendering the `id' attribute.
    """

    def bind_field(self, form, unbound_field, options):
        """
        Raises TypeError in case 'id' is given as a positional arg when constructing a field.
        If this happens, make this code smarter or pass `id' as a keyword arg.
        """
        # we check `id' at rendering time and if it is still _Auto, do not render it
        unbound_field.kwargs.setdefault('id', _Auto)
        return super().bind_field(form, unbound_field, options)

    def render_field(self, field, render_kw):
        if field.id is _Auto:
            field.id = False
        return super().render_field(field, render_kw)

class MyForm(flask_wtf.Form):
    Meta = NoIdAttributeMeta

or be pragmatic:

You could also add a different prefix to each instance of your form and therefore you'd have unique ids:

my_form = MyForm(prefix="form1")
    pass
Georg Schölly
  • 124,188
  • 49
  • 220
  • 267
1

I think you can pass a custom id to the field constructor like this:

<form>
    {{ form.name(id_='yourId') }}
</form>
...
<form>
    {{ form.name(id_='yourId2') }}
</form>
Avi K.
  • 1,734
  • 2
  • 18
  • 28
1

You don't need id=False because you already can set id when you call render_field()

{% macro render_field(_field) %}
<label>
    <span>{{ _field.label.text }} </span>
    {{ _field(**kwargs) }}
</label>
{% endmacro %}

Usage:

{{ render_field(field, id=False) }}

Explaination: Because you have ****kwargs**, you can make the id=False and that would be more dymanic. You can choose when to remove ID. Hope this help for those who have googled this solution

Granit
  • 188
  • 1
  • 11