How can i append twig templates inside a loop? - drupal

Here i am iterating through a loop and rendering different twig templates inside a div with id {{ divId }} on the action of click. But when i am doing this, the html is rendering separately instead of rendering inside the div. Here i am attaching the code and image to further explain the issue.
<script id="template_{{ field_id }}" type="text/html">
{% set scriptSeperatorId = 'separator_' ~ field_id ~ "-" ~ '{section_id}' %}
<span class="sepRater" id="{{ scriptSeperatorId }}"></span>
{% set divId = field_id ~ '-{section_id}' %}
<div id="{{ divId }}">
{% for multi_input_template_field_key, multi_input_template_field_details in multi_input_template_fields %}
{% set multi_input_template_field_id = field_id ~ '-' ~ '{section_id}' ~ '-' ~ multi_input_template_field_key %}
{% set multi_input_template_field_name = field_name ~ ':' ~ '{section_id}' ~ ':' ~ multi_input_template_field_key %}
{% set multi_input_template_field_value = '' %}
{% if multi_input_template_field_details[default] is defined %}
{% set multi_input_template_field_value = multi_input_template_field_details.default %}
{% endif %}
{% set view_data = {} %}
{% set view_data = view_data|merge({'field_id': (multi_input_template_field_id)}) %}
{% set view_data = view_data|merge({'field_name': (multi_input_template_field_name)}) %}
{% set view_data = view_data|merge({'field_value': (multi_input_template_field_value)}) %}
{% set view_data = view_data|merge({'field_details': (multi_input_template_field_details)}) %}
{% set data = {} %}
{% set data = data|merge({'view_data': (view_data)}) %}
{% set data = data|merge({'field_details': (multi_input_template_field_details)}) %}
{% set data = data|merge({'categories': (categories)}) %}
{% include "field-type-render.html.twig" with data %}
{% endfor %}
<div class="form-box">
<label class="pure-material-textfield-outlined smBtnArea">
<button type="button" class=" btn btn-info btn-ad removeBtn" id="remove_multiinput_section_{{ field_id }}-{section_id}">Remove</button>
<span style="color:red;display:none;" class="spancantremove{{ field_id }}-{section_id}">You can't remove the last element </span>
</label>
</div>
</div>
</script>
The type of output i am supposed to get is:
The output i am getting:

Related

Drupal 8 Twig Entity Reference Sub Fields Templating

I'm trying to display sub fields of a multi value entity reference.
Tried:
{% for item in node.field_related_items %}
{{ item.content['#node'].field_author.value }}
{% endfor %}
Also:
{% for item in content.field_related_items %}
{{ item.field_author }}
{% endfor %}
If I do the following:
{% for item in node.field_related_items %}
{% set img1 = item.entity.field_featured_image %}
{{ img1 }}
{% set label1 = item.entity.label %}
{{ label1 }}
{% endfor %}
The label works, but not the image...
Same thing with:
item.entity.field_featured_image.value
No success,
Still not sure how to display sub fields of the entity reference...
Please help!
The answer to image, taxonomy, links and plain fields templating:
{% for item in node.field_related_items %}
<div class="col-sm-12 col-md-4">
<div class="img-wrap">{{ file_url(item.entity.field_featured_image.entity.uri.value) }} </div>
{% set cat1 = item.entity.field_blog_category.entity.label %}
<div class="cat-wrap">{{ cat1 }}</div>
{% set label1 = item.entity.label %}
<div class="title-wrap">{{ label1 }}</div>
{% set aut1 = item.entity.field_author.value %}
<div class="author-wrap">By <span>{{ aut1 }}</span> |
{% set date1 = item.entity.field_publish_date.value %}
{{ date1 }}</div>
Link
</div>
{% endfor %}

How to change "if" condition related to a page

I would like to include tab_system.twig file in two differents files : archive.twig and blog_list.twig to have the same html in those two files.
{% include "tab_system.twig" %}
In this tab_system.twig file I have a condition to add the active class :
{% if XXX %}active{% endif %}
But this condition must be different depending on which page the user is.
For blog_list.twig :
{% if loop.first %}active{% endif %}
For archive.twig :
{% if item.term_id == term_page.term_id %}active{% endif %}
I wrote this without success :
{% set addclass = '' %}
{% if is_blog_list %}
{% set addclass = '{% if loop.first %}active{% endif %}' %}
{% elseif is_archive %}
{% set addclass = '{% if item.term_id == term_page.term_id %}active{% endif %}' %}
{% endif %}
In tab_system.twig I have a tab system with menu from a part and content to the other part. I wrote a js loop to display the corresponding content. I need to add active class on the first link and first content tab in blog_list.twig file and to add active class to the link and content tab depending on which category the user is.
<div class="tab-menu-list">
{% for item in all_posts %}
<a href="#" class="tab-menu {{ addclass }}"</a>
{% endfor %}
</div>
<div class="tab-content-list">
{% for item in all_posts %}
<div href="#" class="tab-content {{ addclass }}"</div>
{% endfor %}
</div>
is_archive and is_blog_list are variables defined elsewhere. They work
How can I create a condition ? Thank you in advance.
As I'm assuming you are looping the records, I'd say don't overcomplicate things,
single.twig
{% for i in 1..5 %}
{% include 'article.twig' with { 'active' : loop.first, } %}
{% endfor %}
template_blog.twig
{% for item in items %}
{% include 'article.twig' with { 'active' : item.term_id == term_page.term_id, } %}
{% endfor %}
article.twig
<div class="articles__list tab-content{{ active ? ' active'}}">
foo
</div>
demo - just change the main template
If you really wanted to keep that for inside the article template, which I think is not a great idea, you could still use the variables is_archive and is_blog_list inside article, e.g.
article.twig
{% for item in items %}
{% if is_archive %}
{% set active = loop.first %}
{% elseif is_blog_list %}
{% set active = item.term_id == term_page.term_id %}
{% endif %}
<div class="articles__list tab-content{{ active ? ' active'}}">
{% endfor %}

How can I render product category and it's subcategory list alphabetically sorted in Django-Oscar?

I can render the product category list in template. But the category list are not showing in alphabetical order. How can I render them in alphabetical order ?
Edit
I am using the following code to render categories and subcategories.
<ul class="cd-accordion-menu animated">
{% for tree_category, info in tree_categories %}
<li {% if info.has_children %}class="has-children"
{% else %}{% endif %}>
{% if info.has_children %}
<input type="checkbox" name="{{ tree_category.name|lower }}"
id="{{ tree_category.name|lower }}">
<label for="{{ tree_category.name|lower }}">{{ tree_category.name|safe }}
{% else %}
{{ tree_category.name|safe }}
{% endif %}
{% if info.has_children %}</label>{% endif %}
{% if info.has_children %}
<ul>
{% endif %}
{% for n in info.num_to_close %}
</ul>
</li>
{% endfor %}
{% endfor %}
</ul>
This shows the categories as below.
I had the same requirement, and ended up customising the category_tree template tag. I copied the original implementation of category_tree (see link) and added a sorting step to sort. Only one lined changed in comparison to the original category_tree template tag.
from django import template
from oscar.core.loading import get_model
register = template.Library()
Category = get_model('catalogue', 'category')
#register.assignment_tag(name="category_tree")
def get_annotated_list(depth=None, parent=None):
"""
Gets an annotated list from a tree branch.
Borrows heavily from treebeard's get_annotated_list
"""
# 'depth' is the backwards-compatible name for the template tag,
# 'max_depth' is the better variable name.
max_depth = depth
annotated_categories = []
start_depth, prev_depth = (None, None)
if parent:
categories = parent.get_descendants()
if max_depth is not None:
max_depth += parent.get_depth()
else:
categories = Category.get_tree()
info = {}
# CUSTOM SORTING HERE
for node in sorted(categories, key=lambda x: x.name):
node_depth = node.get_depth()
if start_depth is None:
start_depth = node_depth
if max_depth is not None and node_depth > max_depth:
continue
# Update previous node's info
info['has_children'] = prev_depth is None or node_depth > prev_depth
if prev_depth is not None and node_depth < prev_depth:
info['num_to_close'] = list(range(0, prev_depth - node_depth))
info = {'num_to_close': [],
'level': node_depth - start_depth}
annotated_categories.append((node, info,))
prev_depth = node_depth
if prev_depth is not None:
# close last leaf
info['num_to_close'] = list(range(0, prev_depth - start_depth))
info['has_children'] = prev_depth > prev_depth
return annotated_categories
PS: check the django docs if you don't know how to include custom templatetags, they need to go in a dedicated folder.
Template code:
<ul class="cd-accordion-menu animated">
{% for tree_category, info in tree_categories %}
<li {% if info.has_children %}class="has-children"
{% else %}{% endif %}>
{% if info.has_children %}
<input type="checkbox" name="{{ tree_category.name|lower }}" id="{{ tree_category.name|lower }}">
<label for="{{ tree_category.name|lower }}">{{ tree_category.name|safe }}</label>
{% else %}
{{ tree_category.name|safe }}
{% endif %}
{% if info.has_children %}
<ul>
{% else %}
</li>
{% endif %}
{% for n in info.num_to_close %}
</ul>
</li>
{% endfor %}
{% endfor %}
</ul>
Just try to order the MP_Node.
class Category(AbstractCategory):
node_order_by = ['name']

Shopify: how to add a class depending on collection

On a clients homepage they want 'all the products' listed with a load more button at the bottom.
There are four categories and each has a different color associated. I want to pull in all the products by date listed order and apply a class to the product depending on the category.
Currently I have
{% assign collection = collections.all %}
{% for product in collection.products %}
{% if collection.handle == 'clothing' %}
<div class="theme-red overview-item">
{% elsif collection.handle == 'pictures' %}
<div class="theme-green overview-item">
{% elsif collection.handle == 'posters' %}
<div class="theme-blue overview-item">
{% elsif collection.handle == 'other' %}
<div class="theme-beige overview-item">
{% else %}
<div class="theme-none overview-item">
{% endif %}
...
</div>
{% endfor %}
This is currently picking up as theme-none and that's because I'm calling collections.all?
How do I get all the products shown regardless of a collection and then apply do something as per the if/else statements like above.
Any ideas, I've tried to see if product.collections, collection.all_types with no happiness.
The reason you're getting theme-none is because your if statement checks if the collection's handle is 'clothing', 'pictures', etc. but you've set the collection to collections.all so it's never going to match any of those conditions.
What you want to do instead is check if the current product is within one of those collections. For example:
{% assign collection = collections.all %}
{% for product in collection.products %}
{% for c in product.collections %}
{% if c.handle == 'clothing' %}
{% assign theme = "red" %}
{% elsif c.handle == 'pictures' %}
{% assign theme = "green" %}
{% elsif c.handle == 'posters' %}
{% assign theme = "blue" %}
{% elsif c.handle == 'other' %}
{% assign theme = "beige" %}
{% else %}
{% assign theme = "none" %}
{% endif %}
{% endfor %}
<div class="theme-{{ theme }} overview-item">
...
</div>
{% endfor %}

Symfony2 Change class name in twig form theme

I want to override form_widget_simple function
{% block form_widget_simple %}
{% spaceless %}
{% set type = type|default('text') %}
{% if errors|length > 0 %}
{{dump(form.vars.attr)}}
{% endif %}
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{% endspaceless %}
{% endblock form_widget_simple %}
but I dont know how to set form.vars.attr['class'] inside if statement
Whent I do set form.vars.attr['class'] = 'error'; I get error Unexpected token "punctuation" of value "." ("end of statement block" expected)
As you see, adding additional attributes is handled in the widget_attributes block. If you take a look in there, you see a simple foreach over the attr array, with all the attributes. I think a simple set with merging existing one, could be done. So your form_widget_simple block will look like
{% block form_widget_simple %}
{% spaceless %}
{% set type = type|default('text') %}
{% if errors|length > 0 %}
{{dump(form.vars.attr)}}
{% endif %}
{% set attr = attr|merge({'class': (attr.class|default('') ~ ' your-css-class')|trim}) %}
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{% endspaceless %}
{% endblock form_widget_simple %}
This will preserve every class attribute set in the form builder and add your-css-class as additional class. If no class attribute is defined, only your-css-class is set.

Resources