If Statement in Nunjucks Macro Not working - javascript

I'm new to Nunjucks. Am loving it so far but ran into an issue.
I just made a macro that will output a title & description. I also have if statement inside of my macro to show a particular div "if" I'm on a certain page.
My issue is that my "if statement" isn't working at all. Is it not possible to do a "if statement" in a macro like this? I know the if statement is working correctly. It works if I include the .njk template as an include. Here is an example:
{% macro titleInfo(title, description) %}
<div class="header-title text-white">
<div class="container">
<div class="row align-items-center">
<div class="col-sm-12 col-lg-9">
<h1>
{{title}}
</h1>
<p>
<small>
{{description | safe}}
</small>
</p>
</div> <!-- /.col -->
{% if active_page == 'check' %} {# this isn't working right now #}
<div class="col-sm-12 col-lg-3 text-lg-right frames-in-stock">
<p>
<strong>000</strong> of <strong>000</strong>
</p>
</div> <!-- /.col -->
{% endif %}
</div> <!-- /.row -->
</div> <!-- /.container -->
</div> <!-- /.header-title -->
{% endmacro %}
I'm including the macro and implementing it on my page like so:
{% extends "layout.njk" %}
{% set active_page = "check" %}
{% import "../templates/components/header-title.njk" as title %}
{% block content %}
{% include "components/header.njk" %}
{# {% include "components/header-title.njk" %} #}
{{
title.titleInfo (
'Your Inventory',
'Please check all that apply.'
)
}}
{% include "components/main-nav.njk" %}
{% endblock %}
Is it not possible to have an if statement in a macro? If it is possible, any direction on what I'm doing wrong would be great!

A macros doesn't have access to global scope when it define in separated file. You must pass active as variable to macros.
{% macro titleInfo(title, description, active) %} ...
Another way is using custom loader to substitution macros to main render page on run-time.
....
// rendered template
{% set active = true %}
{% enable SOMEMACRO %}
...
// somemacro.njk
{% macro SOMEMACRO %}
...
{% endmacro %}
...
// the custom loader implementation to support {% enable regexp-macro-name %}
let macros = fs.readdirSync('templates/macros')
.reduce(function (res, f) {
res[f] = fs.readFileSync(`templates/macros/${f}`, 'utf8');
return res;
}, {});
let CustomLoader = nunjucks.FileSystemLoader.extend({
getSource: function(name) {
let result = nunjucks.FileSystemLoader.prototype.getSource.call(this, name);
if (!result)
return null;
result.src = result.src.replace(/{%\senable\s(\S+)\s%}/g,
function(str, match, offset, s){
return Object.keys(macros)
.filter((key) => (new RegExp(match)).test(key))
.map((key) => macros[key] || '')
.join('\n');
}
);
return result;
}
});
let env = new nunjucks.Environment(new CustomLoader(['templates/']), {autoescape: true});
env.express(app);

Related

(JS) Markdown issue in flask

I have a small problem with markdown in my flash project.
I want markdown to work for all posts, currently it only works for the first post. I suspect I need to use some kind of loop, but I don't know what to do to make it work.
Code:
{% extends "layout.html" %}
{% block content %}
<article class="media content-section">
<div class="media-body">
{% for post in document.posts %}
<div class="article-metadata">
<h3><a class="article-title" href="{{ url_for('posts.post', post_id=post.id) }}">{{ post.title }}</a></h3>
<p class="article-content">{{ post.content }}</p>
</div>
{% endfor %}
</div>
</article>
<script>
const content_text = document.querySelector(".article-content");
content_text.innerHTML = marked(content_text.innerHTML);
</script>
{% endblock content %}
Pic of the posts on website
querySelector returns the first element with the class. You need to use querySelectorAll to get all the elements and then use for loop to loop and apply markdown to each element.
const content_text = document.querySelectorAll(".article-content");
for (i = 0; i < content_text.length; i++){
content_text[i].innerHTML = marked(content_text[i].innerHTML);
}

Create an iterative counter in DJango template

I've checked a lot of other questions and I haven't seen my particular scenario really addressed and I've tried a lot of things out without success.
What I have is a DJango for loop in my HTML code, and within the for loop is an if statement checking if each element from the list that is being looped through equals a certain value. If that is true, then an entry is created on the page. I need to dynamically print the element number (eg. entry 1 would display as 1. and entry 2 would display as 2.)
The two best attempts I have made are:
1.
<!-- this approach prints out 1 for each entry -->
{% with counter=0 %}
{% for q in questionnaire.questions %}
{% if q.answer %}
<div class="row"><h3>
{{ counter|add:1 }}. {{ q.name }}
</h3></div>
<!-- some other code-->
{% endif %}
{% endfor %}
{% endwith %}
{% for q in questionnaire.questions %}
{% if q.answer %}
<div class="row"><h3>
<span id="displayCount">0</span>. {{ q.name }}
</h3></div>
<!-- some other code-->
{% endif %}
{% endfor %}
<script type="text/javascript">
var count = 0;
var display = document.getElementById("displayCount");
count++;
display.innerHTML = count;
</script>
Any help would be appreciated
You can access the built-in counter of your for loop using forloop.counter. It starts at 1, you can also you forloop.counter0 if you'd like to start at zero.
{% for q in questionnaire.questions %}
{% if q.answer %}
<div class="row">
<h3>
{{ forloop.counter }}. {{ q.name }}
</h3>
</div>
<!-- some other code-->
{% endif %}
{% endfor %}
Filter your queryset in your view as to avoid issues with indexing and separating presentation from logic.

Django-bootstrap-datepicker-plus is not rendering datepicker properly

I am facing with the problem that my datetimepicker is not loading at all.
Just in my template, the datetime field loads the current date and time when i press the calendar icon as the image shows.
Despite following the installation steps from here : https://pypi.org/project/django-bootstrap-datepicker-plus/ and checking other answers in stackoverflow i did not manage to find the solution.
I think the problem has to do with the imports and their priority.
my template
{% extends 'base.html' %}
{% load render_table from django_tables2 %}
{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{% block page-title %}Creation of Process Note{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-6 col-xl-6 offset-md-3">
<form class="well" method="post" action="">
{% csrf_token %}
{% bootstrap_form form %}
<br>
{% buttons %}
<button type="submit" class="btn btn-primary">
Submit
</button>
{% endbuttons %}
</form>
{{ form.media }}
</div>
</div>
{% endblock %}
in settings.py
BOOTSTRAP4 = {
'include_jquery': True,
}
In my base.html the appearence of the imports is:
Inside head
<link href="/static/theme/assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">
<script src="/static/theme/assets/js/jquery.min.js"></script>
...
Inside footer
<script src="/static/theme/assets/js/bootstrap.bundle.min.js"></script>
...
my model
class Case_Notes(models.Model):
date_created = models.DateTimeField("Creation Date", null=True,blank=True, default=datetime.datetime.now)
date = models.DateTimeField("Appointment Date", null=True,blank=True)
notes = models.CharField("Notes",max_length=500, blank=True, null=True)
def __str__(self):
return self.notes
my form
class ProcessNotesForm(ModelForm):
notes= CharField(required=False,widget=Textarea(attrs={"rows":5, "cols":20}))
class Meta:
model = Case_Notes
fields = ("date","notes",)
widgets = {
'date': DateTimePickerInput(), # default date-format %m/%d/%Y will be used
}
Why datepicker widget in the form field is not rendering?
According to the documentation, the {{ form.media }} needs to follow right under the {% bootstrap_javascript jquery='full' %} in your template file.
{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{{ form.media }}
Addition to {{ form.media }} you use tuple instead of an array in the fields Meta in the ModelForm:
class ProcessNotesForm(ModelForm):
notes= CharField(required=False,widget=Textarea(attrs={"rows":5, "cols":20}))
class Meta:
model = Case_Notes
fields = ["date", "notes" ] # change this ("date","notes",)
widgets = {
'date': DateTimePickerInput(), # default date-format %m/%d/%Y will be used
}

How do I populate dynamically a StringField with the value of a SelectField in Wtforms

in a wtforms, I would like my SelectField to fill up with its selected value a StringField.
I use flask, bootstrap, and python 3.7
My HTML code is as follow:
{% block body %}
<h3>Edit Bloomberg ticker details</h3>
{% from "includes/forms/_form_helpers.html" import render_field %}
<div class="form-group" id="company_id" onchange="myFunction(event)">
{{render_field(form.company_names, class_="form-control")}}
</div>
<div class="form-group" id="isin_id">
{{render_field(form.isin_id, class_="form-control")}}
</div>
<script>
function myFunction(e) {
document.getElementById("isin_id").value = e.target.value
}
</script>
{% endblock %}
And the pyhon behind is as follow:
class DefTickerForm(_Form):
choices_companies = [(1,'Facebook'), (2, 'Google') ]
company_names = _SelectField(label='Company names:', choices=choices_companies, coerce=int)
isin_id = _StringField(label='isin_id', validators=[_validators.DataRequired], default=-1)
I would like that when the user select 'Facebook', the isin SelectField to be equal to 1. But so far it does nothing.
Note that if if code:
alert(e.target.value)
I get the wanted value. so issue is to set the TextField value.
my render field code is as followed (from a youtube tutorial):
{% macro render_field(field) %}
{{ field.label }}
{{ field(**kwargs)|safe }}
{% if field.errors %}
{% for error in field.errors %}
<span class="help-inline"> {{ error }}</span>
{% endfor %}
{% endif %}
{% endmacro %}
Any help would be much apreciated as google isn't so good on these.
Best
apparently TextField only accepts strings (I guess obvious if you are used to javascript)
so code working is as follow in case someone get he same problem:
<div class="form-group" onchange="myFunction(event)">
{{render_field(form.company_names, class_="form-control")}}
</div>
<div class="form-group">
{{render_field(form.isin_id, class_="form-control")}}
</div>
<script>
function myFunction(e) {
var x = e.target.value;
alert(x);
document.getElementById("isin_id").value = x.toString();
}
</script>
As a note, Jinja or anyway my render, use the fields names as default IDs (wich i realised using Chrome inpector. Meaning I didn't have to add an id for each Div. Anyway that is the thoughts of a beginenr in Javascripts.

Django: Jquery click function not working in Ajax

I have been working through the Tango with Django exercises to cut my teeth into Django. Almost done but having a problem with the Ajax part.
Ajax function to auto_add a page is not being called. Idk what the problem is since the other functions are being called.
On the shell prompt, there is no call to the ajax function at all. Help needed.
Pertinent code attached. It is the same as on the website link above.
static/rango-ajax.js
$('.rango-add').click(function(){
var catid = $(this).attr("data-catid");
var title = $(this).atrr("data-title");
var url = $(this).attr("data-url");
$.get('/rango/auto_add_page/', {category_id: catid, url: url, title: title}, function(data){
$('#pages').html(data);
me.hide();
});
});
templates/rango/category.html
{% if user.is_authenticated %}
<button data-catid="{{category.id}}" data-title="{{ result.title }}" data-url="{{ result.link }}" class="rango-add btn btn-mini btn-info" type="button">Add</button>
{% endif %}
rango/views.py
#login_required
def auto_add_page(request):
context = RequestContext(request)
cat_id = None
url = None
title = None
context_dict = {}
if request.method == 'GET':
cat_id = request.GET['category_id']
url = request.GET['url']
title = request.GET['title']
if cat_id:
category = Category.objects.get(id=int(cat_id))
p = Page.objects.get_or_create(category=category, title=title, url=url)
pages = Page.objects.filter(category=category).order_by('-views')
#Adds our results list to the template context under name pages.
context_dict['pages'] = pages
return render_to_response('rango/page_list.html', context_dict, context)
rango/urls.py
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^goto/$', views.track_url, name='track_url'),
url(r'^add_category/$', views.add_category, name='add_category'),
url(r'^auto_add_page/$', views.auto_add_page, name='auto_add_page'),
Complete code is at this link.
your code is good, the only thing what you have to do is to define your template in /tango/templates/rango/page_list.html. This template have the following code:
{% if pages %}
<ul>
{% for page in pages %}
<li>
{{ page.title}}
{% if page.views > 1 %}
({{page.views}} views)
{% elif page.views == 1 %}
({{page.views}} view)
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<strong> No Pages currently in category. </strong>
{% endif %}
And inside of your category template you must define the following code:
% if category %}
{% if user.is_authenticated %}
Add a new Page <br>
{% endif %}
{% if pages %}
<div id="pages">
<ul>
{% for page in pages %}
<li>
{{ page.title}}
{% if page.views > 1 %}
({{page.views}} views)
{% elif page.views == 1 %}
({{page.views}} view)
{% endif %}
</li>
{% endfor %}
</ul>
</div>
{% else %}
<strong> No Pages currently in category. </strong>
{% endif %}
{% else %}
The specified category {{ category_name }} does not exist!
{% endif %}
I'm working through this section of the tutorial now and just want to add to Héctor's answer. To avoid duplicating the code to display the list of pages I did the following:
I added a get_page_list() method to tango/rango/templatetags/rango_extras.py, similar to the get_category_list() method used to display a list of categories in an earlier section of the tutorial.
from rango.models import Page
#register.inclusion_tag("rango/page_list.html")
def get_page_list(category):
pages = Page.objects.filter(category=category) if category else []
return {'pages': pages}
Then we just need to load rango_extras and call the get_page_list() method in tango/templates/rango/category.html.
{% extends 'rango/base.html' %}
{% load rango_extras %}
<!-- Existing code -->
{% if category %}
<!-- Existing code to show category likes and like button -->
<div id="page_list">
{% get_page_list category %}
</div>
<!-- Existing code to show search if user is authenticated -->
{% else %]
The specified category {{ category_name }} does not exist!
{% endif %}
This allows you to display the list of pages when a category page is first loaded and then refresh it if a category is added from the search area, without having to duplicate any code.

Categories

Resources