Including novalidate attribute into Symfony2 twig template - html

I am trying to disable the HTML5 validation of my form and I have seen I can include the novalidate into the form tag however I am using
{{ form_start(contact) }}
{{ form_end(contact) }}
to create my forms.
Now from the what I have been reading I should be able to include an attribute into the form_start such that the code would give me this
{{ form_start(contact, {'attr' : {'novalidate'}})
This however is not working...does anyone have any ideas?

You need a key/value pair:
{{ form_start(contact, {attr: {novalidate: 'novalidate'}}) }}

If you want to add novalidatein all the forms of your app, create a twig template like this:
{% extends 'form_div_layout.html.twig' %}
{# FORM START #}
{% block form_start %}
<form action="{{ action }}"{% for attrname, attrvalue in attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}{% if multipart %} enctype="multipart/form-data"{% endif %} novalidate>
{% endblock form_start %}
Documentation: Form Theme

You can set form novalidate attribute to symfony 2 form object like this
$form = $this->createForm(new ClientType(), $clientEntity, array(
'action' => $this->generateUrl('client_create'),
'method' => 'POST',
'attr'=>array('novalidate'=>'novalidate') //add novalidate attribute to form
));

You can use function createFormBuilder()->setAttributes() to set any attributes to the whole form, including novalidate:
$form = $this->createFormBuilder($task)
->add('value', IntegerType::class)
->add('save', SubmitType::class, array('label' => 'Save',))
->setAttributes(array(
'novalidate'=>'novalidate',
))
->getForm();

Related

Calling a view as a value for action's attribute in HTML forms that leads to a NoReverseMatch error

I am creating a web application using django, and I want now to add a view that modifies entries (my web application is an encyclopedia, so the view let us editing the page).
We may be able to access the editing page by cliking on the link of this html page:
{% extends "encyclopedia/layout.html" %}
{% block title %}
{{ title }}
{% endblock %}
{% block body %}
{{ html | safe }}
{% if exists %}
<br><br><br><br>
Edit encyclopedia
{% endif %}
{% endblock %}
So django'll go through this url
urlpatterns = [
...
...
...
path("<str:title>/edit", views.edit, name="edit"),
]
Then, this url should bring us to a this view:
def edit(request, title):
if request.method == "POST":
form = NewForm(request.POST)
if form.is_valid():
with open(f"entries/{title}.md", "w") as file:
file.write(form.cleaned_data["content"])
return redirect(reverse("encyclopedia:display"))
else:
return render(request, "encyclopedia/edit.html",{
'form' : NewForm(),
'message' : """<div class="alert alert-danger" role="alert">
Your entries are empty.
</div>"""
})
markup = util.get_entry(title)[0]
print(request.)
return render(request, "encyclopedia/edit.html",{
'form' : NewForm(),
'title' : title,
'markup': markup,
})
And here is my html file:
{% extends "encyclopedia/layout.html" %}
{% block title %}
Edit
{% endblock %}
{% block body %}
<h1>New Encyclopedia</h1>
<p>Our websites' encyclopedias are written in a langage names Markdow<br>
You may have additionnal informations about this language here.</p>
<form action="{% url 'encyclopedia:edit' %}" method="POST" style="display: block; text-align: center; padding: 20px;">
{% csrf_token %}
<p style="margin: 15px;">{{ title }}</p>
<textarea rows='10' placeholder="Encyclopedia's content" name="content" style="width: 90%; margin: 15px;">{{ markup }}</textarea>
<input type="submit" value="Edit" style="width:15%">
</form>
{% endblock %}
But my problem is that when I run my application, and go to the editing page, I get a NoReverseMatch error just like this one:
NoReverseMatch at /wiki/Django/edit
Reverse for 'edit' with no arguments not found. 1 pattern(s) tried: ['wiki/(?P[^/]+)/edit$']
I think that this problem is linked to the fact that I don't give the title argument when I call the editing view in my form, but I don't know how to do this.
If anyone could help me that would just be amazing, I made many researches, but couldn't really understand how to fix the problem...
I've finally found the origin of the error, to whom it may help, it was that I forgott to add the 'title' variable (that is obligatory for my view) just like this:
else:
return render(request, "encyclopedia/edit.html",{
'form' : NewForm(),
'message': """<div class="alert alert-danger" role="alert">
Your entries are empty.
</div>""",
'title' : title,
})
The is_valid() method doesn't really corresponds to how do I want to treat data, I've replaced it with this function:
undecodables = ["è", "à", "é"]
def own_validation(string):
try:
valid = False
for i in string:
if i.isalnum : valid = True
assert i not in undecodables
except AssertionError:
return False
else:
return valid
I don't know what are all the undecodable characters, so the list'll be completed in the future.
Thanks to #iklinac for your help !

How do I access a data value in a dictionary in the html template

I'm passing a dictionary in the context in my views.py to my html template. How do I know access a value in the template based on a particular key. For instance I'd wanna do something like {{ dictionary.keyname.value }} but I don't know the correct syntax and for some reason I can't seem to find the documentation.
I want to achieve the same effect as this without having to use a for loop:
<b>Calories</b>
{% for key, value in output.items %}
{% if key == "calories" %}
{{ value }}
{% endif %}
{% endfor %}
You just want {{ output.calories }}.

how to use django widget tweaks and combine template class string and widget attr attributes string name

I am trying to customise a django form for use with bootstrap 4, custom html layout & per field class or id names on the FormModel defintion
I have the following html
{% for hidden_field in form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
{% for field in form.visible_fields %}
<div class="form-group">
{{ field.label_tag }}
{% if form.is_bound %}
{% if field.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in field.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
{% endfor %}
And the following form defintion:
class DocumentForm(forms.ModelForm):
field1 = PartLookupField(required=True, widget=forms.TextInput(attrs={'class': 'field1-choice-ajax'}))
field2 = forms.CharField(required=True, widget=forms.TextInput(attrs={'id': 'field2-field'}))
form_lines = forms.CharField(widget=forms.HiddenInput())
class Meta:
model = Document
fields = ("field1", "field2", "form_lines")
So essentially, I need to get the per field definition of id or class, from the widget on the model, and combine that with the template defined form-control or is-valid/invalid classes in the template.
I've tried going down this route
How to concatenate strings in django templates?
But it just seems like it's going to end up in a huge mess.
Essentially, how can I combine template defined attributes and per field defined attributes? I need to end up with class="form-control field1-choice-ajax" for the field specified in the model (and the correct extra class names for the valid/invalid states).
Previously I was using the bootstrap4 form library, but I need complete control now:
{% csrf_token %}
{% bootstrap_form form %}
I've created my own template filter in order to add class attributes to existing form fields:
#register.filter
def add_class(field, css):
"""Add a class to a field in a template.
Example:
> {{ form.my_field|add_class:"required" }}
<input id="my_field_id" name="my_field" class="required" type="text">
Args:
field: this should be a form field, of type ``BoundField``
css: this should be a string with one or more class names separated by spaces
"""
class_old = field.field.widget.attrs.get('class', None)
class_new = class_old + ' ' + css if class_old else css
return field.as_widget(attrs={'class': class_new})
So now I can do this in a template:
{{ field|add_class:"is-valid" }}
Use Widget Tweaks.
It allows you to do something like:
{{ field|add_class:'form-control' }}

twig autoescaping html tags

{% autoescape false %}
{% set label = '<i class="flaticon solid plus-1"></i>Add User'|raw %}
{{ form_row(form.submit, { 'label': label }) }}
{% endautoescape %}
This is the output
<i class="flaticon solid plus-1"></i>Add User
How do I get it to not escape? If I just print out label instead of supplying it as a parameter to the "form_row" function, it prints out properly.
You're using the |raw filter at the wrong place - it is only processed when outputting data, not when setting a variable. You should patch it into the form_row function, or append it to it's call - can't be sure without seeing how that function works.
Most probably this will fix it:
{{ form_row(form.submit, { 'label': label })|raw }}
Since I assume it returns the modified string and lets the {{ tags handle output.
in form_div_layout.html.twig
change
<button type="{{ type|default('button') }}" {{ block('button_attributes') }}>{{ label|trans({}, translation_domain) }}</button>
to
<button type="{{ type|default('button') }}" {{ block('button_attributes') }}>{{ label|trans({}, translation_domain)|raw }}</button>
This seems like a hacky solution, since I'm modifying the stuff in the vendor folder.

Assign variables to child template in {% include %} tag Django

I have this code(which doesn't give me expected result)
#subject_content.html
{% block main-menu %}
{% include "subject_base.html" %}
{% endblock %}
#subject_base.html
....
....
<div id="homework" class="tab-section">
<h2>Homework</h2>
{% include "subject_file_upload.html" %}
</div>
child template:
#subject_file_upload.html
<form action="." method="post" enctype="multipart/form-data">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="submit">
</form>
and my view
#views.py
#login_required
def subject(request,username, subject):
if request.method == "POST":
form = CarsForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect("/")
form = CarsForm()
return render_to_response('subject_content.html', {'form':form}, context_instance=RequestContext(request))
The above code creates HTML in the way I want it to be, however the form does not update database.
BUT,
If I skip the middle template and go directly to the uploading form, it works fine:
#subject_content.html
{% block main-menu %}
{% include "subject_file_upload.html" %}
{% endblock %}
Help me please to make it work with middle template.
I want to do this, because I don't wan't to type the same code more than once.
Like #Besnik suggested, it's pretty simple:
{% include "subject_file_upload.html" with form=form foo=bar %}
The documentation for include mentions this. It also mentions that you can use only to render the template with the given variables only, without inheriting any other variables.
Thank you #Besnik