HubSpot macro not outputting markup - html

I have a my_macro.html defined which currently looks like this:
<!--
templateType: "none"
isAvailableForNewContent: false
-->
{% macro video_card(background_image, video_link) %}
<div class="videoCard" style="background-image: url({{ background_image }});">
<a class="button--play" id="play-video"></a>
<h1>test</h1>
</div>
{% endmacro %}
In HubSpot, within my custom module, I'm trying to use this macro. I have the following:
{% import '/website/assets/hubl/my_macros.html' as macros %}
<div class="hero">
<div class="hero__video">
{{ macros.video_card }} <!-- this is where I'm trying to print markup -->
</div>
</div>
However, on the output, where I should expect the markup, I see the following message:
com.hubspot.jinjava.lib.fn.MacroFunction#9d25d51
Unsure why? I've followed the documented import and my_macro.html file name structure defined here.

your macro has 2 parameters video_card(background_image, video_link), but in your template
{{ macros.video_card }} <!-- this is where I'm trying to print markup -->
you forgot to pass any parameters ?
it sould be like:
{{ macros.video_card('bg-image.png', 'video.mp4') }}

For anyone wondering, the correct way to use macros in a custom module would be:
{% from '/website/assets/hubl/my_macros.html' import videoCard %}
And its usage would be:
{{ video_card('image.jpg') }}

Related

<ol> tag doesn't increment from 1 and stays at 1 while using in a 'for' loop in HTML

Firstly, I don't know anything about HTML. I am trying to build a website using Jekyll and found a template for the website, to which I am making modifications.
I have the following code:
{% for publi in site.data.publist %}
{% assign even_odd = number_printed | modulo: 2 %}
{% if even_odd == 0 %}
<div class="row">
{% endif %}
<div>
<ol>
<li>{{ publi.title }}</li>
<!-- <img src="{{ site.url }}{{ site.baseurl }}/images/pubpic/{{ publi.image }}" class="img-responsive" width="33%" style="float: left" />
--> <p>{{ publi.description }}</p>
<p><em>{{ publi.authors }}</em></p>
<p><strong>{{ publi.link.display }}</strong></p>
<!-- <p class="text-danger"><strong> {{ publi.news1 }}</strong></p>
<p> {{ publi.news2 }}</p> -->
</ol>
</div>
{% assign number_printed = number_printed | plus: 1 %}
{% if even_odd == 1 %}
</div>
{% endif %}
{% endfor %}
There is a YAML file in the site.data.publist which has a number of members, each with different fields. The for loop helps to go through all the members of the YAML file.
As you can see in the code, I am using the <ol> tag in the for loop and I have used the <li> tag for the publi.title (a field in the members of the YAML file). But all I get is one repeating for all the members in the YAML file. I have attached the output I get.
As sirko mentioned in his comment, you are generating invalid HTML.
First of all, the <ol> may only contain li as direct children. So make sure to put everything else also within the li tag.
But your real problem is that you generate the ol tags within your loop. As mentioned in the comment, your output the contains multiple lists with one element each, not one list with n elements.
In order to change that, you have to move the ol outside of the for loop. (And then make sure you still generate valid HTML => see point 1.)

Loop through a list of macros using jinja

I want to know if its possible to loop through a list of macros in another macro in Jinja.
For example:
{% set macro_list = [macro_one,macro_two,macro_three] %}
{% for macro in macro_list%}
{{ macro(param) }}
{% endfor %}
Similar to how in python you can loop through a list of functions. Currently this does not work for me, as the macro name is being recognized as a string and not a reference to a macro.
Do you really want references to macros?
Keep it simple and try to use macros with parameter, see Jijnja documentation. Then you can use the code as the following example:
{% macro example(counter) %}
<p>Example {{ counter }}</p>
{% endmacro %}
{% for i in range(1, 4) %}
{{ example(i) }}
{% endfor %}
This gives you:
<p>Example 1</p>
<p>Example 2</p>
<p>Example 3</p>
I have resolved the problem.
You can also qualify a macro in your own project by prefixing it with your package name (this is mainly useful for package authors).
source
An example:
[% set list = ["macro_one","macro_two]%]
{% for macro in list%}
{{ package_name[macro](params) }}
{% endfor %}

SqlAlchemy query db.session.query() output format into HTML

I am running a db query with sqlalchemy and then pushing this output into an HTML page with flask and python. However, the output is formatted as a list, and I am trying to remove the quotes around it and format it nicer.
# views.py
#buyers_blueprint.route('/welcome')
#login_required
def welcome_user():
user = current_user
events = db.session.query(Events.eventname)
return render_template('welcome.html', user=user, events=events)
The welcome.html page is simple and looks like this
welcome.html
{% extends "base.html" %}
{% block content %}
<div class="jumbotron">
<h1>Events Dashboard</h1>
<p>{{user}}! You are logged in.<br>
Here is a list of your events</p><br>
<p>
{% for event in events %}
<li>{{event}}</li>
{% endfor %}
</p>
</div>
{% endblock %}
The output looks like this.
('Event 1',)
('Event 2',)
How do I remove the quotes, and comma to format it so it looks nicer? Thank you so much.
So, thanks to help from others, I came up with an answer. In the HTML, I just needed to ask for the first in tuple.
welcome.html
{% extends "base.html" %}
{% block content %}
<div class="jumbotron">
<h1>Events Dashboard</h1>
<p>{{user}}! You are logged in.<br>
Here is a list of your events</p><br>
<p>
{% for event in events %}
<li>{{event[0]}}</li>
{% endfor %}
</p>
</div>
{% endblock %}

Django - Generalising a Template with Optional Sidebar

I have a working solution for a template that allows for optional sidebars. Depending on the options selected by the user; significant DOM manipulations occur.
The working solution is unnecessarily large and features some code duplication. It also doesn't extend nicely.
I'm looking for a far more generic solution. One that allows for easier extending or abstracting so as to not have to repeat myself for every page that features a sidebar.
The Working Solution
{% extends "app/base.html" %}
{% load wagtailcore_tags %}
{% block content %}
{% if self.sidebar == "left" %}
<div class="row">
<div class="4u 12u(mobile)">
{% include "app/includes/sidebar.html" with sidebar_items=self.sidebar_items.all %}
</div>
<div class="8u 12u(mobile) important(mobile)">
<article class="box post">
{% include "app/includes/banner.html" with feed_image=self.feed_image only %}
{{ self.body|richtext }}
{% include "app/includes/related_links.html" with related_links=self.related_links.all only %}
</article>
</div>
</div>
{% elif self.sidebar == "right" %}
<div class="row">
<div class="8u 12u(mobile)">
<article class="box post">
{% include "app/includes/banner.html" with feed_image=self.feed_image only %}
{{ self.body|richtext }}
{% include "app/includes/related_links.html" with related_links=self.related_links.all only %}
</article>
</div>
<div class="4u 12u(mobile)">
{% include "app/includes/sidebar.html" with sidebar_items=self.sidebar_items.all %}
</div>
</div>
{% else %}
<article class="box post">
{% include "app/includes/banner.html" with feed_image=self.feed_image only %}
{{ self.body|richtext }}
{% include "app/includes/related_links.html" with related_links=self.related_links.all only %}
</article>
{% endif %}
{% endblock %}
{% block content %} is first defined here in app/base.html:
<div id="main-wrapper">
<div class="container">
<!-- <article class="box post"> -->
{% block content %}{% endblock %}
<!-- {% include 'app/includes/prev_next.html' %} -->
<!-- </article> -->
</div>
</div>
And sidebar.html looks like this:
{% load wagtailimages_tags %}
{% for sidebar_item in sidebar_items %}
<section class="box">
{% image sidebar_item.image original as img %}
<img src="{{ img.url }}" alt="" />
<header>
<h3>{{ sidebar_item.title }}</h3>
</header>
<p>{{ sidebar_item.body }}</p>
{% if sidebar_item.button_text %}
<footer>
{{ sidebar_item.button_text }}
</footer>
{% endif %}
</section>
{% endfor %}
My initial attempt at generalising it was to try to do all of the conditionals in app/base.html but I faced issues when it came to optionally the location of {{ block content }}.
Any help greatly appreciated.
If the condition to decide type of sidebar are being decided and supplied by the views.py function serving the page, then the best approach would be to simply make different template for each different page.
This solution sounds overly simple, but if correctly modularized(in terms of all the common code being kept in a basefile and being extended as and when needed), this would be the best approach. Even though the number of other templates might increase, it will give shorter load times because of smaller HTML snippets.
In case you do not want the conditional decisions being handled by views.py , you can alternatively use AJAX, and asynchronously change the template being viewed without causing a reload.
Hope this helps!

How to use multiple objects in a single Django template for loop? [duplicate]

So here's my problem: I've got a bunch of instances of a class. I would like to have a sort of table of these instance objects, so that there is a maximum of six in every row. In bootstrap terms, I would like each object to be represented by a thumbnail in a "div" of class "span2".
My initial impulse was to use a nested for loop, but I am having trouble manipulating my index variable in the template, and I can't figure out how to do so outside of my template.
Here is generally what the python/django template/pseudo code is I'm trying to figure out.
queryset = Class.objects.all()
set_length = queryset.count()
num_rows = set_length/6
#because I want 6 columns in each row, each with one instance
set_as_list = list(queryset)
# have a list so I can iterate through objects by index
for i in range(table_rows):
# make a row
<div class="row">
for j in range (i*6,(i+1)*6):
#make six or less columns
<div class="span2">
<p>set_as_list[j].attribute1</p>
<p>set_as_list[j].attribute2</p>
</div>
</div> # end row
I hope this flagrant mixing of django templating language, python, and html doesn't offend anybody too badly. just trying to express the idea of what I'm trying to do. I would appreciate any help someone may be willing to offer because I've been struggling with this for days and have done quite a bit of searching for a solution both within a template and outside.
I also realise that there will be need to be a final row with the remainder of objects after the integer division.
Have no time to explain, but I've had similar problem and until i closed this browser page here is a solution
{% for sub_article in articles %}
{% if forloop.first %}<div class="row">{% endif %}
<div class="col-xs-4">
<a href="#">
{{ sub_article.name }}
</a>
</div>
{% if forloop.counter|divisibleby:3 %}</div><div class="row">{% endif %}
{% if forloop.last %}</div>{% endif %}
{% endfor %}
Since forloop.counter starts the index with 1, divisibleby 3 does not work.
So use forloop.counter0 instead.
<div class="row">
{% for product in all_products %}
{% if forloop.counter0|divisibleby:3 %}
</div><br><div class="row">
{% endif %}
<div class="col-4"></div>
{% endfor %}
I would recommend to add a custom tag as_chunk. I think it makes the code prettier and more readable.
# app/templatetags/my_tags.py
from math import ceil
from django import template
register = template.Library()
#register.filter
def as_chunks(lst, chunk_size):
limit = ceil(len(lst) / chunk_size)
for idx in range(limit):
yield lst[chunk_size * idx : chunk_size * (idx + 1)]
# app/templates/your-template.html
{% load my_tags %}
...
{% for chunk in elements|as_chunk:6 %}
<div class="row">
{% for element in chunk %}
<div class="col-2">
{{ element.name }}
</div>
{% endfor %}
</div>
{% endfor %}
...
maybe too late but there is simple solution as follow
<div class="container">
<div class="row">
{% for product in products %}
{% if forloop.counter0|divisibleby:3 and not forloop.first %}<div class="w-100"></div>{% endif %}
<div class="col">{{product.title}}</div>
{% endfor %}
</div>
</div>
You could make the code a bit more generic. Here's the logic:
queryset = Class.objects.all()
set_length = queryset.count()
<div class="row">
{% for i in queryset %}
<div class="span2">
<p>i.attr</p>
<p>i.attr</p>
</div>
{% if forloop.counter|divisibleby:"6" or forloop.last %}
</div> <!--end row-->
{% endif %}
{% endfor %}
I hope this solves your problem :-)