Javascript adds another div instead of overwriting - javascript

I am trying to change the chart content with the following script:
function switchType() {
var e = document.getElementById("typeSelect");
var selected_value = e.options[e.selectedIndex].value;
console.log(selected_value)
anychart.onDocumentReady(function () {
var ents = {{ entities_dict|safe }}
var dropdown = document.getElementById("typeSelect");
var val = dropdown.value;
/*
var data = [
{value: 'GeopoliticalEntity',
children: [
{% for i in entities_dict.get('GeopoliticalEntity') %}
{value: "{{ i }}"},
{% endfor %}
]}
];
*/
var data = [
];
data.push({value: val,
children: [
{value: "country"},
{value: "europe"},
{value: "German"},
]})
//let result = data.map(a => a.children);
// create a chart and set the data
var chart = anychart.wordtree(data, "as-tree");
// set the chart title
chart.title("Word Tree: Data (Tree)");
// set the container id
chart.container("word_tree");
// initiate drawing the chart
chart.draw();
});
}
This is my HTML
<div class="container">
<div class="jumbotron">
{% for k in survey %}
<h2 class="display-4">Keyword Analysis</h2>
<h2 class="display-5">Most frequent keywords</h2>
<div id="word_cloud" style="width: 1000px; height: 500px; margin-bottom:5px;"></div><br>
<h2 class="display-5">Keyword frequency and their relevance score</h2>
<div id="bubble_chart" style="width: 1000px; height: 500px;"></div><br>
<h2 class="display-5">Entities found in responses</h2>
<select id="typeSelect" onchange="switchType()">
{% for key in entities_dict.keys() %}
{% if loop.first %}
<option selected="selected" value="{{ key }}">{{ key }}</option>
{% else %}
<option selected="selected" value="{{ key }}">{{ key }}</option>
{% endif %}
{% endfor %}
</select>
<div id="word_tree" style="width: 1000px; height: 500px;"></div>
{% endfor %}
</div>
</div>
The result is that it creates the chart, then creates another one below, and another one on each select change.
Is there any way to overwrite the requested div instead of appending another one to the HTML page?

This piece of code I found on this thread solved it for me: How to overwrite html element from javascript?
if (element) {
// Get its parent
parent = element.parentNode;
// Create the new element
newElement = document.createElement('div');
// Set its ID and content
newElement.id = "word_tree";
// Insert the new one in front of the old one (this temporarily
// creates an invalid DOM tree [two elements with the same ID],
// but that's harmless because we're about to fix that).
parent.insertBefore(newElement, element);
// Remove the original
parent.removeChild(element);
}

Related

Shopify Liquid how to change the source of an image regarding to a specific variant

I have created custom product cards, that I am displaying for example on the collection page in shopify. In the product cards I have created a "toggle like" select form where the user can switch the displayed variant. So when the user changes with the select form the variant I want to retrieve the source of the image of the selected variant so I can display it.
const collectionProductTogglePairs = document.querySelectorAll('.Pair');
collectionProductTogglePairs.forEach(collectionProductTogglePair => {
collectionProductTogglePair.addEventListener('click', function () {
collectionProductTogglePair.nextElementSibling.style.right = "0";
collectionProductTogglePair.nextElementSibling.style.left = "auto";
});
});
const collectionProductToggleSingles = document.querySelectorAll('.Single');
collectionProductToggleSingles.forEach(collectionProductToggleSingle => {
collectionProductToggleSingle.addEventListener('click', function () {
collectionProductToggleSingle.nextElementSibling.nextElementSibling.style.right = "auto";
collectionProductToggleSingle.nextElementSibling.nextElementSibling.style.left = "0";
});
});
.custom-card-product-product-image {
background-image: url({{ card_product.featured_media | product_img_url: '700x'}});
}
.custom-card-product-folder-2:before {
background-image: url({{ card_product.featured_media | product_img_url: '700x'}});
}
<div class="custom-card-product-folder">
<div class="custom-card-product-folder-2"></div>
<h6 class="custom-card-product-product-title" >{{ card_product.title | escape }}</h6>
<div class="custom-card-product-product-price {% unless card_product.compare_at_price == blank %}red{% else %}black{% endunless %}"><span class="grey line-through {% unless card_product.compare_at_price == blank %}margin-right-ten{% endunless %}">{{ card_product.compare_at_price | money}}</span> {{ card_product.price | money}}</div>
<div class="custom-card-product-toggle-wrapper">
{% for option in card_product.options_with_values %}
{% if option.name == "Anzahl" %}
{% for value in option.values %}
<div class="custom-card-product-toggle-value {{ value }}" test="{{ value.image.src }}">{{ value | escape }}</div>
{% endfor %}
<div class="custom-card-product-toggle-active-value-overlay"></div>
{% endif %}
{% endfor %}
</div>
</div>
If you are able to access the product variant based on the option(s) selected, then you can access the variant.featured_image property, which you can pipe to the image_url filter to get the image url at the appropriate size.
Further info on getting the product variant based on the option can be found here

How can I replicate **bold** in my django template?

I am trying to replicate how stack overflow allows the user to type text and produces it below at the same time. The code below in the Django Template works for this.
{% block head %}
<script>
function LiveTextUpdate() {
var x = document.getElementById("myInput").value;
document.getElementById("test").innerHTML = x;
}
</script>
{% endblock %}
{% block body %}
<div class = typing_container>
<div class = note_text>
{{ note_form.note }}
</div>
</div>
<div class = output_container>
<div class = output_note_text>
<p id="test" ></p>
</div>
</div>
The following is in the forms.py file:
class NoteForm(ModelForm):
class Meta:
model = NoteModel
fields = [
'note'
]
widgets = {
'note' : Textarea(attrs={'placeholder' : 'Start a new note', 'class' : 'updated_task_commentary', 'id' : 'myInput', 'oninput' : 'LiveTextUpdate()' }),
}
How can I replicate the ability to bold text when the text is surrounded by "**" please?

infinite scroll working but not populating all data because of javascript call

In my web site I want to show the user ratings - for that I used the infinite scroll but I am facing one problem.
When it first loads the data before calling the <a class="infinite-more-link" href="?page={{ ratings.next_page_number }}"></a> it is showing the star with the count of vote,but when after calling the <a class="infinite-more-link" href="?page={{ ratings.next_page_number }}"></a> it is not showing the star.
my views.py
#login_required
def ratings_user(request,pk):
ratings = VoteUser.objects.filter(the_user_id=pk).order_by('-pk')
paginator = Paginator(ratings, 1)
page = request.GET.get('page')
try:
posts = paginator.page(page)
except PageNotAnInteger:
posts = paginator.page(1)
except EmptyPage:
posts = paginator.page(paginator.num_pages)
return render(request,request.session['is_mobile']+'profile/ratings.html',{'ratings':posts})
html
{% extends 'mobile/profile/base.html' %}
{% block title %}
Ratings
{% endblock %}
{% block leftcontent %}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css" rel="stylesheet">
{% endblock %}
{% block middlecontent %}
<div class="infinite-container">
{% for i in ratings %}
<div class="infinite-item">
<div class="w3-container w3-card w3-white w3-round w3-margin">
<img src="{{ i.the_user.profile.avatar.url }}" alt="Avatar" class="w3-left w3-circle w3-margin-right" style="width:40px;height:40px;border-radius:50%;">
{% with user=i.the_user.profile %}{{ user.prenom|title|truncatewords:2 }} {{ user.nom|title|truncatewords:1 }}{% endwith %}
<br>
<span class="stars" data-rating="{{ i.vote.vote }}" data-num-stars="5" ></span>
<hr class="w3-clear">
<p>
{{ i.commentaire|linebreaksbr }}
</p>
<span class="glyphicon glyphicon-user"></span> {% with user=i.the_sender.profile %}{{ user.prenom|title|truncatewords:2 }} {{ user.nom|title|truncatewords:1 }}{% endwith %}
</div>
</div>
{% endfor %}
</div>
{% if ratings.has_next %}
<a class="infinite-more-link" href="?page={{ ratings.next_page_number }}"></a>
{% endif %}
{% endblock %}
{% block rightcontent %}
{% endblock %}
{% block js %}
<script>
var infinite = new Waypoint.Infinite({
element: $('.infinite-container')[0]
});
</script>
<script>
//ES5
$.fn.stars = function() {
return $(this).each(function() {
var rating = $(this).data("rating");
var fullStar = new Array(Math.floor(rating + 1)).join('<i class="fas fa-star"></i>');
var halfStar = ((rating%1) !== 0) ? '<i class="fas fa-star-half-alt"></i>': '';
var noStar = new Array(Math.floor($(this).data("numStars") + 1 - rating)).join('<i class="far fa-star"></i>');
$(this).html(fullStar + halfStar + noStar);
});
}
//ES6
$.fn.stars = function() {
return $(this).each(function() {
const rating = $(this).data("rating");
const numStars = $(this).data("numStars");
const fullStar = '<i class="fas fa-star"></i>'.repeat(Math.floor(rating));
const halfStar = (rating%1!== 0) ? '<i class="fas fa-star-half-alt"></i>': '';
const noStar = '<i class="far fa-star"></i>'.repeat(Math.floor(numStars-rating));
$(this).html(`${fullStar}${halfStar}${noStar}`);
});
}
</script>
<script>
$(function(){
$('.stars').stars();
});
</script>
{% endblock %}
I have tried to put the <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css" rel="stylesheet"> inside the class="infinite-item" but it does not help.what might be the reason for that ? Thanks.
Since yesterday I am on this question I tried everything.
This is another user that has tried to help me here https://stackoverflow.com/a/69930878/15042684 but I did not really understand could you please help me to understand it with some code.
this is his answer:
It doesn't look like .stars() will look for new elements being added to the DOM. You should look for a callback function configuration option within Waypoint.Infinite that you can call .stars() on the new elements.
Assuming you are using waypoint's Infinite Scroll, you can use the onAfterPageLoad callback
onAfterPageLoad
Default: $.noop.
Parameters: $items.
This is a callback that will fire at the end of the request cycle, after new items have been appended to the container. It is passed one parameter, which is a jQuery object of all the items that were appended during the page load.
Note that despite using the jquery convention of $name indicates a jquery object and stating is a jquery object, in this case, trial and error shows that $items are the DOM elements, not a jquery object.
No example provided in the docs, so it will probably look something like:
<script>
var infinite = new Waypoint.Infinite({
element: $('.infinite-container')[0],
onAfterPageLoad: function(items) {
$(items).find(".stars").stars();
}
});
</script>

Create charts with a loop in Django with charts.js

I created a project in Django. I need charts in my project.
I use chart.js library and Json.
I use an API for take values. In the API page there are 5 objects.Every object has title, value1 and value2.
When I create a table it works. I can get values but I cannot display values in charts. How can I create several charts with a loop?
views.py
def Jdeneme(request):
response = requests.get('https://api....t')
data = response.json()
return render(request, 'charts.html', {'data': data})
charts.html
{% extends "layouts/base.html" %}
{% load static %}
{% block content %}
<div class="content">
<div class="page-inner">
<h4 class="page-title">Chart.js</h4>
<div class="page-category"></div>
{% for dt in data %}
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<div class="card-title">{{ dt.title }} Doughnut Chart</div>
</div>
<div class="card-body">
<div class="chart-container">
<canvas id="doughnutChart" style="width: 50%; height: 50%"></canvas>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock content %}
{% block javascripts %}
<script>
doughnutChart = document.getElementById('doughnutChart').getContext('2d');
var myDoughnutChart = new Chart(doughnutChart, {
type: 'doughnut',
data: {
datasets: [
{
data: [ {{ dt.value1 }}, {{ dt.value2 }} ],
backgroundColor: ['#e95bda','#4bbffd']
}
],
labels: [
'value 1',
'value 2'
]
},
options: {
responsive: true,
maintainAspectRatio: false,
legend : {
position: 'bottom'
},
layout: {
padding: {
left: 20,
right: 20,
top: 20,
bottom: 20
}
}
}
});
// Chart with HTML Legends
var gradientStroke = htmlLegendsChart.createLinearGradient(500, 0, 100, 0);
gradientStroke.addColorStop(0, '#177dff');
gradientStroke.addColorStop(...
var myHtmlLegendsChart = new Chart(htmlLegendsChart, {
...
var myLegendContainer = document.getElementById("myChartLegend");
// generate HTML legend
myLegendContainer.innerHTML = myHtmlLegendsChart.generateLegend();
...
}
</script>
{% endblock javascripts %}
You are referencing the (template) for-loop variable dt outside of the for loop.
You are also giving all the created canvases the same fixed id.
You are only building one Chart in your javascript code.
Try changing your code like this:
{% extends "layouts/base.html" %}
{% load static %}
{% block content %}
<div class="content">
<div class="page-inner">
<h4 class="page-title">Chart.js</h4>
<div class="page-category"></div>
{% for dt in data %}
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<div class="card-title">{{ dt.title }} Doughnut Chart</div>
</div>
<div class="card-body">
<div class="chart-container">
<canvas id="doughnutChart{{ forloop.counter }}" style="width: 50%; height: 50%"></canvas> {# CHANGE THIS #}
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock content %}
{% block javascripts %}
<script>
{% for dt in data %} {# ADD THIS #}
doughnutChart = document.getElementById('doughnutChart{{ forloop.counter }}').getContext('2d'); {# CHANGE THIS #}
var myDoughnutChart{{ forloop.counter }} = new Chart(doughnutChart, { {# CHANGE THIS #}
type: 'doughnut',
data: {
datasets: [
{
data: [ {{ dt.value1 }}, {{ dt.value2 }} ],
backgroundColor: ['#e95bda','#4bbffd']
}
],
labels: [
'value 1',
'value 2'
]
},
options: {
responsive: true,
maintainAspectRatio: false,
legend : {
position: 'bottom'
},
layout: {
padding: {
left: 20,
right: 20,
top: 20,
bottom: 20
}
}
}
});
{% endfor %} {# ADD THIS #}
// Chart with HTML Legends
var gradientStroke = htmlLegendsChart.createLinearGradient(500, 0, 100, 0);
gradientStroke.addColorStop(0, '#177dff');
gradientStroke.addColorStop(...
var myHtmlLegendsChart = new Chart(htmlLegendsChart, {
...
var myLegendContainer = document.getElementById("myChartLegend");
// generate HTML legend
myLegendContainer.innerHTML = myHtmlLegendsChart.generateLegend();
...
}
</script>
{% endblock javascripts %}
By the way, this is just to make your code work the way you are writing it, but it is debatable whether it's a good idea to dynamically generate Javascript code via Django templates.

Modal opening empty because of display null

(I know, bad title, pardon me)
So here's the thing:
I have a navbar with 3 icons and each one opens the same modal, but with different resources inside.
They are only clickable if resources exist for them, otherwise they are grayed out. Therefore 0, 1, 2 or all 3 of them can be visible or grayed out.
It works fine when all 3 are clickable, but if 1 or 2 are grayed out, the other opens an empty modal and the console shows assistance.js:29 Uncaught TypeError: Cannot read property 'style' of null.
This is how the twig looks and how the modal is populated and the modal itself:
<div class="assistance-body">
<nav>
<ul class="nav nav-tabs nav-justified nav-no-padding-top">
{% set allResources = ['videos', 'glossary', 'links'] %}
{% for key in allResources %}
{% if key in resources|keys %}
<li{% if loop.first %} ng-class="active" {% verbatim %}{{class}}{% endverbatim %} {% endif %} class="icon-resource">
<a
data-toggle=""
href="#assistance-{{ key }}"
segment-event="Modules: Tutor: Clicked {{ key|capitalize }} Section"
segment-not-track-if-class="active"
onclick="toggleAssistance('assistance-{{ key }}', ['assistance-videos', 'assistance-glossary', 'assistance-links'] )"
>
<i class="icon-{{ key }} icon-sm"></i>
<span class="sr-only">{{ ('resources.tabs.' ~ key ~ '.title') | trans }}</span>
</a>
</li>
{% else %}
<li{% if loop.first %} {% verbatim %}{{class}}{% endverbatim %} {% endif %} class="icon-resource">
<i class="icon-{{ key }} icon-sm icon-sm-gray"></i>
<span class="sr-only">{{ ('resources.tabs.' ~ key ~ '.title') | trans }}</span>
</li>
{% endif %}
{% endfor %}
</ul>
</nav>
<div id="assistance" class="assistance">
<div>
{% for key, data in resources %}
<div id="assistance-{{ key }}">
<button
type="button"
class="close"
onclick="toggleAssistance('assistance-{{ key }}', ['assistance-videos', 'assistance-glossary', 'assistance-links'] )"
aria-hidden="true">
×
</button>
{% include data.view with { 'category': data.category, 'resources': data.resources } %}
</div>
{% endfor %}
</div>
</div>
</div>
And this is the assistance.js:
function toggleAssistance (target, all) {
var targetAssistanceResource = document.getElementById(target);
var allAssistanceResources = [];
all.forEach(function (el) {
allAssistanceResources.push(document.getElementById(el));
});
// the resource is already opened, let's close it
if (getStyle(targetAssistanceResource, 'display') !== 'none') {
// hiding the main assistance div
document.getElementById('assistance').style.display = 'none';
// hiding all assistance resources
allAssistanceResources.forEach(function (res) {
res.style.display = 'none';
});
} else { // it's not opened, let's open it
// showing the main assistance div
document.getElementById('assistance').style.display = 'block';
// hiding all assistance resources
allAssistanceResources.forEach(function (res) {
res.style.display = 'none';
});
// showing the target assistance resource
targetAssistanceResource.style.display = 'block';
}
}
function getStyle (el, cssprop) {
if (el.currentStyle) { // IE
return el.currentStyle[cssprop];
} else if (window.getComputedStyle) {
return window.getComputedStyle(el)[cssprop];
}
// finally try and get inline style
return el.style[cssprop];
}

Categories