I'm trying to send data between a django view to a seperate file containing my chartJS chart.
const lineChart = document.getElementById('lineChart');
const interactionsListInput = document.getElementById('interactions_list');
const interactionsList = JSON.parse(interactionsListInput.value);
const labels = interactionsList.map(item => item[0]);
const data = interactionsList.map(item => item[1]);
console.log(interactionsList)
new Chart(lineChart, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Interactions',
data: data,
backgroundColor: '#ff0084',
color: '#ff0084',
borderColor: '#ff0084',
borderWidth: 1
}]
},
options: {
plugins: {
legend: {
display: false
}
},
scales: {
y: {
beginAtZero: true
}
}
}
});
I was expecting the chart to render with the data being supplied by interactions_list
Im passing my data into my html page using:
<input type="hidden" id="interactions_list" value="{{ interactions_list|safe }}">
and the data of the interactions_list is in this format:
[['02/06/2023', 'None'], ['02/07/2023', 'None'], ['02/08/2023', 'None'], ['02/09/2023', 'None'], ['02/10/2023', 'None'], ['02/11/2023', 'None'], ['02/12/2023', '19026']]
but i get the following error:
Uncaught SyntaxError: Unexpected token ''', "[['02/06/202"... is not valid JSON
I'm not sure why this error is appearing.
I've tried
<input type="hidden" id="interactions_list" value="{{ interactions_list|escapejs }}">
To see if its some kinda of formation issue between Django and JS, but i no joy.
Any help would be great.
Thanks
interactions_list is not valid json format as the error says. This seems to be an array of tuples or a nested array.
[['02/06/2023', 'None'], ['02/07/2023', 'None'], ['02/08/2023', 'None'], ['02/09/2023', 'None'], ['02/10/2023', 'None'], ['02/11/2023', 'None'], ['02/12/2023', '19026']]
json format is like the below
so your example data should be sort of like this
{
"interaction_list":[
{
"date":"02/06/2023",
"value":"None"
},
{
"date":"02/08/2023",
"value":"None"
}
]
}
Related
I am trying to get Jinja braces to stay in line for a javascript variable used in an apexchart.js call for a flask HTML page.
labels = JSON.parse({{ labels | tojson}})
data = JSON.parse({{ data | tojson}})
The problem I am having is that when I save the html the braces get formatted apart.
labels = JSON.parse({
{
labels | tojson
}
})
data = JSON.parse({
{
data | tojson
}
})
Is there away to stop Visual Studio Code from splitting the Jinja code apart?
Current Code Below:
<!-- language: lang-html -->
<!-- templates/index.html -->
{% extends 'base.html' %} {% block content %}
<title>Dashboard | {{title}}</title>
<div class="flex h-screen justify-center">
<div id="chart" class="h-1/4 w-1/2 content-center"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<script>
labels = JSON.parse({
{
labels | tojson
}
})
data = JSON.parse({
{
data | tojson
}
})
var options = {
colors: ['#01ca95'],
chart: {
type: 'bar'
},
dataLabels: {
enabled: false
},
series: [{
name: 'sales',
data: data
}],
xaxis: {
categories: labels
},
yaxis: {
labels: {
formatter: function(data) {
//Setup new Formatting class variable
var Formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
});
return Formatter.format(data);
}
}
},
}
var chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();
</script>
{% endblock content %}
I have a Kendo Column for date value, There we have used a pipe like this at template property inside the below column.
Now i want to change the format of kendo grid column according to the date format
My Problem/Question :- I am retrieving Date format such as dd-MM-yyyy or MM-dd-yyyy or dd-MM-yy or MM-dd-yy from localStorage which is dynamic according to the user preference.
But whenever i use that variable in the template (containing date format ex: dd-MM-yyyy) in place of the default date pipe having same format of default date pipe, kendo Do not accept it and gives the error : Cannot read property 'timeout' of undefined kendo
const myDateFormat = this.$localStorage.dateFormat;
function getDefaultColumns($translate) {
return [
{
field: 'INVOICE_DATE',
title: $translate.instant('invoiceDate'),
headerTemplate: '{{ \'invDate\' | translate }}',
template: '{{ dataItem.INVOICE_DATE | date: \'yyyy-MM-dd\' }}',//i am using the localStorage value here
filterable: {
ui(element) {
element.kendoDatePicker({
format: 'yyyy-MM-dd'
});
}
},
width: 100
}
];
}
I think you can accomplish what you want with a ES2015 Template String.
Consider this modification to your program listing:
function getDefaultColumns($translate) {
let dateFormat = 'yyyy-MM-dd';
return [
{
field: 'INVOICE_DATE',
title: $translate.instant('invoiceDate'),
headerTemplate: '{{ \'invDate\' | translate }}',
template: `{{ dataItem.INVOICE_DATE | date: \'${dateFormat}\' }}`,
filterable: {
ui(element) {
element.kendoDatePicker({
format: dateFormat
});
}
},
width: 100
}
];
}
i'm working in Django, to draw some graph in function of my modules. ie: if i have 2 modules, i want 2 charts , if 8 modules, 8 charts.
Modules are integreted in a plugin. so i can list all modules found in a plugin. i did this in Django:
def plugin_graph(request, hub_uid, plugin_uid):
request.session['is_admin'] = True
hub = Hub.objects.get(mac=hub_uid)
fields = []
if request.method == 'GET':
if 'field' in request.GET:
fields.append(request.GET['field'])
plugin = Plugin.objects.get(uid=plugin_uid, hub=Hub.objects.get(mac=hub_uid))
#on recupere lensemble desmodules de ce plug
modules = plugin.get_modules_list()
#pour chak module, tracer son graph
for m in modules:
modules_list = {'uid':m.uid,
'name':m.name,
'version':m.version,
'type':m.type,
'time':m.last_time(),
'rssi':m.rssi(),
'status_icon':m.status_icon()}
module = Module.objects.get(uid=m.uid, plugin=Plugin.objects.get(uid=plugin_uid, hub=Hub.objects.get(mac=hub_uid)))
historic = sorted(ModuleDocument.objects.filter(module=module), key=getKey)
values = get_graph_values(historic=historic, dates=None, fields=fields)
print values
field = None if len(fields) < 1 else fields[0]
return render(request, "admin/graph2.html",
{
'values': values,
'hub': hub_uid,
'plugin': plugin_uid,
'uid': m.uid,
'module': module,
'fields': module.get_number_fields(),
'field': field,
'level': 'module',
}
)
After recovering all my modules i draw the charts like that in javascript:
<script>
var ctx = document.querySelector("#chart");
var data = JSON.parse('{{ values }}'.replace(/"/g, '"'));
var labels = [];
var values = [];
var beginAtZero = true;
for (obj in data) {
labels.push(data[obj].x);
values.push(data[obj].y);
if (data[obj].y < 0) {
beginAtZero = false;
}
}
var lineChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: "{{field}}",
data: values,
borderColor: '#97168F'
}]
},
options: {
scales: {
xAxes: [{
time: {
unit: 'day'
}
}],
yAxes: [{
ticks: {
beginAtZero:beginAtZero
}
}]
}
}
});
</script>
My problem is just one chart is printed. i would like to put it in a for loop to recuperate all data & labels of each module to draw normally all charts i want.
Thank u for your help
You need to utilise the forloop.counter method in the django template to dynamically name a number of items, otherwise the charts will just get overwritten each time and you are just left with the last chart. Its worth noting that I include this code in the block content not a specific js block.
In the example below, the items that are dynamically named are;
The container div
<div id = 'emg-{{forloop.counter}}'>
The canvas
<canvas id="myChart-{{forloop.counter}}">
The chart JS function name
var func_name = "container-{{forloop.counter}}";
func_name = new Chart(
document.getElementById('myChart-{{forloop.counter}}'),{
type: 'scatter',
I've included the full code below. I appreciate my example is different from your posted code, but it demonstrates the concept of dynamically creating certain elements.
{% for time, name_list, value_list, latitude_list, longitude_list, polyline_list in data %}
{% with forloop.counter as track_object_counter %}
<div id = 'emg-{{forloop.counter}}'>
{% for item in emg_data %}
{% if item.loop_id == track_object_counter %}
<div id = "emg-plot" style="height:15rem; padding-top: 1rem;">
<canvas id="myChart-{{forloop.counter}}">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
var y_data = {{item.data|strip_apostrophe}}
var x_data = '{{item.name}}'
var func_name = "container-{{forloop.counter}}";
func_name = new Chart(
document.getElementById('myChart-{{forloop.counter}}'),{
type: 'scatter',
data: {
datasets: [{
showLine: true,
label: x_data,
data: y_data,
backgroundColor: 'rgba(141,49,123,0.7)',
borderWidth: 2,
borderColor: 'rgba(141,49,123,0.7)'
}],
},
});
</script>
</canvas>
</div>
{% endif %}
{% endfor %}
</div>
{% endwith %}
{% endfor %}
Twig malforms my array keys and adds " " brackets to my array keys passed from a symfony2 controller.
The array is passed to a Javascript graphics library which requires:
[{x:"disabled test object",y:"17",label:"disabled test object"}]
Instead {{ array|json_encode|raw }} as suggested by the Twig docs and other SO questions I've read through returns the unreadable:
[{"x":"disabled test object","y":"17","label":"disabled test object"}]
I figure this should not be complicated to achieve but going through the json_encode options so far has not resulted in a clear answer. I am unsure whether there is something I can do from PHP so I've added the tag for now.
EDIT:
I am now attempting to step through the array manually using Twig. {{dump(points)}} confirms it is filled properly
{% set points = chart.dataPoints|json_encode|raw %} <=== this was the problem
dataPoints:
{% for point in points %}
{{ dump(point) }}
{ x: {{ point.x }}, y: {{ point.y }}, label: {{ point.label }} }
{% if loop.lastIndex != true %}
,
{% endif %}
{% endfor %}
But this does not work either as the dump is never reached. Is this the correct way of trying to access objects in a foreach via Twig though? This code is an amalgamation of several Twig docs tutorials.
EDIT 2, the solution:
The line {% set points = chart.dataPoints|json_encode|raw %} turned the whole array into a single string, making it impossible for javascript to interpret as an array. After removing this, all that was left was to make sure the query result had the proper array keys and to transform the X-axis data before passing it to Twig.
$i = 0;
$points = array();
/** #var array $query_result*/
foreach($query_result as &$row) {
foreach($row as $value) {
$point[] = [
'x' => ($i)*10,
'y' => $value['y'],
'label' => $value['label']
];
$points[$i] = $point;
$i++;
}
}
Quotes are not a problem for CanvasJS. As you can see in the example below, "x": works (I took this example):
window.onload = function () {
var chart = new CanvasJS.Chart("chartContainer",
{
title:{
text: "Top Oil Reserves"
},
data: [{
dataPoints: [
{ x: 1, y: 297571, label: "Venezuela"},
{ "x": 2, "y": 267017, label: "Saudi" }
]
}]
});
chart.render();
}
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/canvasjs/1.7.0/canvasjs.min.js"></script>
</head>
<body>
<div id="chartContainer" style="height: 200px; width: 100%;"></div>
</body>
</html>
So we need to provide a JSON array for dataPoints:
Define the PHP array in your Controller's function and pass it to the template:
public function myAction()
{
// …
$json = array(
array(
'x' => 1,
'y' => 297571,
'label' => 'Venezuela',
),
array(
'x' => 2,
'y' => 267017,
'label' => 'Saudi',
),
);
return array(
// …
'json' => $json,
);
}
Display the array in the template and pass it to dataPoints :
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/canvasjs/1.7.0/canvasjs.min.js"></script>
<script>
var json = {{ json|json_encode|raw }};
window.onload = function () {
var chart = new CanvasJS.Chart("chartContainer",
{
title:{
text: "Top Oil Reserves"
},
data: [{
dataPoints: json
}]
});
chart.render();
}
</script>
<div id="chartContainer" style="height: 300px; width: 100%;"></div>
The rendered output will be:
// …
<script>
var json = [{"x":1,"y":297571,"label":"Venezuela"},{"x":2,"y":267017,"label":"Saudi"}];
// …
CanvasJS will be able to read this JavaScript array and display the chart.
It looks like the first one is a JavaScript object, and the second one is JSON, try running JSON.parse on the string like this to convert it back in to an object:
var fixed = JSON.parse('[{"x":"disabled test object","y":"17","label":"disabled test object"}]');
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
I have created a jsbin at http://jsbin.com/ifimadOw/11/edit to illustrate.
I have this listview object:
<ul id="marketplace-categories-listview" data-bind="source: results"></ul>
And I have this dataset:
dsCats = new kendo.data.DataSource({
transport: {
read: {
url: myUrl,
data: {
key: myKey
}
}
}
});
$("#marketplace-categories-listview").kendoMobileListView({
dataSource: dsCats,
template: $("#marketplace-product-template").text()
});
The data returned from the API looks something like this:
{"count": 3, "results": ["Acupuncture Therapy","Automobiles","Lawn Care"]}
And here is my template:
<script type="text/x-kendo-tmpl" id="marketplace-categories-template">
<li data-bind="text: this"></li>
</script>
Because my data doesn't have named elements, I can't use something like "#:category#" in the template. I have also tried data-bind (as above), but so far nothing works. Surely there is a way to do this.
Simply use data (which is the name of the context variable passed to the template function) in your template:
$("#category-listview").kendoMobileListView({
dataSource: dsCats,
template: "#= data #"
});
(updated JSBin)