Live Data Feed and Scrollbar Position - javascript

I am retrieving data from a MySQL database and displaying it on a website using the EventSource API. So far everything is working as expected, but I want to display the data in a fixed height div, and fix the scrollbar to the bottom of this div - i.e always show the latest feed results first.
Now when I load the page the scrollbar is fixed to the top.
I have tried the suggestion here but it doesn't seem work. Is it because I am working with live data and AJAX requests in order to populate the div?
My cose so far is;
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.js"></script>
<style type="text/css">
#result {
overflow: auto;
max-height:224px;
width: 500px;
}
</style>
<script type="text/javascript">
// scrollbar to bottom
$("document").ready(function(){
var objDiv = document.getElementById("result");
objDiv.scrollTop = objDiv.scrollHeight;
});
// retrieve data from server and display in div
$("document").ready(function(){
var source = new EventSource("data.php");
var offline;
$.ajax({
type: "POST",
url: 'data.php',
data: {lastSerial: true},
dataType: 'json',
success: function(data){
$.each(data, function(key, value) {
document.getElementById("result").innerHTML += "New transaction: " + value.SerialNo + ' ' + value.TimeStamp + "<br>";
});
} // end success
});
});//end dom ready
</script>
</head>
<body>
<div id="result"><!--Server response inserted here--></div>
</body>
</html>
The strange this is, whenever I remove the live feed javascript and manually add some (lorem ipsum) text into the <div id="result"> it works, the scrollbar appears at the bottom of the div.
I could be doing something very silly :)
Any advice is appreciated.

When you load more data via ajax, the size of the content will change. Have you tried setting the scroll again after you've rendered the content? i.e.:
success: function(data){
var objDiv = document.getElementById("result");
$.each(data, function(key, value) {
objDiv.innerHTML += "New transaction: " + value.SerialNo + ' ' + value.TimeStamp + "<br>";
});
objDiv.scrollTop = objDiv.scrollHeight;
} // end success
});
Thus setting the scroll value the same way you do when the page loads.
Alternatively, here's another completely different option:
If you want the most recent values to be most prominent, you could simply output them in reverse order, so the newest ones are at the top of the div, where the user will see them first. You can use jQuery's .prepend() method to add content to the beginning of the div, above the previous results. Then there's no need for messing about with scrolling. http://api.jquery.com/prepend/ I'd argue this is more user-friendly, but it's up to you obviously.

I'm not 100% sure about this but one issue that I see is that you're making an asynchronous AJAX call to the server after you scroll to the bottom of the div.
Maybe try something along the lines of this:
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.js"></script>
<style type="text/css">
#result {
overflow: auto;
max-height:224px;
width: 500px;
}
</style>
<script type="text/javascript">
// retrieve data from server and display in div
$("document").ready(function(){
var source = new EventSource("data.php");
var offline;
$.ajax({
type: "POST",
url: 'data.php',
data: {lastSerial: true},
dataType: 'json',
success: function(data){
$.each(data, function(key, value) {
document.getElementById("result").innerHTML += "New transaction: " + value.SerialNo + ' ' + value.TimeStamp + "<br>";
});
var objDiv = document.getElementById("result");
objDiv.scrollTop = objDiv.scrollHeight;
} // end success
});
});//end dom ready
</script>
</head>
<body>
<div id="result"><!--Server response inserted here--></div>
</body>
</html>
Explanation: The div gets populated after you scroll to the bottom of it. Therefore when the scrolling is executed the scrollHeight property is still at the original height value of the div. Now, if you execute the scroll action after you populate the div, it should work fine.

var objDiv = document.getElementById("result");
objDiv.scrollTop = objDiv.scrollHeight;
that code doesn't say "anchor" the scrollbar to the bottom, it just says scroll down the actual height of the div once, but since you put this code before your ajax request, your div must be empty, so just put theese two lines at the end of your ajax "success" function.
success: function(data){
$.each(data, function(key, value) {
document.getElementById("result").innerHTML += "New transaction: " + value.SerialNo + ' ' + value.TimeStamp + "<br>";
});
var objDiv = document.getElementById("result");
objDiv.scrollTop = objDiv.scrollHeight;
}

It was just small line which you were missing, please add below code
$.ajax({
type: "POST",
url: 'data.php',
data: {lastSerial: true},
dataType: 'json',
success: function(data){
var objDiv = document.getElementById("result");
$.each(data, function(key, value) {
objDiv.innerHTML += "New transaction: " + value.SerialNo + ' ' + value.TimeStamp + "<br>";
});
objDiv.scrollTop = objDiv.scrollHeight;
} // end success
});

Related

How to display API data using Ajax?

I want to be able to use the API from the code below to display data in a formatted way such as this example.
Job Title: Agricultural and Related Trades
Percentage of Occupancies in Area: 15.41%
You can find my poor attempt to display the data below. I am very new to Ajax, jQuery, JavaScript, etc.
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script>
$(function() {
$.ajax({
url: "http://api.lmiforall.org.uk/api/v1/census/jobs_breakdown?area=55.9895989531941,-3.796229726988194",
type: "get",
dataType: "json",
success: function(data) {
console.log(data[0].area);
outputString= data[0].description.percentage;
var paragraph = $("<p />", {
text: outputString
});
$("body").append(paragraph);
}
});
});
</script>
After successfully execute your GET request you will get your response at data variable now you can run a for loop to populate your expected outcome 'HTML' TEXT
than you can append it on your HTML body
I have used here JavaScript toFixed() Method keeping only two decimals
$(function() {
$.ajax({
url: "http://api.lmiforall.org.uk/api/v1/census/jobs_breakdown?area=55.9895989531941,-3.796229726988194",
method: "GET",
dataType: "json",
success: function(data) {
var str = "";
for(var i= 0; i < data.jobsBreakdown.length; i++){
str +='Job Title : '+data.jobsBreakdown[i].description+' and Related Trades <br> Percentage of Occupancies in Area : '+data.jobsBreakdown[i].percentage.toPrecision(2)+'% <br><br>';
}
$("body").html(str);
}
});
});
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
</head>
<body>
<h1>This is a Heading</h1>
<p>This is a paragraph.</p>
</body>
</html>
Something like this is likely what you want:
<script>
$(function() {
$.ajax({
url: "http://api.lmiforall.org.uk/api/v1/census/jobs_breakdown?area=55.9895989531941,-3.796229726988194",
type: "get",
dataType: "json",
success: function(data) {
data.jobsBreakdown.forEach(function(job) {
var job_text = "Job Title: " + job.description;
var percentage_text = "Percentage of Occupancies in Area: " + job.percentage.toFixed(2) + "%"
$("body").append("<div style='margin-bottom: 10px;'><div>" + job_text + "</div><div>" + percentage_text + "</div></div>")
})
}
});
});
</script>
You can use string templates to create your paragraph content.
Use the <br /> HTML element to make a new line in the paraghraph.
let data = [{
area: 'Agricultural and Related Trades',
percentage: 15.41
}]
var paragraph = document.createElement('p');
paragraph.innerHTML = `Job Title: ${data[0].area}<br/>
Percentage of Occupancies in Area: ${data[0].percentage}%"`;
document.body.appendChild(paragraph);
You need to define a function to render a single item of description and percentage.
For parsing the percentage, you can use Number object
When you get the data back from Ajax, you need to loop on the items and pass each one of them to your render function you defined earlier (here I used forEach).
Generally, as rule of thumb, you have to split your code into functions each with single responsibility.
function renderItem(itemData) {
const title = $('<p/>').text('Job Title: ' + itemData.description);
const percentage = $('<p/>').text('Percentage of Occupancies in Area: '+ new Number(itemData.percentage).toFixed(2) + '%');
const item = $('<li/>').append(title, percentage);
$('#result').append(item);
}
$(function() {
$.ajax({
url: "http://api.lmiforall.org.uk/api/v1/census/jobs_breakdown?area=55.9895989531941,-3.796229726988194",
type: "get",
dataType: "json",
success: function(data) {
data.jobsBreakdown.forEach(renderItem);
}
});
});
Job Title: Agricultural and Related Trades
Percentage of Occupancies in Area: 15.41%
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="result"></ul>

Json table update after certain date

At the moment i have this code
// JavaScript Document
$.ajax({
type: 'GET',
crossDomain: true,
dataType: 'json',
url: 'https://api.import.io/store/data/93296dfc-1edb-4aa6-a3e5-2207fa52f3ea/_query?input/webpage/url=http%3A%2F%2Fwww.seatwave.com%2Fthe-script-tickets%2Fseason&_user=687c839c-f236-4817-90c9-f6eb81334c2a&_apikey=pvXHYMTbZD3Za3TB%2Bn8LgVybPltV1a379yBNfSfzepw2piIhs%2FxHinVseH7G4BwItVQ57aNJnyk6g6g%2BAxyEMg%3D%3D',
success: function (json) {
//var json = $.parseJSON(data);
for(var i =0;i < json.results.length;i++) {
var title = json.results[i].name;
var venue = json.results[i].venue;
var date = json.results[i].date;
var button = "<button class='btn btn-info' data-url='"+(i+1)+".html'>Compare</button>";
$("#apple").append("<tbody><tr><td>"+title+"</td><td>"+venue+"</td><td>"+date+"</td><td>"+button+"</td></tr></tbody>");
$("#apple").find(".btn.btn-info").click(function(){
location.href = $(this).attr("data-url");
});
}
},
error: function(error){
console.log(error);
}
});
This appends the URL to a table. However as you can see this code here data-url='"+(i+1)+".html' created the button with an increment of 1 on the amount of buttons listed.
The issue is, this api is updating every 5 hours. When the event passes, The buttons need to really be updated. Otherwise the whole site breaks.
So the question is how could i go around making the links unique and update when an event passes? whilst im writing this i believe i could just use the Date function, So the code would be
data-url='"+date+".html'
Any other suggestions would be great?
There are many ways you could do this. The easiest would be to add a meta tag to the page that forces it to refresh each 5 hours. If for some reason you need to do it with code, then you'll need to add a timer that checks for updates and refreshes the button data. A working example of that is shown below. The data does have a time stamp, but it's set to the far future. So rather than check that the code simply updates each 10 seconds (you can set to whatever frequency you need).
<html>
<body>
<style type="text/css">
table { border-collapse: collapse; font-family: sans-serif; font-size: 12px;}
table td { border: 1px gray dotted; padding: 2px;background-color:aliceblue;}
table caption {font-weight: bold; color: firebrick;}
</style>
<table id="apple"><caption></caption><tbody></tbody></table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script type="text/javascript">
var lastUpdate;
function update() {
$.ajax({
type: 'GET',
crossDomain: true,
dataType: 'json',
url: 'https://api.import.io/store/data/93296dfc-1edb-4aa6-a3e5-2207fa52f3ea/_query?input/webpage/url=http%3A%2F%2Fwww.seatwave.com%2Fthe-script-tickets%2Fseason&_user=687c839c-f236-4817-90c9-f6eb81334c2a&_apikey=pvXHYMTbZD3Za3TB%2Bn8LgVybPltV1a379yBNfSfzepw2piIhs%2FxHinVseH7G4BwItVQ57aNJnyk6g6g%2BAxyEMg%3D%3D',
success: function (json) {
/*
Removed - data time stamp does not appear to be useful
if (json.results[0].date == lastUpdate) return;
lastUpdate = json.results[0].date;
$("#apple caption").html( 'Last Updated: ' + lastUpdate );
*/
$("#apple caption").html( "Last Updated: " + (new Date()).toString() );
$("#apple tbody").html( "" );
for(var i =0;i < json.results.length;i++) {
var title = json.results[i].name;
var venue = json.results[i].venue;
var date = json.results[i].date;
var button = "<button class='btn btn-info' data-url='"+(i+1)+".html'>Compare</button>";
$("#apple tbody").append("<tr><td>"+title+"</td><td>"+venue+"</td><td>"+date+"</td><td>"+button+"</td></tr>");
$("#apple").find(".btn.btn-info").click(function(){
location.href = $(this).attr("data-url");
});
}
},
error: function(error){
console.log(error);
}
});
}
update();
var timerId = setInterval( update, 10000 );
</script>
</body>
</html>

jQuery animated message after form submit

I have a form and after user is successfully filled the form I want the actual message
to "bounce" from the top about 30px and show the actual message. The problem is that my
form's height is huge, about 900px so I'll never see the actual message unless I scroll on top of my page which is impossible because the page reloads itself after 3 seconds. How should I implement this? Here's my AJAX code for now:
<script type="text/javascript">
$(document).ready(function() {
// Process the form with AJAX
$("form").on('submit', function(e)
{
e.preventDefault();
var from = $("form");
$.ajax({
url: from.attr('action'),
type: from.attr('method'),
data: $(from).serialize(),
}).done(function(data) {
if(data.result == 0) {
$("#new_survey_success").hide();
for (var key in data.error) {
var value = data.error[key];
var output = '<p>' + value + '</p>';
}
$("#new_survey_error").fadeIn(1000).show().html(output);
}
if(data.result == 1) {
$("#new_survey_error").hide();
$("#new_survey_success").fadeIn(200).show().html("<p>" + data.success + "</p>");
window.setTimeout(function(){location.reload()},3000)
}
}, 'json');
return false;
});
});
</script>
Thanks in advance!

How can I set loading image during post data jquery ajax and change alert msg to div error?

I want to show a div if the comment field is empty out instead of showing an alert. How can I do this? My other question is, the data is displayed after some seconds. During that loading period is possible to to add a loading image?
<script type="text/javascript">
$(function () {
// on post comment click
$('.bt-add-com').click(function () {
var theCom = $('.the-new-com');
var theName = $('#name-com');
var theMail = $('#mail-com');
if (!theCom.val()) {
alert('You need to write a comment!');
} else {
$.ajax({
type: "POST",
url: "ajax/add-comment.php",
data: 'act=add-com&id_post=' + <? php echo $id_post; ?> +'&name=' + theName.val() + '&email=' + theMail.val() + '&comment=' + theCom.val(),
success: function (html) {
theCom.val('');
theMail.val('');
theName.val('');
$('.new-com-cnt').hide('fast', function () {
$('.new-com-bt').show('fast');
$('.new-com-bt').after(html);
})
}
});
}
});
});
</script>

How to dynamically generate collapsible-set in jQuery?

I retrieve from a php file some headline datas (main headlines, each of them has sub headlines).
The data I receive works fine, but when I want to generate a collapsible-set in jquery (mobile), it doesn't show the beautiful theme... just plain text?!
Here's my HTML file:
<div data-role="collapsible-set" data-content-theme="d" id="headlinegroup">
And here's my javascript file:
$.ajax({
type: "POST",
url: "headline_getter.php",
dataType: 'json',
cache: false,
success: function(data1){
console.log ("debug 2");
var i = 0;
var $elements = '';
$.each(data1[i].main, function() {
console.log ("debug 3 ");
$elements += ($('div[data-role=collapsible-set]#headlinegroup').append('<div data-role="collapsible"><h3>' + data1[i].main + '</h3><div data-role="fieldcontain"><fieldset data-role="controlgroup" id="headlinegroup'+[i]+'">'));
var j = 0;
$.each(data1[i].sub, function() {
console.log ("debug 4");
$elements += ('<label><input type="checkbox" name="headlines[]" data-mini="true" value="' + data1[i].mid[j] + '"/>' + data1[i].sub[j] + '</label>');
j++;
});
$elements += ('</fieldset></div></div>');
$elements.collapsible();
i++;
});
}
});
I don't really know where the problem is. I've read some thread here at stackoverflow and added the .collapsible attribut but it don't work... theres just plain text.
Thanks in advance. Best regards, john.
have you tried to add .trigger('create') at the end of every element you append?

Categories

Resources