Jinja2/JavaScript nested for loop only displaying first div - javascript

I have a Flask web application where I am calling an IBM Watson API (JSON output) and displaying the results in a series of Bootstrap modals where each contain information on a separate news article (eg. Watson returns 40 news articles, the page will have buttons for 40 modals with the data accessed via a loop). Within each modal I am trying to display a keyword in text next to a small percentage bar (to display the sentiment of the keyword). I have a nested for loop to extract the correct information and using the loop index to make the div id's unique. The results display correctly in the first modal only, however do not display in any of the other modals. I've tried combinations of adding the inner and outer loop indexes to the div id but cannot get it to work! Here is a simplified version of the code within the modal and the corresponding JavaScript. Thank you!
results.html
{% for results in watson_results %}
{% set resultsloop = loop %}
{% for item in results.enriched_text.keywords[0:5] %}
<ul class="list-group list-group-flush">
<li class="list-group-item">
<div class="progress" style="display: inline-block; vertical-align: middle" id="progressdiv1-{{loop.index}}">
<div class="progress-done-pos" style="display: inline-block; vertical-align: middle" id="progress1-{{loop.index}}" data-done={{item.sentiment.score}}>
{{item.sentiment.score}} Positive
</div>
</div>
<span class="explanation" style="margin-left:5px; vertical-align:middle">{{item.text}}</span>
</li>
</ul>
{% endfor %}
{% endfor %}
JavaScript
<script type="text/javascript">
var progress = document.getElementById('progress1-{{loop.index}}');
progress.style.width = (progress.getAttribute('data-done')*100) + "%";
progress.style.opacity = 1;
</script>

Related

Gray the card on click in Bootstrap

A common function in infinite list is that, the item will be grayed after when we clicked on him. Can we get this effect with only HTML, CSS, JS, jQuery(on the user's side)?
How it works?
1.) the user clicks on the card element
2.) When pressed, class text-muted is added to the card element, causing it to be grayed out as below
The simplest example of code in bootarap looks like this:
{% for obj in objects %}
<a href="/detail/id/" target="_blank">
<div class="card" id="card{{ obj.id }}">
<!--..content card..-->
</div>
</a>
{% endfor %}
You just can add CSS pseudo-class to visited links a:visited { color: grey; }. Without custom class and javascript logic.
See doc

Change DOM element class based on text content of another element when generated by Jinja for loop

I need to alter the colour of an HTML element based on the text content of another element. However, the content is being generated with a Python for loop using a Jinja shortcut.
For example:
{% for article in articles %}
<div class="row article">
<div class="col s6">
<strong>{{ article.title }}</strong>
<p>Page count: {{ article.page_count }}</p>
<p>Layout code: <span id="layout">{{ article.layout }}</span></p>
</div>
<div id="show_layout" class="col s1 layout"></div>
</div>
{% endfor %}
I'm trying to use Javascript or jQuery to make the #show_layout element red if a layout code is present (ie. there is some text content in that span). The trouble is that I'm only able to make all or none show up red as the JS function runs once and affects every iteration of the for loop. For example, if 3 article listings are generated by the for loop (pulled from MongoDB) then each of the #show_layout elements turn red, if just one has any layout code content. I've tried experimenting with using the 'this' keyword, but I'm not getting anywhere.
Currently this is the basic function I'm altering, though there have been many different versions! I'm calling this on page load; calling it from the element itself doesn't seem to do anything!
function showLayout() {
let code = document.getElementById("layout").textContent;
let toChange = document.getElementById("show_layout");
if (code !== "") {
toChange.classList.add("layout-red");
console.log(code)
}
else {
console.log("arghghg")
}
}
I'm very new to Python and Jinja, so perhaps my approach is entirely wrong. Can anyone suggest a better way of doing this, or am I missing something obvious?
CBroe pointed me in the right direction here, by suggesting that I do this via Jinja, which had not occurred to me (I'm very, very new to Jinja!).
adding:
{% if article.layout != "" %}
<div id="show_layout" class="col s1 layout-red show_layout"></div>
{% endif %}
did the trick!
Thank you CBroe!

Changing background color of a bootstrap panel

I am trying to change the background color of a panel using javascript to emulate "selected" functionality.
So, on click I get hold of the div by ID and change its background color.
It works fine but only momentarily and again resets the background color, and I have no idea why?
DJANGO HTML Template
<div class="panel-group">
{% if articles %}
{% for article in articles %}
<div class="panel panel-success" id="aid_{{ article.articleId }}">
<div class="panel-body">
<b>{{ article.title }}</b><br/>
<span style="color:darkgrey; font-size:.9em; font-family:sans-serif; font-style:italic">{{ article.source }} - {{ article.date }}</span><br/>
{{ article.sentences }}
</div>
</div>
{% endfor %}
{% else %}
NO ARTICLES PRESENT
{% endif %}
</div>
Javascript
function populateArticle(aid) {
document.getElementById('aid_'+aid).style.backgroundColor="#DEF1DE";
}
Also here is a link to a gif I recorded that shows the behavior: http://g.recordit.co/fSoTieo5Qn.gif (copy-paste the link in a new tab in case if it gives error).
Any ideas why this is happening?
You are not preventing default <a> tag behavior, so Your page refreshes.
onclick="populateArticle({{ article.articleId }});return false;"
Should fix it.
No idea why that may be happening, I personally would try this:
<script>
$(document).ready(function () {
$(".panel-body a").on("click", function (e) {
e.preventDefault();
var id = "#aid_" + $(this).attr("data-articleID");
$(id).css("background-color", "#DEF1DE");
});
});
</script>
After your jQuery script and lose the onClick in your HTML (Bad practice) instead pass the id reference by adding a data-articleID attribute. Like this:
<b>article title</b>
If your issue still persists you'd have to check for any other JavaScript changing the background back to original colors.

How to repeat elements pulled from an array inside a javascript object literal with ng-repeat

I'm repeating elements from a big javascript object literal. Currently, I display the tabbed navigation, image, and title for each product correctly. I cannot get the info to display correctly however. I have the following code:
<div ng-repeat="section in tab.sections" class="product">
<div ng-repeat="child in section.children" ng-if="productIsActive(child, $index)">
<div class="additionalProductInfo">
<nav class="secondaryTabbedNavigation">
<ul>
<li class="active" ng-repeat="pTabs in child.productTabs">
<a class="activelink" href="#">{{pTabs.title}}</a> //title of each tab
</li>
</ul>
</nav>
</div>
<div class="productImage">
<img ng-src="{{ child.productImageURL }}"/> //the product image
</div>
<div class="productInfo">
<h2 class="productTitle">{{ child.title}}</h2> //the product title
<div ng-repeat="info in pTabs.infoData" class="productDescription">
<p>
{{info[1]}} //product info goes here.
</p>
</div>
</div>
</div>
</div>
I also tried "{{info}}" , "{{info[i][i]}}", and a couple things using $index. But when "{{info}}" didn't display anything, I figured I was retrieving the data incorrectly.
Here is the "tabs" javascript object that all this info comes from:
As you can see the product info is in a two dimensional array (the first array with the labels of what the information is (e.g. "Title", "Link") and the corresponding information is in the second array. I know this may not be ideal, but this information is currently grabbed from .csv files that prone to changing
and I cannot change how they come into this javascript object.
I know this may seem overcomplicated but this is about as deep as I need to go to get data from the large javascript object and I'm very close.
How can I get the contents from the second array in the two dimensional array (infoData[1]) to display like I did with the tabs, image, and title.
Thank you very much for your time!

Infinite scroll for static page with jQuery

I have coded a paginated comment section,
even if you never used symfony2 its very simple to understand
It just loops through 100 comments and then uses a "next" button for the next comment page to show.
{% for comment in pagination %}
<div class="comment-container">
<div class="bubble">
<div class="cmt-avatar"></div>
{{ comment.text }}
</div>
</div>
{% endfor %}
this method is working perfectly so far.
But it makes the design look terrible, specially with a giant scroll bar on the right side of the page.
What I'd need is a way to make it 'look' like the comment-container is being loaded while the user scrolls.It's obviously just a static page, it just needs to look like its infinite scroll.
What I've tried so far:
I found this on this page, it didn't work though, no errors, but does nothing.
{% for comment in pagination %}
<div class="scrollable-data'">
<div class="comment-container">
<div class="bubble">
<div class="cmt-avatar"></div>
{{ comment.text }}
</div>
</div>
</div>
{% endfor %}
... script
var $doc=$(document);
var $win=$(window);
// hide everything that is out of bound
$('.scrollable-data').filter(function(index){
return ($(this).scrollTop() > $doc.height());
}).hide();
var DATA_INCREMENT=5;
$(window).scroll(function(){
// test if at the bottom
if ($doc.height()-$win.height()-$(this).scrollTop() == 0) {
// show the <DATA_INCREMENT> (5) next hidden data tags
$('.scrollable-data:hidden:lt('+DATA_INCREMENT+')').show();
}
});
Your routine is script intricated.
This is how I would implement this:
A routine that shows only elmenets contained "within the current scrollbar" (sorry, no better words for it):
function rescroll(){
//show all
$('.scrollable-data').show();
// hide everything that is out of bound
$('.scrollable-data').filter(function(index){
console.log($(this).position().top, $(window).height()+$(window).scrollTop());
return ($(this).position().top > $(window).height()+$(window).scrollTop());
}).hide();
}
Then call this routine every time the user perform a scroll:
$(window).scroll(function(){
rescroll();
});
Then call also rescroll() at the page loading.
Working example: http://jsfiddle.net/5WtTU/
Some considerations:
Usually infinite scroll works so that, when the user scrolls 'till a certain comment, then, if he/she scrolls back these comments are not hidden again!
So you should save somewhere the maximum of the scroll of a user, and always hide untill this point. In this way you wont re-hide things if the user scrolls up.

Categories

Resources