Detect scroll to bottom of div and load new posts - javascript

I am using this method to detect the end of two div columns and load new posts. It is working. But the problem is, first it loads five posts by default function, then when user scroll down it loads the next five posts(2nd phase) at least 10 times. than when you scroll more down, it loads next 5 posts(3rd phase) again at least 10 times. Otherwise the function is good.
<script>
$(window).scroll(function() {
if($(window).scrollTop() >= $('.div1').height() - $(window).height()) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
$('#loadmoreinstagram').remove();
document.getElementById("instagramresponse").innerHTML = document.getElementById("instagramresponse").innerHTML+this.responseText;
}
};
xmlhttp.open("GET", "<?php echo $settings['URL']; ?>getdata.php?type=" + $('#type').last().val() + "&page=" + $('#page').last().val() + "&lasttime=" + $('#lasttime').last().val(), true);
xmlhttp.send();
}
if($(window).scrollTop() >= $('.div2').height() - $(window).height()) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
$('#loadmoretwitter').remove();
document.getElementById("twitterresponse").innerHTML = document.getElementById("twitterresponse").innerHTML+this.responseText;
}
};
xmlhttp.open("GET", "<?php echo $settings['URL']; ?>getdata.php?type=" + $('#typetwitter').last().val() + "&page=" + $('#pagetwitter').last().val() + "&lasttime=" + $('#lasttimetwitter').last().val(), true);
xmlhttp.send();
}
});
</script>

Your problem is that the window.scroll event fires many times for one "scroll". you can see this by simply logging the events by pasting the following into your console.
$(window).scroll(function() {console.log('scroll')})
To fix this, you need to block your request from firing many times in a row in a short period of time. This is called debouncing. Underscorejs has a great builtin function for it, but a quick google will yield lots of resources for writing your own. Code below using the underscorejs function solves your problem.
var debouncedFn = _.debounce(function() { console.log('scroll')}, 100)
$(window).scroll(debouncedFn)
Learning about debounce https://davidwalsh.name/javascript-debounce-function
for your application:
</script>
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
function handleScroll() {
if($(window).scrollTop() >= $('.div1').height() - $(window).height()) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
$('#loadmoreinstagram').remove();
document.getElementById("instagramresponse").innerHTML = document.getElementById("instagramresponse").innerHTML+this.responseText;
}
};
xmlhttp.open("GET", "<?php echo $settings['URL']; ?>getdata.php?type=" + $('#type').last().val() + "&page=" + $('#page').last().val() + "&lasttime=" + $('#lasttime').last().val(), true);
xmlhttp.send();
}
if($(window).scrollTop() >= $('.div2').height() - $(window).height()) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
$('#loadmoretwitter').remove();
document.getElementById("twitterresponse").innerHTML = document.getElementById("twitterresponse").innerHTML+this.responseText;
}
};
xmlhttp.open("GET", "<?php echo $settings['URL']; ?>getdata.php?type=" + $('#typetwitter').last().val() + "&page=" + $('#pagetwitter').last().val() + "&lasttime=" + $('#lasttimetwitter').last().val(), true);
xmlhttp.send();
}
}
var debouncedScroll = debounce(handleScroll, 100)
$(window).scroll(debouncedScroll);
</script>

Typically, if you're using jquery, you do something like this:
$.get(url).done( result => {
// do stuff when ajax is done
})
but this setup you have here seems to rely solely on the users' scrolling action to activate the stuff to do in done. So I'm not sure what to tell you other than send it back to the developer (according to a comment you made elsewhere).
A regular implementation of jquery would be something like:
<script>
var working = false;
$(window).scroll(function() {
if($(window).scrollTop() >= $('.div1').height() - $(window).height() && !working) {
working = true;
$.get( url ).done( result => {
$('#loadmoreinstagram').remove();
$("#loadmoreinstagram").html = $("#loadmoreinstagram").html + result.responseText;
working = false;
} )
}
if($(window).scrollTop() >= $('.div2').height() - $(window).height() && !working) {
working = true;
$.get( url ).done( result => {
$('#loadmoretwitter').remove();
$("#loadmoretwitter").html = $("#loadmoretwitter").html + result.responseText;
working = false;
} )
}
});
</script>
You can see the differences, that your dev isn't using jquery to make the hard stuff easy.

Related

Javascript check if a class name has been added to DIV and perform task

I have the following functions:
<div class="chat-box"></div>
setInterval(() => {
let xhr = new XMLHttpRequest();
xhr.open("POST", "processes/get-chat.php", true);
xhr.onload = ()=> {
if(xhr.readyState === XMLHttpRequest.DONE) {
if(xhr.status === 200) {
let data = xhr.response;
chatBox.innerHTML = data;
// if(!chatBox.classList.contains("active")) {}
}
}
}
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send("incoming_id=" + incoming_id);
}, 500);
if(chatBox.classList.contains("active")) {
$('html,body').animate({scrollTop: document.body.scrollHeight},"fast");
}
I want to check if the chatbox div has the class name active and move to the bottom of the div automatically. The active class is being added from the setInterval function. However, I cannot the if condition inside the setInterval function because it will then be executed ever n amount of time and then I won't be able to scroll up and read the contents. It will take me to the bottom every n seconds. Therefore, I want the scroll to bottom to be executed only once. For this, I have placed it outside of setInterval function. But, this does not seem to be working. What can be the issue here? How can I make this work? Any help would be appreciated. Thanks :)
This kind of things can easily be done by adding additional logic and counter.
You define outside variable let count = 0;
Then inside the interval you add +1 every time. And then add this to your if to react only once, when count is 1.
++count
if (chatBox.classList.contains("active") && count === 1) {
< div class = "chat-box" > < /div>
let count = 0;
setInterval(() => {
let xhr = new XMLHttpRequest();
xhr.open("POST", "processes/get-chat.php", true);
xhr.onload = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
let data = xhr.response;
chatBox.innerHTML = data;
++count
if (chatBox.classList.contains("active") && count === 1) {
$('html,body').animate({
scrollTop: document.body.scrollHeight
}, "fast");
}
}
}
}
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send("incoming_id=" + incoming_id);
}, 500);
OR true false logic, you get the picture:
< div class = "chat-box" > < /div>
let count = true;
setInterval(() => {
let xhr = new XMLHttpRequest();
xhr.open("POST", "processes/get-chat.php", true);
xhr.onload = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
let data = xhr.response;
chatBox.innerHTML = data;
if (chatBox.classList.contains("active") && count === true) {
count = false;
$('html,body').animate({
scrollTop: document.body.scrollHeight
}, "fast");
}
}
}
}
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send("incoming_id=" + incoming_id);
}, 500);

Javascript (Vanilla) Execution Order inside Function with DOM update and AJAX call

I've a piece of JavaScript that gets called when a button is clicked.
The function manipulates some DOM (makes the page opaque, reveals an animation) and then loops through AJAX calls to 'script.php' many times. When that's over it reloads the page, fresh.
My issues is that on Chrome and IE, for the life of me, I can't get the DOM modifications to happen before the AJAX runs and completes. It works fine on Firefox.
I've tried calling sequentially in the code. Nesting each part in a function and in a third, calling each in order.
I've tried to use a promise. Everytime, the AJAX runs and completes, the screen flickers with the DOM mods just before the page reloads.
How is this usually managed?
The problem in a nutshell.
What are some ways I can force Chrome (and Edge) to update the DOM first and then run the AJAX rather than the other way around.
My code is here:
function Backup(OrgRowIDs) {
document.getElementById('Overlay').style.visibility="visible";
document.getElementById('Overlay').style.display="block";
document.getElementById('ActionWindow').style.visibility="visible";
document.getElementById('ActionWindow').style.display="inline";
function GenerateBackupID () {
var Characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
var ID = '';
for (var i = 1; i <= 12; i++) {
var pos = Math.floor((Math.random() * 60) + 1)
ID = ID + Characters.substring(pos, pos + 1);
}
return ID;
}
function RecordBackupSessionID() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
return;
}
}
xhttp.open("GET", "../AJAX/RecordBackupID?backupfile=" + OrgRowIDs[i] + "&backupid=" + BID , false);
xhttp.send();
}
for (i = 0; i < OrgRowIDs.length; i++){
BID = GenerateBackupID();
RecordBackupSessionID();
function BackupFiles(i) {
for (j = 0; j < 20; j++) {
function BackupEndPoints(j) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
//do something if we want.
}
}
xhttp.open("GET", "../AJAX/BackupFiles?backupfile=" + OrgRowIDs[i] + "&endpoint=" + j + "&backupid=" + BID , false);
xhttp.send();
}
BackupEndPoints(j)
}
}
BackupFiles(i)
}
location.reload();
}

Update DOM object in time intervals using JavaScript Worker

I'm trying to do some DOM objects updates in background.
What I mean is update tab title, and some elements regardless if user has tab active or not ( to show that there are new notifications )
I already found out, that Worker has to be used as it runs in background ( but don't have access to DOM). Tried as follows:
Main HTML:
...some html
<script>
$(document).ready(function ($) {
if (window.Worker) {
console.log('[DEBUG] Worker is supported')
var eventsWorker = new Worker("<c:url value="/resources/js/eventTimer.js" />");
setInterval(eventsWorker.postMessage([appUrl]), 20 * 1000);
//setEventsNonWorker()
eventsWorker.onmessage = function (e) {
console.log('Message received from worker' + e.data);
setEventsCount(e.data, appName, eventsTxt);
}
} else {
console.log('[DEBUG] Worker is NOT supported')
setEventsNonWorker()
}
});
function setEventsNonWorker(){
//regular update with setTimout and stuff
}
worker javascript file
function setEventsCount(count, appName, eventsTxt) {
var bell, text, countPar;
if (count > 0) {
bell = '<i class="fa fa-bell"></i> ';
countPar = '(' + count + ') ';
text = bell + eventsTxt + countPar;
$(".event-menu-li").html(text);
$("#event-menu-icon").html(bell + count)
document.title = countPar + appName;
} else {
bell = '<i class="fa fa-bell-o"></i> ';
text = bell + eventsTxt;
$(".event-menu-li").html(text);
$("#event-menu-icon").html(bell)
document.title = appName;
}
}
onmessage = function (e) {
var appUrl = e.data[0];
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === XMLHttpRequest.DONE && xmlhttp.status === 200) {
postMessage(xmlhttp.responseText);
}
};
xmlhttp.open("GET", appUrl, true);
xmlhttp.send();
}
The first call is working ( the event count is properly set ) but there are no more calls in 20 sec
Ok it turns out I was putting timeout in wrong place
html should be
//...
eventsWorker.postMessage([appUrl]);
eventsWorker.onmessage = function (e) {
console.log('Message received from worker' + e.data);
setEventsCount(e.data, appName, eventsTxt);
//...
which will just init worker , while worker.js should have the timeout
//...
onmessage = function (e) {
var appUrl = e.data[0];
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === XMLHttpRequest.DONE && xmlhttp.status === 200) {
postMessage(xmlhttp.responseText);
}
};
xmlhttp.open("GET", appUrl, true);
xmlhttp.send();
setInterval(function () {
xmlhttp.open("GET", appUrl, true);
xmlhttp.send();
}, 20*1000);
}

set time out in ajax call while using core javascript

I have a JavaScript function to call ajax. Now I need to add time out in this function like while calling service took more than defile time ajax call should time out and display a default message. I don't want to use Jquery in it.
here is my code:
AJAX = function (url, callback, params) {
var dt = new Date();
url = (url.indexOf('?') == -1) ? url + '?_' + dt.getTime() : url + '&_' + dt.getTime();
if (url.indexOf('callback=') == -1) {
ajaxCallBack(url, function () {
if (this.readyState == 4 && this.status == 200) {
if (callback) {
if (params) {
callback(this.responseText, params);
} else {
callback(this.responseText);
}
}
}
});
} else {
var NewScript = d.createElement("script");
NewScript.type = "text/javascript";
NewScript.src = url + '&_' + Math.random();
d.getElementsByTagName('head')[0].appendChild(NewScript);
}
},
ajaxCallBack = function (url, callback) {
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = callback;
xmlhttp.open("GET", url, true);
xmlhttp.send();
}
Here's an example of how you can handle a timeout:
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", "http://www.example.com", true);
xmlHttp.onreadystatechange=function(){
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
clearTimeout(xmlHttpTimeout);
alert(xmlHttp.responseText);
}
}
// Now that we're ready to handle the response, we can make the request
xmlHttp.send("");
// Timeout to abort in 5 seconds
var xmlHttpTimeout=setTimeout(ajaxTimeout,5000);
function ajaxTimeout(){
xmlHttp.abort();
alert("Request timed out");
}
In IE8, You can add a timeout event handler to the XMLHttpRequest object.
var xmlHttp = new XMLHttpRequest();
xmlHttp.ontimeout = function(){
alert("request timed out");
}
Use a javascript framework to do this though, i don't know why you're not using one, do you like uneccesary work? :)
If you want to simply add timeout, You can add it in the first function in three places:
setTimeout(function() {callback(this.responseText, params)}, 1000)
And your callback will execute around 1s later. The second palce is second call of callback.
Third place that i would suggest is to wrap this function like above:
ajaxCallBack(url, function () {
if (this.readyState == 4 && this.status == 200) {
if (callback) {
if (params) {
callback(this.responseText, params);
} else {
callback(this.responseText);
}
}
}
});
Usually when i get in to testing internet connection i rather add throttling in the chrome developer tools like this:
Here is your code with first approach:
AJAX = function (url, callback, params) {
var dt = new Date();
url = (url.indexOf('?') == -1) ? url + '?_' + dt.getTime() : url + '&_' + dt.getTime();
if (url.indexOf('callback=') == -1) {
ajaxCallBack(url, function () {
if (this.readyState == 4 && this.status == 200) {
if (callback) {
if (params) {
console.log(new Date());
setTimeout(function() {callback(this.responseText, params)}, 2000);
} else {
console.error((new Date()).getSeconds());
setTimeout(function() {callback(this.responseText)}, 2000);
}
}
}
});
} else {
var NewScript = d.createElement("script");
NewScript.type = "text/javascript";
NewScript.src = url + '&_' + Math.random();
d.getElementsByTagName('head')[0].appendChild(NewScript);
}
},
ajaxCallBack = function (url, callback) {
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = callback;
xmlhttp.open("GET", url, true);
xmlhttp.send();
}
AJAX('http://ip.jsontest.com/', function() {console.error((new Date()).getSeconds()); });
Maybe the answer to this question will help.
Timeout XMLHttpRequest
since from what i understand you need to set timeout for xmlhttprequest,
you can use xmlhttp.timeout = /*some number*/

Browser freeze when calling an ajax post / get methods

I have two ajax functions which freeze the window whenever they are called.
Is there a way to prevent such behaviour ? (Pure javascript).
Here's the two functions:
function fetch_json_data(a)
{
if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest() }
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
var json_response = JSON.parse(xmlhttp.responseText);
for (var key in json_response)
{
if(json_response[key] != null && json_response[key].length > 0)
{
var e = document.getElementById(key+".div");
e.innerHTML = "<pre>"+json_response[key]+"</pre>";
var e = document.getElementById(key);
e.setAttribute("class", "active");
e.parentNode.parentNode.previousElementSibling.setAttribute("class", "active");
results_status[key] = true;
if (key.match("sh"))
{
quick_info.children[2].innerHTML += key + ", ";
}
quick_info.setAttribute("class", "show-data");
close_alert();
}
}
}
}
xmlhttp.open("POST","ajax.php", false);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send(a);
}
function number 2:
function fetch_data(a, b)
{
if (window.XMLHttpRequest)
{
xmlhttp = new XMLHttpRequest();
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
if (last_fetched_element != null) { last_fetched_element.removeAttribute("class") }
last_fetched_element = document.getElementById(b.id+".div");
var t = last_fetched_element;
var response = xmlhttp.responseText;
if (xmlhttp.responseText.length == 0) response = "No Data";
t.innerHTML = "<pre>" + response + "</pre>";
t.setAttribute("class", "show-data");
document.getElementById(b.id).setAttribute("class", "active");
close_alert();
results_status[b.id] = true;
}
}
xmlhttp.open("POST","ajax.php", false);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send(a); // "fname=Henry&lname=Ford"
}
I can't tell why this is happening. the response arrive rather quickly, but still,
I would be nice to avoid that freeze.
it is because you are using a synchronous call, try asynchronous
set the third parameter of open to true
The XMLHttpRequest.open() function. The third parameter sets Async or Normal. With Async set to true the browser won't freeze. With normal, the browser will freeze and wait for everything to be loaded. So change your lines.
xmlhttp.open("POST","ajax.php", false);
To:
xmlhttp.open("POST","ajax.php", true);

Categories

Resources