Jinja & Wtforms- check if html attribute has been defined - html

Let's say I have a form with a hundred fields. Some of them have description defined:
i.e. Sales=IntegerField('Sales', description='Annual Sales')
some of them do not:
i.e. Name=TextField('Full Name')
in Jinja, how can I check whether description has been set or not?
I've tried
{% for field in form %}
{% if field.description != None %}
<h2>{{field.description}}</h2>
{{field.label}}
{{field}}
{% endif %}
{% endfor %}
I'm trying to iterate through the fields, and create an html header to group the fields into sections.
I was also doing
{%set currDesc="nothing"%}
{%for field in form %}
{% if field.description != currDesc %}
<h2>{{field.description}}</h2>
{% set currDesc= field.description %}
{% endif %}
{% endfor %}
but it ends up creating a ton of <h2>s

upon further research, we can check whether an attribute is defined explicitly in wtforms by using an empty string comparison:
{% if field.description =! '' %}
<h2>{{field.description}}</h2>
{% endif %}

Related

Jekyll nested include with for loop

I'd like to use a {% for %} loop in an included file, to avoid repeating logic to create the loop array (it's an assign with multiple where_exps).
But I'd like to use different content depending on where I include the loop, so sometimes I will do this:
{% for i in a %}
<li>{{ i.name }}</li>
{% endfor %}
and sometimes:
{% for i in a %}
<loc>{{ i.url }}</loc>
{% endfor %}
How can I achieve this? So far I have to put each of the inner contents in their own template, so I would have files like below, but I'd like to avoid the extra template files, and just keep that content in the appropriate main file:
html_template.html:
<li>{{ i.name }}</li>
xml_template.xml:
<loc>{{ i.url }}</loc>
page_loop.html:
{% assign a = "logic I don't want to repeat" %}
{% for i in a %}
{% include {{ include.inner_template }} %}
{% endfor %}
html_main.html:
{% include page_loop.html inner_template="html_template.html" %}
xml_main.xml:
{% include page_loop.html inner_template="xml_template.xml" %}
It would probably be another more elegant (?) solution developing a plugin, but quickly modifying your code, in _includes/page_loop.html:
{% assign a = "something" %}
{% for i in a %}
{%if include.type == "name"%}
<li>{{ i.name }}</li>
{%else if include.type == "url"%}
<loc>{{ i.url }}</loc>
{%endif %}
{% endfor %}
Then each time you include page_loop.html pass an additional parameter specifying which type of output you want:
{% include page_loop.html type="name" %}
or
{% include page_loop.html type="url" %}

How to select specific items in Liquid

Assuming I have a list of tags: iFix_6.3, iFix_7.0, iFix_7.1, iFix_8.0, announcement, and so on... and I want to run an operation only on certain several tags. How can I check for these multiple values?
There is contains, but I'm looking for the opposite of it and for multiple values...
Here is an example where I actually filter out all posts that contain the iFix_6.3 tag, thus display all other posts. This actually does not work yet... plus needs to be extended to work for multiple tags.
// posts with iFix_xxx tag should be filtered from the main posts view.
{% assign postUpdates = site.posts | where_exp:"item", "item.tags != 'iFix_6.3'" %}
{% for post in postUpdates limit:10 %}
<div class="postItem inline">
<p class="postDate">{% if post.pinned %}<span class="glyphicon glyphicon-pushpin"></span>{% endif %}{{post.date | date: '%B %d, %Y'}}</p>
<p class="postTitle">{{post.title}}</p>
</div>
{% endfor %}
You can do this by building an array of excluded tags (excluded_tags) using split and a string of the comma-separated tags. Then for each post, you iterate on the post's tags. Check if the tag is in excluded_tags using contains, if it is then raise the flag filtered_out to not display the post, using the unless control flow tag.
{% assign excluded_tags = "iFix_6.2,iFix_6.3,announcement" | split : "," %}
{% for post in site.posts limit:10 %}
{% assign filtered_out = False %}
{% for tag in post.tags %}
{% if excluded_tags contains tag %}
{% assign filtered_out = True %}
{% break %}
{% endif %}
{% endfor %}
{% unless filtered_out %}
...
{% endunless %}
{% endfor %}
Seems unless would solve the case.
{% assign postUpdates = site.posts | where_exp:"item", "unless item.tags contains 'iFix_6.3'" %}

Is there a way in Liquid to use the contains operator to check for an exact match?

When searching an array for a match in a Liquid template, how do you call contains exactly? For example, if tag of a page may contain separable or non-separable, how do you find the pages that contain only the separable and not the non-separable tag? In my experience, the {% if post.tags contains 'separable' %} statement considers both cases.
Refer to the documentation you can use this filter
{% assign tags = post.tags | where:"tag","separable" %}
Loop through the array and check the values with a match operator. If it matches change a variable from false to true:
{% assign found_seperable = false %}
{% for tag in post.tags %}
{% if tag == 'separable' %}
{% assign found_seperable = true %}
{% endif %}
{% endfor %}
Then check the variable:
{% if found_seperable %}
do what you want if true
{% else %}
do what you want if false
{% endif %}

How to delete the odd attributes while rendering form

I rewrite some widgets in bootstrap_3_layout.html.twig and I don't want the form fields to have some attributes while they are rendered.
I've found out the sequence of some widgets
button_widget → button_row → form_widget → widget_attributes
And I made a little change
{% block widget_attributes %}
{% spaceless %}
{# bla-bla-bla #}
{% for attrname, attrvalue in attr %}
{% if attrname in ['placeholder', 'title'] %}
{{ attrname }}="{{ attrvalue|trans({}, translation_domain) }}"
{% elseif attrname not in ['first','last','data-help'] %}
{{ attrname }}="{{ attrvalue }}"
{% endif %}
{% endfor %}
{% endspaceless %}
{% endblock widget_attributes %}
But it doesn't work for buttons.
I'm not sure what you are achieving but you can intercept the odd index of a twig loop as follow:
{% for attrname, attrvalue in attr %}
{% if loop.index is odd %}
odd
{% else %}
even
{% endif %}
{% endfor %}
More info on loop variable and odd test function.
Hope this help
It's strange, but the form layout in twig_bridge has some widgets to work with attributes.
1. for inputs `widget_attributes`
2. for buttons `button_attributes`
3. for another element `widget_container_attributes`
For each widget, there are next blocks in twig-bridge:
{name_of_widget}_widget - main block to render an element
{name_of_widget}_label
{name_of_widget}_row
And for attributes, there are
widget_attributes
widget_container_attributes
button_attributes
attributes
I just used incorrect one :)
Thank all for your patience.

How can I loop on all items where a certain field is not empty?

I want to loop over all items in a collection that have a certain field set (not empty). I tried this:
{% assign papers_with_demos=site.data.papers | where:"demo", not blank %}
{% if papers_with_demos.size > 0 %}
<h2>demos</h2>
{% for paper in papers_with_demos %}]
...
{% endfor %}
{% endif %}
but it does not work; all papers are returned.
My goal is that the heading "demos" will be shown, only if there is one or more paper with a demo.
If papers are being returned, you must be using data files. If a value is empty for a particular key in a data file it will return false. So you could check the data key with a forloop like:
{% for paper in site.data.papers %}
{% if paper.demo %}
something
{% endif %}
{% endfor %}
You'll find more info in the Data Files section of the Jekyll documentation.
Updated in response to your reply:
{% for item in site.data.items %}
{% if item.random %}
{% assign random-val = item.random %}
{% if random-val %}
<p>true</p>
{% endif %}
{% endif %}
{% endfor %}
This will return true if inside items.yml, you have - random: true, nothing if empty.