Javascript not working when Alert is removed - javascript

I use D3.js and upon loading data from csv file the page isn't rendering when I remove the alert() statements. I;'m not a js specialist and I know it's something to do with asynchronous modes of operation but I don't know what to change.
when alert("AAAAAAAA"); is removed it works I appreciate this is a bespoke
issue so the other posts on the subject were not easily understood.
Many Thanks
Andy
</style>
<div id='dashboard2' align="center"></div>
<div id='dashboard' align="center"></div>
<script src="/xxxxxxxx/templates/uber/js/d3.min.js"></script>
<script type="text/javascript">
var climate_csv = function()
{
d3.csv("/xxxxxxxx/templates/uber/js/theclimate.csv", function(climate_statistics)
{
//prices is an array of json objects containing the data in from the csv
console.log("climate_statistics:", climate_statistics)
climate_data = climate_statistics.map(function(d)
{
//each d is one line of the csv file represented as a json object
console.log("d", d)
month = d.month;
console.log("month:", d.month, month)
low = +d.low;
console.log("low:", d.low, low)
high = +d.high;
console.log("high:", d.high, high)
rainfall = +d.rainfall;
console.log("rainfall:", d.rainfall, rainfall)
sunshine = +d.sunshine;
console.log("sunshine:", d.sunshine, sunshine)
nighttime = +d.nighttime;
console.log("nighttime:", d.nighttime, nighttime);
return {"Month": month, "cStats": {"low": low , "high": high} , "rainfall": rainfall , "sun":{"Sunshine": sunshine , "Nighttime": nighttime}}
})
})
}
</script>
<script type="text/javascript">
var climateStats2=[
{TempRange:'Low',cStats:{low:0}}
];
var climateStats3=[
{TempRange3:'High',cStats:{high:0}}
];
var climateStats4=[
{TempRange4:'Rainfall',cStats:{rainfall:0}}
];
var climateStats5=[
{TempRange4:'Rainfall',cStats5:{lower5:0, upper5:0}}
];
climate_csv();
alert("AAAAAAAA");
dashboard('#dashboard',climate_data,climateStats2,climateStats3,climateStats4,climateStats5);

Seems like your data is not fully loaded, when you call dashboard. It works with the alert because while the alert is open, your script is paused. Another thing is, that you are using global variables here. Let's avoid this using callbacks.
D3's csv function uses a callback and calls it, when the data is ready.
d3.csv("/xxxxxxxx/templates/uber/js/theclimate.csv", function(climate_statistics) {
/* ... */
});
You can now either call the dashboard function inside the callback, or add a callback to your function. Let's do the latter here:
var climate_csv = function( callback ) {
d3.csv(
"/xxxxxxxx/templates/uber/js/theclimate.csv",
function( climate_statistics ) {
var climate_data = climate_statistics.map(function( d ) {
month = d.month;
low = +d.low;
high = +d.high;
rainfall = +d.rainfall;
sunshine = +d.sunshine;
nighttime = +d.nighttime;
return {
"Month": month,
"cStats": {
"low": low,
"high": high
},
"rainfall": rainfall,
"sun": {
"Sunshine": sunshine,
"Nighttime": nighttime
}
};
});
// we are done with mapping our data
// let's call the callback with the data
callback(climate_data);
});
};
/* ... */
climate_csv(function( climate_data ) {
dashboard('#dashboard', climate_data, climateStats2, climateStats3,
climateStats4, climateStats5);
});

Put the function that is not working when you remove the alert inside the success callback, that will make the trick.
.csv works async, so when you put the alert, the request is completed on the background, when you remove it no "wait time" is added (as it should be) and that's why it's not working.
Not using d3.js, but this doc could help:
https://github.com/mbostock/d3/wiki/CSV
d3.csv("path/to/file.csv")
.row(function(d) { return {key: d.key, value: +d.value}; })
.get(function(error, rows) { console.log(rows); });
Hope it helps.

Related

Using AJAX, JavaScript to call python flask function with return to JavaScript

I know that you can have javascript to call a python flask function and be able to return data to a designated id. Like this:
HTML
<div id = "update"> </div>
<script type="text/javascript">
var counter = 0;
window.setInterval(function(){
$("#update").load("/game?counter=" + counter);
counter++;
}, 5000)
views.py
from flask import request
#app.route("/game")
def live_game():
textlist = ['a','b','c','d']
counter = request.args.get('counter')
return "<p> " + textlist[counter] + " </p>"
I found this in a previous post. What I would like to do is update utilize this method in updating some cool justgage that I found online to show the most up to date temperature and humidity readings from my database. Here is the script that I was wanting to use:
HTML
<div class="container">
<div class="jumbotron">
<h1>Historical Environmental Readings</h1>
<div class="container-fluid" id="dht-container">
<div id="g1" style="width: 200px; height: 150px;"></div>
<div id="g2" style="width: 200px; height: 150px;"></div>
</div>
</div>
</div>
.....
<script>
function ajaxd(NodeID) {
//reload result into element with id "dht-container"
$(??????).load("/tempnodeDHT", function() { alert( "Temp Load was performed." ); });
document.addEventListener("DOMContentLoaded", function (event) {
var g1 = new JustGage({
id: "g1",
value: 50,
min: -20,
max: 150,
title: "DHT Temp",
label: "temperature",
pointer: true,
textRenderer: function (val) {
if (val < NODE_EnvCP.low_temp) {
return 'Cold';
} else if (val > NODE_EnvCP.hot) {
return 'Hot';
} else if (val === NODE_EnvCP.optimum_temp) {
return 'OK';
}
},
});
var g2 = new JustGage({
id: "g2",
value: 50,
min: 0,
max: 100,
title: "Target",
label: "Humidity",
pointer: true,
textRenderer: function (val) {
if (val < NODE_EnvCP.low_hum) {
return 'LOW';
} else if (val > NODE_EnvCP.high_hum) {
return 'HIGH';
} else if (val === NODE_EnvCP.optimum_hum) {
return 'OK';
}
},
});
setInterval(function () {
(currentTemp, currentHumidity)=ajaxd();
g1.refresh(currentTemp);
g2.refresh(currentHumidity);
return false;
}, 2500);
});
</script>
This is my python flask function:
run.py
#app.route('/nodeDHT')
def getLatestDHT():
NodeID = request.args.get('NodeID')
df = DAO.Pull_CURRENT_DHT_Node_Data(self, NodeID)
currentTemp = df.Temperature[0]
currentHumidity = df.Humidity[0]
return (currentTemp, currentHumidity)
I was hoping that I could change the ?????? inside
$(??????).load("/nodeDHT", function() { alert( "Temp Load was performed." ); });
so that the two variables (currentTemp, currentHumidity) would end up back into the javascript portion so that the gages would update every 2.5 seconds. Also, am I passing the variable back to the python flask? there is a variable already pushed to the html when it was rendered.
EDIT:
could I do something like this:
#app.route('/nodeDHT')
def getLatestDHT():
NodeID = request.args.get('NodeID')
df = DAO.Pull_CURRENT_DHT_Node_Data(self, NodeID)
currentTemp = df.Temperature[0]
currentHumidity = df.Humidity[0]
return json.dumps(currentTemp, currentHumidity)
and in the javascript side do something like this?
function ajaxd(NodeID) {
//reload result into javascript
$.get("/nodeDHT",function( currentTemp, currentHumidity ){ console.log($.parseJSON(currentTemp, currentHumidity)});
What I'm really asking is. How can I pass single/multiple variables to the python flask function from the javascript function and then get back a dataframe where I can use column values to update a chart or multiple variables back to the javascript function to be used in a setinterval to be used for multiple functions such as updating justgage
setInterval(function () {
(currentTemp, currentHumidity)=ajaxd();
g1.refresh(currentTemp);
g2.refresh(currentHumidity);
return false;
}, 2500);
---------------------DOUBLE EDIT -----------------------
COULD I DO SOMETHING LIKE THIS:
function UPDATEGAGES(NodeID) {
$.get('/nodeDHT?NodeID='+NodeID+'&startdatetime='+startdatetime,
function(data){ const parsed = JSON.parse(data)};
g1.refresh(currentTemp);
g2.refresh(currentHumidity);
});
setInterval(function () {
UPDATEGAGES(NodeID);
return false;
}, 2500);
If you want to send variables to server in get method, use variables in url
'/tempnodeDHT?NodeID='+your_nod_id+'&anotherVar='+value+'&anotherVar2='+value2
You can access them in your flask server as below
NodeID = request.args['NodeID']
anotherVar = request.args['anotherVar']
anotherVar2 = request.args['anotherVar2']
If you want to send multiple variables from flask server to your front end, send it as JSON
return jsonify({'currentTemp': currentTemp, 'currentHumidity': currentHumidity })
When you handle it the response from the server, again parses it to JSON.
$.get( '/nodeDHT/tempnodeDHT?NodeID='+your_nod_id+'&anotherVar='+value+'&anotherVar2='+value2, function( data ) {
const parsed = JSON.parse(data)
// here you can access your 'currentTemp' variable from parsed.currentTemp
});
EDIT
For your final desired output
function UPDATEGAGES(NodeID, startdatetime) {
$.get('/nodeDHT?NodeID='+NodeID+'&startdatetime='+startdatetime,
function(data){
const parsed = JSON.parse(data)
g1.refresh(parsed.currentTemp);
g2.refresh(parsed.currentHumidity);
};
)
};
setInterval(function () {
UPDATEGAGES(NodeID, startdatetime);
return false;
}, 2500);

How to auto update value from Flask inside JS in html?

Im trying to get a sensor value from Flask to auto update in a javascript gauge. The sensor input is named "a1" in Flask python.
I got it to work in a regular html code like this:
<div id="main">
<h4>Sensor 1: <span class="bold white">{{a1}}</span> bar </h4>
and to auto update it every second with this:
$(document).ready(function(){
setInterval(function(){
$("#main").load(window.location.href + " #main" );
}, 1000);
});
and the value even shows up in the js gauge:
<div id="PT1" class="gauge-container pt">
<span class="label">Pressure Transmitter 1</span>
<span class="label2">0 - 400 bar</span>
</div>
JS:
var PT1 = Gauge(
document.getElementById("PT1"), {
max: 400,
dialStartAngle: 135,
dialEndAngle: 45,
label: function(value) {
return Math.round(value * 100) / 100;
}
}
);
(function loop() {
var value1 = {{a1}}
PT1.setValueAnimated(value1, 1);
setTimeout(loop, 1000);
})();
My problem is that the gauge value dont auto update, it only shows the correct value when I refresh the page, and stays unchanged until I refresh again. (while the html code keeps updating every second)
Is this possible to solve?
Thanks
Vincent
Here's my final working example code.
Python:
from flask import Flask,render_template, jsonify
from random import random
app = Flask(__name__)
#app.route('/read_sensor')
def read_sensor():
data = {'a1': (random()*150)}
return jsonify(data)
#app.route('/')
def index():
return render_template("index.html")
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80, debug=True)
HTML
<body>
<div id="PT1" class="gauge-container">
<span class="label">DEFAULT</span>
</div>
</div>
<script type='text/javascript'>
var PT1 = new Gauge(
document.getElementById("PT1"), {
max: 400,
dialStartAngle: 135,
dialEndAngle: 45,
label: function(value) {
return Math.round(value * 100) / 100;
}
}
);
function callme(){
//This promise will resolve when the network call succeeds
//Feel free to make a REST fetch using promises and assign it to networkPromise
var networkPromise = fetch('/read_sensor')
.then(response => response.json())
.then(data => {
console.log(data);
PT1.setValueAnimated(data['a1'], 1);
});;
//This promise will resolve when 2 seconds have passed
var timeOutPromise = new Promise(function(resolve, reject) {
// 2 Second delay
setTimeout(resolve, 2000, 'Timeout Done');
});
Promise.all(
[networkPromise, timeOutPromise]).then(function(values) {
console.log("Atleast 2 secs + TTL (Network/server)");
//Repeat
callme();
});
}
callme();
</script>
</body>
Thanks!
You need to write some Javascript to query the endpoint periodically. I used the approach in this answer which makes a request every two seconds, without making a second call when a request is under way.
You'll need to build a Flask route which returns only JSON with the sensor data. I mocked this with random numbers:
import random
#app.route('/read_sensor')
def read_sensor():
# return the actual sensor data here:
return {'a1': random.choice(range(1,400))}
Then use the following JS which makes a request every 2000ms. I had to tweak your example slightly, changing the div to a canvas to get guage.js to work properly:
<html>
<body>
<div class="chart">
<canvas id="PT1"></canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gauge.js/1.3.7/gauge.min.js" integrity="sha512-J0d1VfdfTSDoDPEsahCtf2nC+groXdWkuQFyJjS+s3CpKj63X9Hf3pMEJtjIJt/ODh0QwTRx2/OioL+9fMoqSA==" crossorigin="anonymous"></script>
<script type='text/javascript'>
//
// Guage init code
//
var PT1 = new Gauge(
document.getElementById("PT1"), {
max: 400,
dialStartAngle: 135,
dialEndAngle: 45,
label: function(value) {
return Math.round(value * 100) / 100;
}
}
);
//
// End guage init code
//
function callme(){
//This promise will resolve when the network call succeeds
//Feel free to make a REST fetch using promises and assign it to networkPromise
var networkPromise = fetch('/read_sensor')
.then(response => response.json())
.then(data => {
console.log(data);
//
// Set guage code
//
PT1.set(data['a1']);
//
// End set guage code
//
});;
//This promise will resolve when 2 seconds have passed
var timeOutPromise = new Promise(function(resolve, reject) {
// 2 Second delay
setTimeout(resolve, 2000, 'Timeout Done');
});
Promise.all(
[networkPromise, timeOutPromise]).then(function(values) {
console.log("Atleast 2 secs + TTL (Network/server)");
//Repeat
callme();
});
}
callme();
</script>
</body>
</html>
Here's what this renders like:
Thanks for your reply and example.
I just cant get your example to work with my gauge...
Can you please show an example of the rest of the flask route? Like the part with "return / render html"
Here is a simplified copy of my old Flask:
(that works, but not updating)
#app.route('/')
def index():
a1 = sensors()
return render_template("index.html", a1=a1)
def sensors():
a1 = "%0.2f" % (287.8 + random())
return a1
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80, debug=True)
Isnt there an easy way to just get the "a1" to be updated inside the JS for the gauge?
(function loop() {
var value1 = {{a1}}
PT1.setValueAnimated(value1, 1);
setTimeout(loop, 1000);
})();
If I replace {{a1}} with "Math.random() * 100," then its updating every second.
Full example of the gauges here:
https://codepen.io/ernestoulloa/pen/abmGYyY (I am using gauge1)

Group JSON data into weeks / months without additional external library?

I am looking for a solution to group data into weeks / months without external library. I have seen the D3.js nest() option here: how can i group JSON data into the weeks according to calender?
Here another way using npm: https://www.npmjs.com/package/group-by-time
Maybe I am crazy having grown up in the age of dialup, but I still like to keep how many things I load on a page down to what is actually needed instead of loading everything possible, just in case I want to use it, even though the user "might" already have a cached copy from a CDN.
I am currently using Chart.js to display data, also available are Bootstrap and jQuery. I would love to be able to switch the chart between day, week month, using only javascript or jQuery, which seems like it should be a fairly common thing, but I don't see any examples without going for a bigger library like I mentioned above.
var chart={
dates: ['2015-09-01', '2015-09-02', '2015-09-03', '2015-09-04', '2015-09-05', '2015-09-06', '2015-09-07', '2015-09-08', '2015-09-09', '2015-09-10', '2015-09-11', '2015-09-12', '2015-09-13', '2015-09-14', '2015-09-15', '2015-09-16', '2015-09-17', '2015-09-18', '2015-09-19', '2015-09-20', '2015-09-21', '2015-09-22', '2015-09-23', '2015-09-24', '2015-09-25', '2015-09-26', '2015-09-27', '2015-09-28', '2015-09-29', '2015-09-30', '2015-10-01', '2015-10-02', '2015-10-03', '2015-10-04', '2015-10-05', '2015-10-06', '2015-10-07', '2015-10-08', '2015-10-09', '2015-10-10', '2015-10-11', '2015-10-12', '2015-10-13', '2015-10-14', '2015-10-15', '2015-10-16', '2015-10-17', '2015-10-18', '2015-10-19', '2015-10-20', '2015-10-21', '2015-10-22', '2015-10-23', '2015-10-24', '2015-10-25', '2015-10-26', '2015-10-27', '2015-10-28', '2015-10-29', '2015-10-30', '2015-10-31', '2015-11-01', '2015-11-02', '2015-11-03', '2015-11-04', '2015-11-05', '2015-11-06', '2015-11-07', '2015-11-08', '2015-11-09', '2015-11-10', '2015-11-11', '2015-11-12', '2015-11-13', '2015-11-14', '2015-11-15', '2015-11-16', '2015-11-17', '2015-11-18', '2015-11-19', '2015-11-20', '2015-11-21', '2015-11-22', '2015-11-23', '2015-11-24', '2015-11-25', '2015-11-26', '2015-11-27', '2015-11-28', '2015-11-29', '2015-11-30', '2015-12-01', '2015-12-02', '2015-12-03', '2015-12-04', '2015-12-05', '2015-12-06', '2015-12-07', '2015-12-08', '2015-12-09', '2015-12-10', '2015-12-11', '2015-12-12', '2015-12-13', '2015-12-14', '2015-12-15', '2015-12-16', '2015-12-17', '2015-12-18', '2015-12-19', '2015-12-20', '2015-12-21', '2015-12-22', '2015-12-23', '2015-12-24', '2015-12-25', '2015-12-26', '2015-12-27', '2015-12-28', '2015-12-29', '2015-12-30', '2015-12-31', '2016-01-01', '2016-01-02', '2016-01-03', '2016-01-04', '2016-01-05', '2016-01-06', '2016-01-07', '2016-01-08', '2016-01-09', '2016-01-10', '2016-01-11', '2016-01-12', '2016-01-13', '2016-01-14', '2016-01-15', '2016-01-16', '2016-01-17', '2016-01-18', '2016-01-19', '2016-01-20', '2016-01-21', '2016-01-22', '2016-01-23', '2016-01-24', '2016-01-25', '2016-01-26', '2016-01-27', '2016-01-28', '2016-01-29', '2016-01-30', '2016-01-31', '2016-02-01', '2016-02-02', '2016-02-03', '2016-02-04', '2016-02-05', '2016-02-06', '2016-02-07', '2016-02-08', '2016-02-09', '2016-02-10', '2016-02-11', '2016-02-12', '2016-02-13', '2016-02-14', '2016-02-15', '2016-02-16', '2016-02-17', '2016-02-18', '2016-02-19', '2016-02-20', '2016-02-21', '2016-02-22', '2016-02-23', '2016-02-24', '2016-02-25', '2016-02-26', '2016-02-27', '2016-02-28', '2016-02-29'],
data: [77.02, 63.80, 21.64, 86.60, 65.40, 46.25, 27.38, 66.65, 67.25, 65.59, 64.80, 01.00, 32.75, 04.30, 51.92, 02.75, 40.20, 72.30, 62.90, 83.60, 66.66, 37.30, 93.90, 01.50, 55.77, 50.00, 73.20, 30.03, 07.95, 21.65, 07.93, 66.94, 11.72, 33.75, 22.80, 14.55, 68.78, 66.78, 52.35, 06.24, 64.78, 22.21, 19.08, 23.69, 54.40, 39.55, 28.76, 22.25, 09.85, 07.50, 22.47, 75.94, 93.34, 16.29, 28.98, 64.40, 78.68, 30.65, 96.65, 99.35, 77.50, 75.30, 89.85, 97.50, 53.90, 97.55, 28.98, 75.08, 25.66, 41.00, 73.72, 68.50, 95.40, 49.50, 32.50, 86.00, 05.43, 88.19, 50.39, 03.90, 82.90, 53.78, 94.20, 82.40, 12.63, 78.80, 07.50, 66.50, 41.75, 91.25, 34.50, 22.50, 85.50, 80.00, 33.75, 59.50, 52.50, 73.25, 76.50, 38.75, 11.00, 55.00, 37.25, 92.50, 74.75, 55.75, 37.25, 61.01, 90.95, 87.65, 99.08, 84.49, 47.00, 72.20, 45.95, 44.35, 10.90, 27.05, 63.10, 63.50, 66.48, 97.25, 39.85, 81.50, 57.90, 02.78, 72.95, 41.55, 39.44, 15.85, 06.60, 13.60, 87.10, 86.40, 90.75, 48.30, 29.75, 16.25, 20.51, 45.40, 51.10, 82.00, 24.24, 92.88, 81.75, 18.50, 89.15, 55.75, 53.50, 74.90, 41.35, 61.40, 07.80, 56.80, 33.75, 75.02, 78.50, 46.10, 39.25, 95.00, 22.85, 36.00, 43.53, 63.80, 32.85, 88.30, 89.69, 05.75, 16.15, 15.25, 20.55, 44.50, 46.28, 71.75, 19.45, 41.75, 25.75, 09.05, 58.77, 76.20, 30.45, 71.75]
};
I'm assuming that date format is YYYY-MM-DD as in sample and for convenience I'm saving both dates and data in different arrays.
var dates = chart.dates;
var data = chart.data;
Keeping above assumptions in mind, you can easily group data by months.
var groupByMonth = {};
dates.forEach(function (d, i) {
var v = data[i];
var monthYear = d.slice(0, 7);
if (groupByMonth.hasOwnProperty(monthYear)) {
groupByMonth[monthYear].push(v);
} else {
groupByMonth[monthYear] = [v];
}
});
console.log(groupByMonth)
However to group by week, you need to find week number. Here is a extension method to do that so:
Date.prototype.getWeekNumber = function(){
var d = new Date(+this);
d.setHours(0,0,0);
d.setDate(d.getDate()+4-(d.getDay()||7));
return Math.ceil((((d-new Date(d.getFullYear(),0,1))/8.64e7)+1)/7);
};
Using above extension method you can easily group data by week number too. Week number repeats in each year so, I'm using combination of week and year to uniqly identify any week.
var groupByWeek = {};
dates.forEach(function (d, i) {
var v = data[i];
var weekYear = d.slice(0, 4) + '-' + new Date(d).getWeekNumber();
if (groupByWeek.hasOwnProperty(weekYear)) {
groupByWeek[weekYear].push(v);
} else {
groupByWeek[weekYear] = [v];
}
});
console.log(groupByWeek)
#Adnan UmerĀ“s solution is probably better for your case since you already have the dates as strings, but here is a more general method in case you had the date instead of string:
function roundDate(date,type){
var d = new Date(date) // so as to not override
var types = ["day","week","month"]
var idx = types.indexOf(type)
if(idx > -1){ // remove all less than day
d.setMilliseconds(0)
d.setSeconds(0)
d.setMinutes(0)
d.setHours(0)
if(idx > 0){ //remove day of the week
d.setDate(d.getDate() - d.getDay()) // make it a sunday
if(idx > 1){ //remove day of month
d.setDate(1)
}
}
}
return d;
}
function parseDate(str){ // in your case, we need to keep the date disregarding the locale offset
return new Date(new Date(str).getTime() + new Date().getTimezoneOffset()*60*1000)
}
var lastDate = null
var grouping = "month"
var datesGrouped = []
var dataGrouped = []
function addToLast(arr,val){return arr[arr.length-1]+=val}
//I am assumming your dates are already sorted
chart.dates.map(function(date,index){
data = chart.data[index] // get corresponding data point
var group = roundDate(parseDate(date),grouping).getTime()
if(group == lastDate){
addToLast(dataGrouped, data)
}else{
datesGrouped.push(group)
dataGrouped.push(data)
lastDate = group
}
})
console.log(datesGrouped, dataGrouped)

Reference Global jquery function variable within foreach loop

I want to change the value of a global jquery variable within the foreach loop every time there is a new model item. I want to add new dates to the calendar but cant do that until I can access these functions from foreach loop.
*edit***
I over simplified my example for the question which was answered correctly by vov v. The actual code will do a lot more than add a value as it will add data to a calendar. I've added more code to show what it will do a little better
jquery:
<div id="calendar" style="width: 500px;" />
<script type="text/javascript">
$(document).ready(function () {
var calendar = $('#calendar').glDatePicker(
{
showAlways: true,
borderSize: 0,
dowOffset: 1,
selectableDOW: [1, 2, 3, 4, 5],
selectableYears: [2012, 2013, 2014, 2015],
specialDates: [
{
date: new Date(2013, 0, 8),
data: { message: 'Meeting every day 8 of the month' },
repeatMonth: true
},
{
date: new Date(2013, 5, 7),
data: { message: 'Meeting every day 8 of the month' }
},
],
onClick: function (target, cell, date, data) {
target.val(date.getFullYear() + ' - ' +
date.getMonth() + ' - ' +
date.getDate());
if (data != null) {
alert(data.message + '\n' + date);
}
}
}).glDatePicker(true);
$('#visible').change(function () {
var showAlways = eval($(this).val());
calendar.options.showAlways = showAlways;
if (!showAlways) {
calendar.hide();
}
else {
calendar.show();
}
});
});
var value = 0;
$('#total').click(function () {
alert(value);
});
function add() {
// will eventually add new specialDates to the calendar taken from model items
//test lines
//value = value + 1;
//return value;
}
</script>
razor view:
<input type="button" id="total" />
#foreach (var item in Model){
if (item.AppointmentStatus == "active")
{
// item display code
#: <script type="text/javascript"> add();</script>
}
if (item.AppointmentStatus == "history")
{
// item display code
}
}
I run this and get error below as it doesnt see the other code
'0x800a1391 - JavaScript runtime error: 'add' is undefined'
If you just want to capture "a count" that you want to send down to your client then you can simply do it like this:
<script>
var value = '#Model.Count';
// the rest of you script goes here
$(document).ready(function () {
$('#total').click(function () {
alert(value);
}
});
</script>
So say you have 7 items in your model, then the html that will be generated is this:
var value = 7;
and when you click on that total element it will give you an alert with the text 7.
Try moving your add function and variable declaration outside of doc ready. The functions in doc ready are not available until your razor has executed.

what's wrong with this automatic creation of charts for time spent on webpages?

!SOLVED!
I want to automatically create charts with users and their time spent on pages of a website.
I have a file - "log.xml" where I keep information with users (customers), visited pages, dates and their time spent; and after I "get" this Xml file with Ajax, I want to parse it and create with values "extracted" charts with JqPlot.
My problem is that I can't loop through more than just one customer and it don't build chart for the single customer.
If I remove the code block with initialization of variable plot I can loop through all my customers from Xml.
Please, if someone can tell me what is wrong, and how to create charts for all customers...
Here is the code of the file "log.xml":
<?xml version="1.0"?>
<log>
<customer id="14" name="Florin Virdol">
<page name="/mobilestore/index.php">
<date_ts on="2011-12-02" timeSpent="205"/>
</page>
<page name="/mobilestore/products_all.php">
<date_ts on="2011-12-02" timeSpent="15"/>
</page>
</customer>
<customer id="0" name="guest">
<page name="/mobilestore/services.php">
<date_ts on="2011-12-02" timeSpent="50"/>
</page>
</customer>
</log>
Here is the javascript code of the "operations":
$(document).ready(function()
{
//read from xml
$.ajax({
type: "GET",
url: "log.xml",
dataType: "xml",
success: parseXml
});
});//ready
//parse xml
function parseXml(xml) {
var i = 0;
$(xml).find("customer").each(function() {
$('<div class = "jqplot graph" id = "chart' + i + '"></div>').appendTo('#content');
var customerName = $(this).attr("name");
var line_inside = []; // declare as array
$(this).find("page").each(function() {
var pageName = $(this).attr("name");
$(this).find("date_ts").each(function() {
var timeSpent_ = $(this).attr("timeSpent");//if mai multe timespent, sa faca totalul, else singuru; timespent
line_inside.push([pageName,timeSpent_]); //do not string cat, push onto array
});
});
var line = '[' + line_inside + ']';
//--------jqplot----!!! if i remove this block, will loop through customers------------
var plot = $.jqplot('chart' + i, [line_inside],
{
title: customerName,
series:[{renderer:$.jqplot.BarRenderer}],
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
label: 'Web Page',
labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
tickRenderer: $.jqplot.CanvasAxisTickRenderer,
tickOptions: { labelPosition:'middle', angle: -30 }
},
yaxis: {
autoscale:true,
label: 'Total Time Spent',
labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
tickRenderer: $.jqplot.CanvasAxisTickRenderer,
tickOptions: { labelPosition:'middle', angle: -30 }
}
}
});
//-------jqplot----!!! if i remove this block, will loop through customers------------
i++;
});//find customer
}//parse xml
SOLUTION: made modifications that Mark suggested, and it works.
(now, above code works!)
You are passing strings that look like arrays and not actual arrays to jqplot.
Try:
var line_inside = []; // declare as array
$(this).find("page").each(function() {
var pageName = $(this).attr("name");
$(this).find("date_ts").each(function() {
var timeSpent_ = $(this).attr("timeSpent");//if mai multe timespent, sa faca totalul, else singuru; timespent
line_inside.push([pageName,timeSpent_]); //do not string cat, push onto array
});
});
alert(line_inside); // this is an array of arrays
var plot = $.jqplot('chart' + i, [line_inside],
Since you want a different plot for each customer, you need to make plot a local var to your inline function: "var plot" not just "plot" -- same goes for "line". You are assigning a global scope variable and overwriting it each time, currently.

Categories