jquery long polling: prevent update until data actually changes - ajax

I have created a script that long polls a JSON source and updates a div with the results. My code is posted below.
The code works fine and the data I request is grabbed and outputted correctly. The code checks the JSON and grabs 2 images and some text data.
The problem is it keeps refreshing the data and downloading the images constantly causing high server load and bandwidth consumption (obviously this is small right now but will increase as I complete my project). This also leads ot me not being able to select the text in the div and the images flicker as they are reloaded, both are undesirable consequences of my current code.
I want to be able to grab the data and display it, and not update it at all until the data actually changes in the JSON response, I am assuming I need to do something with a timestamp?. I have tried creating a lastupdate timestamp by using the first_aired key from the JSON but it is not working, I am unsure if I have made a mistake or if I am barking up the wrong tree.
Could someone take a look at the code I have and perhaps point me in the correct direction as to what I need to do?
var lastupdate = 0;
// call getData when the document has loaded
$(document).ready(function(){
getData(lastupdate);
});
var getData = function(lastupdate) {
$.ajax({
type: "GET",
url: 'http://api.trakt.tv/user/watching.json/apikey/user/lastupdate='+lastupdate+'&callback=?',
dataType: 'jsonp',
async: true,
cache: false,
// timeout after 5 minutes, shut process down and restart
timeout:300000,
// process a successful response
success: function(watching_now) {
if (!jQuery.isEmptyObject(watching_now)) {
//console.log(watching_now);
var airDate = watching_now.episode.first_aired;
var showTitle = watching_now.show.title;
var showPoster = watching_now.show.images.poster;
var showURL = watching_now.show.url;
var episodeTitle = watching_now.episode.title;
var episodeScreen = watching_now.episode.images.screen;
var episodeNumber = watching_now.episode.number;
var episodeSeason = watching_now.episode.season;
$('#watching-now').html('<div class="screencap"><img src="' + episodeScreen +' " width="240" height="150" /></div><div class="poster"><img src="' + showPoster +'" width="85" height="120" /></div><div class="watching-info">'+episodeSeason+'x'+episodeNumber+' - '+episodeTitle+'</div>')
}
else {
$('#watching-now').html('You are not currently watching anything')
}
// set lastupdate
lastupdate = watching_now.airDate;
// call again in 1 second
setTimeout('getData('+lastupdate+');', 1000);
},
// handle error
error: function(XMLHttpRequest, textStatus, errorThrown){
// try again in 10 seconds if there was a request error
setTimeout('getData('+lastupdate+');', 10000);
},
});
};
Here is the JSON I am getting the information form:
{"type":"episode","action":"watching","show":{"title":"Stargate Atlantis","year":2004,"url":"http://trakt.tv/show/stargate-atlantis","imdb_id":"tt0374455","tvdb_id":"70851","tvrage_id":"5324","first_aired":1089961200,"country":"United States","overview":"The story of Stargate Atlantis follows the cliffhanger episode on Stargate SG-1's seventh season finale \"Lost City\", where SG-1 found an outpost made by the race known as the Ancients in Antarctica. After the events of Stargate SG-1 season eight premiere \"New Order\", the Stargate Command sends an international team to investigate the outpost. Soon, Dr. Daniel Jackson discovers the location of the greatest city created by the Ancients, Atlantis. The story unfolds when the members of the expedition encounter the Wraith, the race that defeated the Ancients ten thousand years ago.","runtime":60,"network":"Syfy","air_day":"Monday","air_time":"9:00pm","certification":"TV-PG","images":{"poster":"http://trakt.us/images/posters/329.3.jpg","fanart":"http://trakt.us/images/fanart/329.3.jpg","banner":"http://trakt.us/images/banners/329.3.jpg"},"genres":["Action","Adventure","Science Fiction"]},"episode":{"season":3,"number":10,"title":"The Return (1)","overview":"The Atlantis expedition is stunned to learn that a ship full of Ancients is returning to reclaim their lost city. ","first_aired":1158908400,"url":"http://trakt.tv/show/stargate-atlantis/season/3/episode/10","images":{"screen":"http://trakt.us/images/episodes/329-3-10.3.jpg"}}}
If you need more information please just ask and I will provide everything I can.
Cheers

Take a look at example shown in link below.
http://www.zeitoun.net/articles/comet_and_php/start
what it does is pass time-stamp and get the record between current time-stamp and passed time-stamp.

Related

How to query cosm json feed using the cosm javascript library

I am new to web development and I have bit off more than I can chew.
So far, I successfully have created a website to query the latest data at cosm.com
Now I am trying to save the last 10 data points from the cosm.com feed to an array using the cosm javascript library. I can't get the right syntax and I can't find examples to guide me.
cosm.feed.history( 12068, duration:'30seconds', callback(data) );
console.log(data);
http://jsfiddle.net/spuder/29cFT/12/
http://cosm.github.com/cosm-js/docs/
UPDATE 2013-4-14
After implementing #bjpirt's solution, I noticed I wasn't getting 'every' value returned inside the specified duration.
Solved it by adding "interval:0" to the request.
cosm.datastream.history( cosmFeed1, cosmDataStream1, {duration:'60seconds', interval:0}, getHistory );
http://jsfiddle.net/spuder/ft2MJ/1/
#lebreeze is correct with his advice. I got your JSFiddle working so that it is now fetching data from the Cosm API:
http://jsfiddle.net/nLt33/2/
I had to make a few changes to get it working, any of which would have been causing you errors:
The feed ID and datastream ID were incorrect
You didn't have a callback function
The options weren't in a javascript object
Also, that feed doesn't seem to have been updated recently.
Here's the updated code which seems to be working fine now:
//read only key
cosm.setKey("-Ux_JTwgP-8pje981acMa5811-mSAKxpR3VRUHRFQ3RBUT0g");
var cosmFeed = 120687;
var cosmDataStream = "sensor_reading";
$(document).ready( function() {
var success = function(data){
for(var datapoint in data.datapoints){
var dp = data.datapoints[datapoint];
$('#stuff').append('<li>Value: ' + dp.value + ' At: ' + dp.at + '</li>');
}
}
//Print out the last 10 readings or so
cosm.datastream.history( cosmFeed, cosmDataStream, {duration:'1day'}, success );
})
It's difficult to get just the last x datapoints (that's something we should change in the API I think) - what you'd normally do is ask for a specific time period.
Hope this helps.
You may need to wrap your duration:'30seconds' json options in {}
Try something like:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="http://d23cj0cdvyoxg0.cloudfront.net/cosmjs-1.0.0.min.js"></script>
<script>..
cosm.setKey( "APIKEY" );
cosm.feed.history(40360, {duration:'30seconds'}, function(data){
console.log(data);
console.log(data.datastreams);
});
</script>

Website loses performance after some jQuery $.ajax calls

I admit I'm quite noob with full ajax websites, and so I'm surely making some mistakes.
The problem is this:
in http://lamovida.arabianessence.com
every page is loaded with an $.ajax call using this function
function getAjaxPage() {
$('a.ajaxc').click(function() {
$("li.page_block").find(".wrapper").fadeOut(400).remove();
hideSplash();
var $thishref = $(this).attr('href'),
$thisurl = $thishref.replace("#!/",""),
$urlArr = $thisurl.split('-'),
$urlOk = $urlArr[0],
$dataOk = $urlArr[1];
$.ajax({
url : $urlOk + ".php",
data : 'id='+$dataOk,
success : function (data,stato) {
$("#content").css({opacity:1}).fadeIn(400);
$("li.page_block").html(data);
$("li.page_block").css('visibility', 'visible');
$("li.page_block").find(".wrapper").css({opacity:0}).show().animate({opacity:1},1000);
var $whgt = $(".wrapper").height(),
$ctop = ( ( $(window).height() - $whgt ) /2 )-40;
$("#content").stop().animate({height: $whgt+40, top: $ctop},1000);
$("li.page_block").css('padding-top',20);
$('.scrollable').jScrollPane();
$('.slider>ul>li').jScrollPane();
getAjaxPage();
},
error : function (richiesta,stato,errori) {
alert(errori);
}
});
});
}
Every time this function is called the content gets loader slower, and after about 20 clicks things get real bad, and the loading time grows and grows.
I tried to analyze the situation using the Google Chrome's Timeline, and I saw that after each click the browser uses more memory. If I comment the getAjaxPage(); row in the "success" section the situation starts to get better, but of course I lose all the internal navigation.
What could I do to avoid this problem?
Many thanks to all!
Every call to $('a.ajaxc').click() is adding new event handler thus every click causes more requests to be made. After the first click, every click will cause two requests. Another click? Another three requests. Etc.
Put the handler outside the function and you will have only one AJAX call per click:
$(document).ready(function() {
$('a.ajaxc').click(getAjaxPage);
});
I also don't see the reason behind calling getAjaxPage again from within the callback, so remove it as well to avoid infinite loop of requests.

Handle ajax response with node.js

I am trying to scrape information from a specified website. This site uses authentication first, thus a i use zombie.js:
var Browser = require("zombie");
var browser = new Browser();
browser.visit("https://*****login.aspx", function(){
browser.fill('#user', '*****');
browser.fill('#pwd', '*****');
var button = browser.querySelector('#btnSubmit');
browser.fire('click', button, function(){
//scraping main.aspx
});
});
It's working, i can scrape the main.aspx: there is a <table>, containig information about new messages(from, date, subject,), the problems comes here: the subject field is clickable, and clicking on it makes a new window appear with the actual message. However it is an ajaxgrid, and when i perform a click:
var field = browser.querySelector('#VeryLongIdOfTheField');
browser.fire('click', field, function(){
console.log(browser.querySelector('#VeryLongIdOfTheFieldContainingTheMessage').innerHTML);
});
it returns an error message, saying that undefined has no innerHTML. I suppose its because this action handled with some ajax magic. I am new in this js/nodejs/jquery/.. world, some help needed to enlight me.
Since the data is populated using async ajax, I'm guessing there's a lag between your click and the actual DOM population inside the node. How about waiting for a bit before checking the content inside the node.
browser.fire('click', field, function(){
setTimeout(function(){
console.log(browser.querySelector('#VeryLongIdOfTheFieldContainingTheMessage').innerHTML);
}, 3000)
});
If the time taken is not very predictable, you could also run it inside a loop until you find the content or exit after a reasonable number of retries.

Ajax / JSON Redrawing google chart

Im using the google visualization chart api here: https://developers.google.com/chart/interactive to make a server uptime graph which seems to be working nicely.
However I want the users to be able to select a date range and then redraw the graph without having to refresh the browser. And I have a small problem with this.
I first draw the graph with the initial data, and then if a user changes the date range this graph should be redrawn. I tried redrawing with some sample data and this works fine. However I cant seem to get it to work with the updated data.
Now in the php file where i fetch the data from the DB i return both the average uptime for this period as well as the total uptime for the period as such:
/*mysql query striped*/
$uptime_result = mysql_query($query, $connection) or die(mysql_error());
$uptime_data = "['Day', 'Uptime'],";
while ($items = mysql_fetch_array($uptime_result)){
$uptime_data.="['{$items['date']}',{$items['uptime']}], ";
}
// get average uptime
/*mysql query striped*/
$uptime_result = mysql_query($query, $connection) or die(mysql_error());
$result_array = mysql_fetch_array($uptime_result);
$avg_uptime = round($result_array['AVG(uptime)'],2);
echo "{\"data\":\"{$uptime_data}\",\"average\":$avg_uptime}";
Which outputs something like:
{"data":"['Day', 'Uptime'],['2012-05-31',100.00], ['2012-06-01',100.00], ['2012-05- 22',99.65], ['2012-05-21',99.65], ['2012-05-20',100.00], ['2012-05-31',100.00], ['2012-05-30',100.00], ['2012-05-29',100.00], ['2012-05-28',100.00], ['2012-05-27',100.00], ['2012-05-26',100.00], ['2012-05-25',100.00], ['2012-05-24',100.00], ['2012-05-23',100.00], ['2012-05-19',100.00], ['2012-05-18',100.00], ['2012-05-17',100.00], ['2012-05-16',100.00], ['2012-05-15',100.00], ['2012-05-14',100.00], ['2012-05-13',100.00], ['2012-05-12',100.00], ['2012-05-11',100.00], ['2012-05-10',100.00], ['2012-05-09',100.00], ['2012-05-08',100.00], ['2012-05-07',100.00], ['2012-06-02',100.00], ['2012-06-03',100.00], ['2012-06-04',100.00], ","average":99.98}
I.e a JSON array with two variables data and average. I am able to fetch the two independently as such:
$(function(){
$('#from,#to').focusout(function(){
var start=$('#from').val();
var end=$('#to').val();
$.ajax({
type: 'POST',
data: ({from : start, to : end, id : <?php echo $id; ?>}),
url: 'fetchuptime.php',
success: function(data) {
//7 reulst goes here
//var json = data;
var obj = jQuery.parseJSON(data);
$('#uptime_span').html(obj.average +" %");
$('#test').html(data);
chart_data = google.visualization.arrayToDataTable([
obj.data
]);
var ac = new google.visualization.AreaChart(document.getElementById('visualization'));
ac.draw(chart_data, {
colors : ['#00DB00'],
title : '',
isStacked: false,
width: 570,
height: 400,
'chartArea': {'width': '88%', 'height': '90%'},
hAxis: {minValue: 0,showTextEvery: 6, slantedText: false},
vAxis: {
viewWindowMode:'explicit',
viewWindow:{
max:100,
min:90.65
}
},
pointSize: 3,
legend: {position: 'none'}
});
}
});
});
});
eg. obj.average and obj.data gives me the two string. However this does not seem to work, i guess the data doesn't get passed along correctly.
I have tested the actual output data (eg obj.data) is formatted correct as I've tried inserting it statically.
So I'm obviously doing something wrong here, and I assume it's because I'm passing an string while google chart needs an array, tried to fix it in various ways but haven't found anything working yet.
Can anyone help me with this one?
The format of your JSON is valid, but probably not what you're wanting:
{"data":"['Day', 'Uptime'],['2012-05-31',100.00] ... ['2012-06-04',100.00], ", "average":99.98}
That represents an object with a field named data whose value is a string (like you said). What you probably want to do is make it an array on the server side. Instead of double quotes, use square brackets. There is also a trailing comma which must be removed.
{"data":[['Day', 'Uptime'],['2012-05-31',100.00] ... ['2012-06-04',100.00]], "average":99.98}

Assign jQuery.get() to a variable?

What is the correct way of assigning to a variable the response from jQuery.get() ?
var data = jQuery.get("output.csv");
I was reading that jQuery.get() must have a callback function? why is that? and how would i use this callback function to assign the response back to the data variable?
Thanks in advance for your help and clarification.
Update:
Thank you all for your answers and explanations. I think i am starting to finally grasp what you are all saying.
My code below is doing the right thing only the first iteration of it.
The rest of the iterations its writing to the page undefined.
Am i missing something?
<tbody>
<table id="myTable">
<script type="text/javascript">
$.get('output.csv', function(data) {
csvFile = jQuery.csv()(data);
for ( var x = 0; x < csvFile.length; x++ ) {
str = "<tr>";
for ( var y = 0; y < csvFile.length; y++) {
str += "<td>" + csvFile[y][y] + "</td>";
}
str += "</tr>";
}
$('#myTable').append(str);
});
</script>
</tbody>
</table>
A callback function is required for asynchronous function calls, like an AJAX GET request. There is a delay between calling the get function and getting a response back, which could be a millisecond or several minutes, so you need to have a callback function that gets called when the asynchronous GET has completed its work.
Here's some more info on jQuery's AJAX get function: http://docs.jquery.com/Ajax/jQuery.get#urldatacallbacktype.
From jQuery's examples:
// this would call the get function and just
// move on, doing nothing with the results
$.get("test.php");
// this would return the results of the get
$.get("test.php", function(data){
alert("Data Loaded: " + data);
});
If you get undefined when you try to use the data variable in the callback function, open up the console in Firebug in Firefox and watch the get request. You can see the raw request and the response that it comes back with. You should get a better indication of the issue after seeing what's being sent to the server and what's being sent back to the client.
tsvanharen answered the question well, but DCrawmer's still missing the point. Let me attempt a clarification for him. I'm oversimplifying some of this, and smoothing over some details.
Look at the code shown below. This is pretty much the same code as tsvanharen's, except that I've replaced the anonymous function for the callback with an actual function pointer, and am a little more explicit so you can see what's going on:
var x = null;
function myCallback(data)
{
alert("Data Loaded:" + data);
}
$.get("test.php", myCallback);
// the rest of your code
alert("The value of X is: " + x);
Assuming that test.php takes even a moment or two to load, notice the order that the alerts probably come up in:
1. "The value of X is"
2. "Data Loaded"
The function $.get() runs instantaneously. JavaScript moves on and runs the rest of your code right away. In the background, it's retrieving your page at test.php. jQuery hides some of the messy details of this.
The callback function (the second argument to $.get()) runs later (asynchronously). Or, said another way, the function myCallback is a handler to an event. That event is "$.get() has finished retrieving the data". It doesn't get run until that point. It doesn't run when $.get() runs! $.get() just remembers where that function is for later.
The function myCallback may run milliseconds or minutes later, long after $.get() has been dealt with.
If myCallback doesn't run until minutes later, then what's the value of x when the "The value of X" code is run? It's still null. There's your bug.
To use the data retrieved from the page in your script, you have to do things more like this:
Start your script, declare your variable to hold the data.
Call $.get(), with a callback function to handle the return.
Do nothing else. [Or, at least, nothing that requires the data]
Let the page just sit there.
...sometime in the future...
X. Your callback function will get run, and have the results of your web page.
Your callback function can:
* Display the data
* Assign that data to a variable
* Call other functions
* Go along it's merry way.
Actually in your example the data will be the XMLHttpRequest request object.
var x;
$.get( 'output.csv', function(data){
x = data;
console.log(x); // will give you the contents.
});
I really struggled with getting the results of jQuery ajax into my variables at the "document.ready" stage of events.
jQuery's ajax would load into my variables when a user triggered an "onchange" event of a select box after the page had already loaded, but the data would not feed the variables when the page first loaded.
I tried many, many, many different methods, but in the end, the answer I needed was at this stackoverflow page: JQuery - Storing ajax response into global variable
Thanks to contributor Charles Guilbert, I am able to get data into my variables, even when my page first loads.
Here's an example of the working script:
jQuery.extend
(
{
getValues: function(url)
{
var result = null;
$.ajax(
{
url: url,
type: 'get',
dataType: 'html',
async: false,
cache: false,
success: function(data)
{
result = data;
}
});
return result;
}
}
);
// Option List 1, when "Cats" is selected elsewhere
optList1_Cats += $.getValues("/MyData.aspx?iListNum=1&sVal=cats");
// Option List 1, when "Dogs" is selected elsewhere
optList1_Dogs += $.getValues("/MyData.aspx?iListNum=1&sVal=dogs");
// Option List 2, when "Cats" is selected elsewhere
optList2_Cats += $.getValues("/MyData.aspx?iListNum=2&sVal=cats");
// Option List 2, when "Dogs" is selected elsewhere
optList2_Dogs += $.getValues("/MyData.aspx?iListNum=2&sVal=dogs");
You just need to specify the callback function in the parameter to get method. Your data will be in the variable you specify in the function.
$.get("output.csv", function(data) {
// Put your function code here, the 'data' variable will hold your data.
});

Resources