Create charts with a loop in Django with charts.js - javascript

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.

Related

How can i array to grid table in Django HTML?

I can send my model to the html page and bring it to the array structure, but I cannot integrate this array into the grid table. Does anyone know how I can do this?
views.py
def tests(request):
resultQueryet = ResultsModel.objects.all()
requests = serialize('json', resultQueryet)
context = {
"requests" : requests
}
return render(request, 'admin/tests.html', context=context)
html
{% block content %}
<div class="card-body">
<div id="table-card" class="table-card"></div>
</div>
{% endblock %}
{% block extra_js %}
<script>
var model = {{requests|safe}};
console.log(model)
document.getElementById("table-card") &&
new gridjs.Grid({
columns: ["Name", "Surname", "Date", "Amount", "Result", "Details"],
sort: !0,
pagination: { limit: 5 },
data: [
[
{% for x in model %}
{{x.name}},
{{x.surname}},
{{x.date}},
{{x.amount}},
{{x.result}},
{{x.details}},
{% endfor %}
],
],
}).render(document.getElementById("table-card"))
</script>
<script src="{% static 'libs/prismjs/prism.js'%}"></script>
<script src="{% static 'libs/gridjs/dist/gridjs.umd.js'%}"></script>
<script src="{% static 'js/pages/gridjs.init.js'%}"></script>
{% endblock extra_js %}
I can view the model as array on the console screen, but I cannot print it to the table via a for loop.

Problem showing the main slider on user click in a splidejs carousel

I just made a carousel using splide and I just made it in the way I want. There is only one detail left and it doesn't work. I don't want to show the main slider at the beginning and begin to show it only when the user click on any thumbnail. I implemented it this way:
#main-slider{
display:none;
}
and then
thumbnails.on('click', function(){
document.getElementById('main-slider').style.display = "block";
})
But the main slider only get partially visible. That is, only pagination and arrows will display. No way to show everything, especially the image.
Here's the entire code:
{% load static %}
{% comment %} If you want to fully customize the slider appearance, pick the splide-core.min.css file that does not include arrows, pagination and progress bar styles, which reduces unnecessary "override" works. {% endcomment %}
<link href="{% static 'js/splide-3.2.1/dist/css/splide.min.css' %}" rel="stylesheet">
<style>
.splide__slide {
/* opacity of the thumbnails */
opacity: .6;
}
.splide__slide.is-active {
/* opacity of the selected thumbnail */
opacity: 1;
}
#main-slider{
display:none;
}
</style>
<div class="splide">
<div id="main-slider" class="splide">
<div class="splide__track">
<ul class="splide__list">
{% for image in images %}
<li class="splide__slide">
<img src="{{ image.image.url }}" />
</li>
{% endfor %}
</ul>
</div>
</div>
<div id="thumbnail-slider" class="splide">
<div class="splide__track">
<ul class="splide__list">
{% for image in images %}
<li class="splide__slide">
{% comment %} data-splide-lazy must be enabled for lazy load {% endcomment %}
<img src="{{ image.image.url }}" data-splide-lazy="{{ image.image.url }}">
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
<script>
document.addEventListener( 'DOMContentLoaded', function () {
var main = new Splide( '#main-slider', {
type : 'slide',
heightRatio: 0.5,
speed :500,
pagination : true,
arrows : true,
cover : true,
} );
var thumbnails = new Splide( '#thumbnail-slider', {
fixedWidth : 100,
fixedHeight : 60,
gap : 10,
perMove : 1,
perPage : 1,
rewind : true,
pagination : false,
cover : true,
isNavigation: true,
lazyLoad : false,
keyboard : true,
wheel : true,
focus : 'center',
dragMinThreshold: {
mouse: 4,
touch: 10,
},
breakpoints : {
600: {
fixedWidth : 60,
fixedHeight: 44,
},
},
} );
main.sync( thumbnails );
main.mount();
thumbnails.mount();
thumbnails.on('click', function(){
document.getElementById('main-slider').style.display = "block";
})
} );
</script>
<script src="{% static 'js/splide-3.2.1/dist/js/splide.min.js' %}"></script>

Django AJAX Infinite Scroll Error on page reload

I'm trying to implement infinite scroll with django and jquery(Waypoint).
I have a ListView with a pagination of 5, but when waypoint loads second page, AJAX requests are no longer performed so I added the AJAX function on the onAfterPageLoad which helps bring back AJAX function to the newly loaded page.
That's fine, but then it introduces a bug to my code making the page loaded initially (First Page) no longer perform AJAX functions very well. It makes AJAX on the first page run 3 times if I just loaded a third page and makes AJAX on the second page run twice and so on depending on the number of pages loaded already.
I don't know if there are any cool ways to achieve this because I tried using just jquery without waypoint, but still get same errors as I get when using just waypoint making it an error. This is kinda tricky so far.
{% extends "base.html" %}
{% block content %}
{% load static %}
<div class="container" style="max-width:700px">
<div class="px-3 pt-md-5 pb-md-4 mx-auto text-center">
<h1 class="display-4">All Groups</h1>
<p class="lead">List of groups</p>
</div>
<div class="">
<div class="row infinite-container">
{% for group in groups %}
<div class="col-md-12 infinite-item">
<!-- <img class="img-fluid" src="https://picsum.photos/700"> -->
<a class="text-dark" href="{{ group.get_absolute_url }}">
<div class="card mb-4 box-shadow">
<div class="card-body">
<h2 style="font-size:18px;font-weight:bold;min-height:42px;">
{{group.name|truncatechars:50}}</h2>
<div class="d-flex justify-content-between align-items-center">
<small class="text-muted">{{group.owner}}</small>
<small class="text-muted">{{group.date_created}}</small>
</div>
<p><a class='follow-btn' data-href='{{ group.get_group_follow_api_url }}'
data-likes='{{ page.likes.count }}'
href='{{ group.get_group_follow_url }}'>{{ group.follows.count }}
{% if request.user.profile in group.follows.all %}
Unfollow
{% else %}
Follow
{% endif %}
</a></p>
</div>
</div>
</a>
</div>
{% endfor %}
</div>
<!-- Comment for loading spinner -->
{% comment %}
<div class="d-flex d-none position-fixed" style="top:35vh;left:46vw">
<button class="btn btn-primary loading">
<span class="spinner-border spinner-border-sm"></span>
Loading...
</button>
</div>
{% endcomment %}
<!-- End of comment for loading spinner -->
<div class="row">
<div class="col-12">
{% if page_obj.has_next %}
<a class="infinite-more-link" href="?page={{ page_obj.next_page_number }}"></a>
{% endif %}
</span>
</div>
</div>
</div>
</div>
<script src="{% static "js/jquery.waypoints.min.js" %}"></script>
<script src="/static/js/infinite.min.js"></script>
<script>
var infinite = new Waypoint.Infinite({
element: $('.infinite-container')[0],
offset: 'bottom-in-view',
onBeforePageLoad: function () {
$('.loading').show();
},
onAfterPageLoad: function () {
$('.loading').hide();
$(document).ready(function(){
function updateText(btn, newCount, verb){
btn.text(newCount + " " + verb)
}
$(".follow-btn").click(function(e){
e.preventDefault()
var this_ = $(this)
var badge = this_.find('.unlike-update')
var followUrl = this_.attr("data-href")
var followCount = parseInt(this_.attr("data-follows")) | 0
var addFollow = followCount + 1
var removeFollow = followCount - 1
if (followUrl){
$.ajax({
url: followUrl,
method: "GET",
data: {},
success: function(data){
console.log(data)
var newFollows;
if (data.followed){
// updateText(this_, addLike, "Unlike")
// updateText(this_, data.likescount, badge)
updateText(this_, data.followscount, "Unfollow")
} else {
// updateText(this_, removeLike, "Like")
updateText(this_, data.followscount, "Follow")
// remove one like
}
}, error: function(error){
console.log(error)
console.log("error")
}
})
}
})
})
}})
</script>
{% include 'group/snippets/group_follow.html' %}
{% endblock %}
class GroupListView(LoginRequiredMixin, ListView):
model = Group
paginate_by = 5
context_object_name = 'groups'
template_name = 'group/group_list.html'
ordering = ['-date_created']

Loop JavaScript in Ajax

i'm following the Django code that dynamically generates cards according to my amount of variables i have in a bank. For each card it consumes data from an API through ajax code. However, my ajax code is not being called every loop. It is called only once. What I can do is wrong, because I need ajax to be called every loop of HTML.
{% block content %}
<div id="auto" class="row">
{% for row in list %}
{% if row.state == 1 %}
<div class="col-xs-6 col-md-4">
<div class="card">
<h5 class="card-header">{{row.description}} - Temperatura Atual (˚C)</h5>
<!--<img class="card-img-top" src="{% static 'img/gauge.png' %}" width="100" height="200" alt="Card image cap">!-->
<canvas id="myChart-{{ forloop.counter }}" class="piechart"></canvas>
<script>
var rowId = {{ row.id }}
console.log(rowId);
readTempDinamic(rowId);
//refresh();
</script>
<p class="text-center font-weight-bold" style="font-size: 0.7rem"><span id="datetime"></span></p>
Show
</div>
</div>
{% endif %}
{% endfor %}
</div>
{% endblock content %}
function readTempDinamic(rowId) {
var endpointTemp = '/api/weatherData/getSensor/1/' + rowId + '/'
console.log(endpointTemp);
/* ############################################################################# */
$.ajax({
method: "GET",
url: endpointTemp,
success: function(data){
var row = []
var value = []
var read_data = []
row = data.row
value = data.value
read_data = data.read_date
generateGaugeCharts(row[0], read_data[0], value[0])
},
error: function(error_data){
console.log("error")
console.log(error_data)
}
})
/* ############################################################################# */
}

Interacting with text in Django for loop

I am working on a Django project where I want to output a text file and apply certain operations like highlighting to the text. My idea was to implement it in such a way that each word can be clicked, for a popup window (or tooltip window) to appear, displaying all the options.
{% for Line in File.body %}
<div>
{% for Token in Line %}
{% if not Token.content == None %}
<span class="inline token" id="token">
<strong style="color: {{ Token.highlight }};">
{{ Token.content }}
</strong>
</span>
<div id="{{ Token.unique_id }}">
POPUP </br>
<button onclick="changeColor()">Highlight</button>
</div>
<script>
tippy('.token', {
content: document.getElementById("{{ Token.unique_id }}"),
delay: 100,
arrow: true,
arrowType: 'round',
size: 'large',
duration: 500,
animation: 'scale',
allowHTML: true,
hideOnClick: true,
trigger: "click"
})
function changeColor() {
var token = document.getElementById("token");
token.style.color="blue;";
}
</script>
{% endif %}
{% if Token.endline %}
</br>
{% endif %}
{% endfor %}
</div>
{% endfor %}
I tried using the tippjs tooltip library (https://atomiks.github.io/tippyjs/), but clicking the highlight button doesn't do anything. If i don't put the javascript part in the loop, nothing happens at all. The code with the javascript part not in the loop would look something like this:
<script>
tippy('.token', {
content: document.getElementById("{{ Token.unique_id }}"),
delay: 100,
arrow: true,
arrowType: 'round',
size: 'large',
duration: 500,
animation: 'scale',
allowHTML: true,
hideOnClick: true,
trigger: "click"
})
function changeColor() {
var token = document.getElementById("token");
token.style.color="blue;";
}
</script>
{% for Line in File.body %}
<div>
{% for Token in Line %}
{% if not Token.content == None %}
<span class="inline token" id="token">
<strong style="color: {{ Token.highlight }};">
{{ Token.content }}
</strong>
</span>
<div id="{{ Token.unique_id }}">
POPUP </br>
<button onclick="changeColor()">Highlight</button>
</div>
{% endif %}
{% if Token.endline %}
</br>
{% endif %}
{% endfor %}
</div>
{% endfor %}
I am new to django and even newer to javascript, so I'm not sure if this is even the right way to go about this.
Can somebody point me in the right direction here?

Categories