Jack Evans
Jack Evans

Reputation: 1717

Django pass template variable to custom templatetag

I'd like to display django my error messages inside the form as a placeholder, instead of above the form input box itself. Is this possible in Django, or would I have to achieve this by writing some Javascript?

    <div class="form-group">

        {% if login_form.password.errors %}
            {% for error in login_form.password.errors %}
                <p>{{ error }}</p>
            {% endfor %}
        {% endif %}

        <div class="input-group">
            <span class="input-group-addon"><i class="fa fa-key fa-fw"></i></span>
            {{ login_form.password | placeholder:"password" | addClass:"form-control" }}
        </div>

    </div>

Specific lines of interest. I'd like to change this:

{{ login_form.password | placeholder:"password" | addClass:"form-control" }}

To this

{{ login_form.password | placeholder:{{ error }} | addClass:"form-control" }}

where {{error}} is an the Django error message thrown by the form

I'm thinking there must be some way of getting the string value of a template variable, but can't find any answers

EDIT: I've tried the following, to no avail

<div class="form-group">
    {% if login_form.password.errors %}
        {% for error in login_form.password.errors %}
            <div class="input-group">
                <span class="input-group-addon"><i class="fa fa-key fa-fw"></i></span>
                {{ login_form.password | placeholder:{{ error|escape }} | addClass:"form-control" }}
            </div>
        {% endfor %}
    {% endif %}
</div>

My custom templatetag looks as follows

@register.filter(name='placeholder')
def placeholder(value, token):
    value.field.widget.attrs["placeholder"] = token
    return value

Django throws a TemplateSyntax Error complaining that:

placeholder requires 2 arguments, 1 provided

Upvotes: 0

Views: 972

Answers (3)

joanbm
joanbm

Reputation: 811

First, the nested expression in django template system is incorrect, so placeholder's filter argument shouldn't be enclosed in double brackets, but written directly:

{{ login_form.password | placeholder:error | addClass:"form-control" }}

Here, error variable is correctly evaluated in context of outer curly brackets scope.

Second, I'd suggest make sure about filter argument's type. If you do expect string value, you may use built-in filter to make an explicit conversion:

{% with err_msg=error|stringformat:"s" %}
{{ login_form.password | placeholder:err_msg | addClass:"form-control" }}
{% endwith %}

Upvotes: 2

Leonard2
Leonard2

Reputation: 890

I have not tested yet, but this may work:

# forms.py
class MyForm(forms.Form):
    class meta:
        model = MyModel

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        error_messages = self.fields['myfield'].error_messages
        self.fields['myfield'].widget.attrs.update({'placeholder': error_messages})

Upvotes: 1

Mevin Babu
Mevin Babu

Reputation: 2475

This can be done.

{{ login_form.password.errors }}

Here's the relevant documentation for that https://docs.djangoproject.com/en/1.9/topics/forms/#rendering-form-error-messages

The piece of code should be re-written as

{{ login_form.password | placeholder:"password" | addClass:"form-control" }}
{% if login_form.password.errors %}
   <span class="error">{{ login_form.password.errors }}</span>
{% endif %}

or can be done in this way too

{{ login_form.password | placeholder:"password" | addClass:"form-control" }}
<input type="password" class="form-control" placeholder="
{% if login_form.password.errors %}
   {{ login_form.password.errors }}
{% else %}
   password
{% endif %}
">

Upvotes: 1

Related Questions