Incorrect AJAX data loading with "infinite" scrolling - javascript

I'm currently working on a script that loads content when either you trigger it (by clicking a link), or you scroll to the bottom of the page. I'm doing this for fun, but it is slowly turning into a nightmare...
The triggered part works correctly, while the "scroll to the bottom" part sometimes works and sometimes doesn't. It will sometimes load a post twice, and sometimes repeat the sets of posts (I'm loading 5 at a time) and not display the next set, my guess is that it is because it loads content so fast, that:
The queries get all mixed up (AJAX calls/mysql queries/Responses...?) or...
There's some kind of problem with the DOM (I guess this is the correct way of calling this...) or...
It is the cause of another glitch that I can't currently think of because of my basic knowledge...
The problem arises when you keep the scroll bar down, and so it loads the content very fast, it is especially a problem with Firefox, since if you are already at the bottom and refresh the page, it will load indefinitely until there are no more posts, and again, it does it really fast.
I've tried different approaches, all day... and I can't find a solution.
First, I tried setting a flag, so that when each AJAX call finishes, it increases a certain variable by the number of posts loaded, and will only execute the call again if the number has been increased, and it must do so orderly (which in my head meant succesful AJAX call). This didn't work.
Then I tried setting a timeout, for the AJAX call, and then for the function that contains that call, and then for the function that executes the function in the first place (scrolling to the bottom), this kind of worked, but with the drawback of it not doing anything for that timeout (and thus, not even displaying the "loading" html) and with the situation happening fewer times, but still happening. I also tried setting the timeout in the $.ajax() function, which I think is a different kind of timeout, because it did not do what I desired...
Finally, I tried making async false, which I read is a bad thing, because it hangs the page until it's done, and because it is also deprecated; needless to say, it didn't work either (I didn't notice any visible change in behaviour).
I'm really lost here; I'm not even sure why this "glitch" happens...
Here's my code...
$.ajax({ //Removed some code in order to make it brief
url: 'load.php',
type: 'post',
dataType: 'json',
data: {offset: countContent, limit: displayNumber},
success: function(data)
{
if(data)
{
for(var i=0;i<display_n;i++)
{
var title = data[i][1];
var author = data[i][2];
var img = data[i][3];
var date = data[i][4];
var htmlStr =
'<div class="post" id="'+i+'"></div>';
$(element).append(htmlStr);
$(element).children('#'+i+':last').hide().fadeIn(200+(i*250));
}
}
else if(data == null){
//Do something when there are no more posts
}
},
error: function() {
// Error
}
});
And the php that processes the ajax call
<?php
$offset = (int) $_POST['offset'];
$limit = (int) $_POST['limit'];
$db = 'mysql:host=localhost;dbname=posts;charset=utf8';
$u = 'username';
$p = 'password';
$con = new PDO($db,$u,$p);
$q = $con->prepare("SELECT id, title, author, img, date FROM articles
ORDER BY id DESC LIMIT :limit OFFSET :offset");
$q->bindParam(':offset',$offset,PDO::PARAM_INT);
$q->bindParam(':limit',$limit,PDO::PARAM_INT);
$q->execute();
$articles = $q->fetchAll(PDO::FETCH_NUM);
$con = null;
$array_count = count($articles);
if ($articles){
for ($i=0;$i<$array_count;$i++)
{
$articles[$i][4] = date("d F Y",strtotime($articles[$i]['4']));
}
echo json_encode($articles);
}
else
{
$articles = null; //sends null if the data is empty
echo json_encode($articles);
}
?>
Is there any way to "delay" the ajax call before the other one gets executed, so that the articles load correctly? Or wait till everything in the ajax loaded as according to plan before going to the next one? What can I do in this case?
I'm sorry if this post is kind of huge, I guess I wanted to make a point, ha. Help is very much appreciated, thanks.
EDIT: Here's what I posted below, and the solution:
I set a global variable running to false, and wrapped the whole AJAX
call inside an if !running condition, immediatly making the variable
true after entering the loop, and making it false again on either the
"complete: " parameter of the $.ajax function or via $.ajaxComplete().
I'm guessing one can also use .on() and .off() statements to bind and
unbind the event trigger, but I found the previous method so much more simple.
This allows the AJAX call to finish before the other one starts, and the content is displayed correctly.

I suggest you turn off the event trigger right after it's been triggered, and turn it back on after you populated the DOMs.

Related

Function firing additional time for each time it is called - jQuery/AJAX

Scope
We have a function. Inside of it is an ajax request:
function search(){
$.ajax({
url: "url",
dataType: "text",
success: function(result) {
var filter = $(result).find('#myDiv');
// populate a hidden div with this information
$("#ladderInformation").html(filter);
}
});
}
Once this is complete, we iterate over the results of the initial ajax request, and run a new ajax request for each of them:
// yes, this is attached to the above, it's not outside of the first ajax call
.done(function(){
// for every team, we're going to run this ajax call
$('.team').each(function(i){
$.ajax({
url: "(we make use of $(this).text() here)",
dataType: "text",
success: function(teamdata){
$('#teamListing').append($(teamdata).find('#team-sheet'));
// for every time it runs, we'll append a div to the wrapper.
$('.wrapper').append('<div class="teamInfo" id="'+ Team [i] + '"></div>');
}
});
});
});
This is all working completely fine.
Next, I manipulate the elements received:
$(document).ajaxStop(function(){
//this function is irrelevant to the issue
configureTeams();
});
All of the above is wrapped in the first mentioned function, search();. We call this with
$(document).ready(function(){
search();
$('select').on('change', function(){
search();
});
});
On first page load it does everything as expected.
The Issue
When the select listener is fired multiple times, for every time it is used, the app drastically slows down. This was also noticed when I tried to add an "auto refresh" to the results (doing so by adding setTimeout(function(){ search() }, 5000); to the end of the $(document).ajaxStop(){} function).
For every time that search() is called, it will fire an additional time. So, for example, if you've changed select 6 times (or left the app running and auto refreshing for 6 times), it is firing 6 times to match this, and inevitably breaks.
Attempts to Fix
If I were to console.log() in the $(document).ajaxStop() function, it will fire an extra time for each time search() has been called. This can be combated by changing it to $(document).one('ajaxStop', function(){}) but that isn't solving the entire problem, since all that does is prevent the configuring from firing multiple times.
I have got the divs that hold the information emptying at the start of search(), so there are no conflicts with the same data or anything like that, I have tried managing the ajax requests in a queue, I have tried multiple methods of detecting that all of the ajax requests are finished before continuing, I have tried limiting the $.each() function so it doesn't exceed the required amount of iterations, but to no avail.
TL;DR
What I'm trying to accomplish, is that when I run a function multiple times, we completely start over each time. It seems as though it is recording each time it has been called. Could there be a solution with clearing memory, or the AJAX queue, or something like that?
I can provide the full code if that will be more helpful.
Thanks

Auto refresh JavaScript code

Here's the scenario:
- there is a set of variables
- these variables indicate the statuses of various equipment
- the goal is to display an always-updated status chart
So, I have gotten as far as having a parser in Perl that spits out JavaScript var x = 'y'; type code, and now I'm looking for how to have the HTML or other JavaScript automatically check for updates to this "spit out" code, versus just caching it after the first time.
The closest thing I've seen is to use "setInterval" to have it execute a function, so I went ahead and wrapped the "var" statements in a function with a "setInterval" timer. But will this reliably be always up-to-date, or does it cache the whole function, depending on the browser?
EDIT: I'm not currently using any libraries or anything, and would prefer not to - but I will if I have to.
EDIT2: Finally found what I'm looking for. http://www.philnicholas.com/2009/05/11/reloading-your-javascript-without-reloading-your-page/
Just had to modify the last line to get it to work.
You're already close to the solution. Create a function that makes an ajax call to the 'spit out' you have written in perl.
function getSpitOut() {
$.ajax({
async: true,
type: "GET",
url: "spit_out.pl",
data: "x=8&y=7",
success: function(msg){
// UPDATE CHART
}
});
}
And another function to make the ajax calls at intervals:
$(document).ready(function() {
setInterval(getSpitOut, 60000); // Call getSpitOut every 60s
})
The browser won't cache it because you're updating the chart based on the server side perl script.
Apparently I never closed this.
Slightly modified from: "http://www.philnicholas.com/2009/05/11/reloading-your-javascript-without-reloading-your-page/", I have this:
var docHeadObj = document.getElementsByTagName("head")[0];
var dynamicScript = document.createElement("script");
dynamicScript.type = "text/javascript";
dynamicScript.src = scriptName;
docHeadObj.appendChild(dynamicScript);

retrieve value from mysql database with php/javascript in refreshing window

i have script that works as follows:
there is main page with 'start' button that initializes javascript function which loads a php page into a div frame, then via setTimeout it calls a 'refresh' function thats supposed to work indefinitelly and refresh the page inside frame
the refreesh timer is in database and is forwarded to java like this:
var min_refresh_time = ;
$min_refresh_time_sec is taken from database earlier in the code
what i wanted to modify is so the refresh min_refresh_time would be taken each time a refresh function is run, to my surprise this worked (or at least i thought so):
var min_refresh_time = ;
(custom sql functions are defined in separate php file included in main.php which is my main page)
unfortunatelly it seems that it 'worked' only due to some strange caching on java part and my pseudo-php code to take value from database is just a hoax - it looks like it is run only initially and then stores output somehow
simplified code of what is done and what i want to do:
function refresh_code(){
refresh_time = <?php Print(sql_result(sql_execute("SELECT value FROM settings WHERE setting='min_refresh_time'", $connection), 0, 0)); ?>;
refresh_time = 5;
alert(refresh_time);
$.post("index.php",{refresh_time:refresh_time_post, account_group: "1"},
function(data)
{
$.ajaxSetup ({
cache: false,
});
$("#frame_1").html(data);
});
setTimeout(function(){refresh_code()}, refresh_time);}
lets say min_refresh_time is 1 in database, i run it, it alerts 1 then 5 each time it self-refreshes, now if i go to database and change 1 to 3 i would want it to alert 3 then 5 obvious, it still does 1 then 5 tho...
i need a way to execute a dummy php file that only takes value from database, then sends it via post back to java and it gets intercepted there, any simple way to do that?
or do i need to use entirely different method for retrieving database value without js...
thx in advance
update:
i actually came back to it and analyzed potential solutions with fresh mind
first of all, i dont think my initial code had chance to work, java cant execute serverside code by itself, i took some of my aax code from other script and reworked it to launch php file that grabs the value from database, then i intercept output data and put into variable
looks like that:
$.ajax({
method: "POST",
url: "retrieve_refresh.php",
data: { retrieve_data: "max"},
cache: false,
timeout: 5000,
async: false,
cache: false,
error: function(){
return true;
},
success: function(msg){
if (parseFloat(msg)){
return false;
}
else {
return true;
}
}
}).done(function(php_output2) {
max_refresh_time = php_output2;
});
retrieve_refresh.php returns only the variable i want but the solution is unelegant to say the least, i havent searched yet but could use a way of sending variables as post back to ajax...

AJAX -- Multiple concurrent requests: Delay AJAX execution until certain calls have completed

I am currently working on a web based time tracking software. I'm developing in grails, but this question is solely related to javascript and asynchronous requests.
The time tracking tool shall enable users to choose a day for the current month, create one or multiple activities for each day and save the entire day. Each activity must be assigned to a project and a contract.
Upon choosing "save", the partial day is saved to the database, the hours are calculated and a table is updated at the bottom of the page, showing an overview of the user's worked hours per month.
Now to my issue: There may be a lot of AJAX request. Patient users might only click the "create activity" button just once and wait until it is created. Others, however, might just keep clicking until something happens.
The main issue here is updating the view, although i also recognized some failed calls because of concurrent database transaction (especially when choosing "save" and "delete" sequentially). Any feedback on that issue -- requests not "waiting" for the same row to be ready again -- will be apreciated as well, yet this is not my question.
I have an updateTemplate(data, day) function, which is invoked onSuccess of respective ajax calls in either of my functions saveRecord(), deleteRecord(), pasteRecords(), makeEditable() (undo save). Here is the example AJAX call in jquery:
$.ajax({
type: "POST",
url: "${g.createLink(controller:"controller", action:"action")}",
data: requestJson,
contentType:"application/json; charset=utf-8",
async: true,
success: function(data, textstatus) {updateTemplate(data["template"], tag); updateTable(data["table"]);},
});
In the controller action, a JSON object is rendered as a response, containing the keys template and table. Each key has a template rendered as a String assigned to it, using g.render.
Now, what happens when I click on create repeatedly in very short intervalls, due to the asynchronous calls, some create (or other) actions are executed concurrently. The issue is that updateTemplate just renders data from the repsonse; the data to render is collected in the create controller action. But the "last" request action only finds the objects created by itself. I think this is because create actions are run concurrently
I figure there is something I'm either overcomplicating or doing something essentially wrong working with a page that refreshs dynamically. The only thing I found that helps are synchronous calls, which works, but the user experience was awful. What options do I have to make this work? Is this really it or am I just looking for the wrong approach? How can I make this all more robust, so that impatient users are not able to break my code?
*********EDIT:********
I know that I could block buttons or keyboard shortcuts, use synchronous calls or similar things to avoid those issues. However, I want to know if it is possible to solve it with multiple AJAX requests being submitted. So the user should be able to keep adding new activities, although they won't appear immediately. There is a spinner for feedback anyway. I just want to somehow make sure that before the "last" AJAX request gets fired, the database is up to date so that the controller action will respond with the up-to-date gsp template with the right objects.
With help of this Stackoverflow answer, I found a way to ensure that the ajax call -- in the javascript function executed lastly -- always responds with an up-to-date model. Basically, I put the javascript functions containing AJAX calls in a waiting queue if a "critical" AJAX request has been initiated before but not completed yet.
For that I define the function doCallAjaxBusyAwareFunction(callable) that checks if the global variable Global.busy is 'true' prior to executing the callable function. If it's true, the function will be executed again until Global.busy is false, to finally execute the function -- collecting the data from the DOM -- and fire the AJAX request.
Definition of the global Variable:
var Global = {
ajaxIsBusy = false//,
//additional Global scope variables
};
Definition of the function doCallAjaxBusyAwareFunction:
function doCallAjaxBusyAwareFunction(callable) {
if(Global.busy == true){
console.log("Global.busy = " + Global.busy + ". Timout set! Try again in 100ms!!");
setTimeout(function(){doCallAjaxBusyAwareFunction(callable);}, 100);
}
else{
console.log("Global.busy = " + Global.busy + ". Call function!!");
callable();
}
}
To flag a function containing ajax as critical, I let it set Global.busy = true at the very start and Global.busy = false on AJAX complete. Example call:
function xyz (){
Global.busy = true;
//collect ajax request parameters from DOM
$.ajax({
//desired ajax settings
complete: function(data, status){ Global.busy = false; }
}
Since Global.busy is set to true at the very beginning, the DOM cannot be manipulated -- e.g. by deletes while the function xyz collects DOM data. But when the function was executed, there is still Global.busy === true until the ajax call completes.
Fire an ajax call from a "busy-aware" function:
doCallAjaxBusyAwareFunction(function(){
//collect DOM data
$.ajax({/*AJAX settings*/});
});
....or fire an ajax call from a "busy-aware" function that is also marked critical itself (basically what I mainly use it for):
doCallAjaxBusyAwareFunction(function(){
Global.busy = true;
//collect DOM data
$.ajax({
//AJAX SETTINGS
complete: function(data, status){ Global.busy = false; }
});
});
Feedback is welcome and other options too, especially if this approach is bad practice. I really hope somebody finds this post and evaluates it, since I don't know if it should be done like that at all. I will leave this question unanswered for now.

Filtering items with jQuery (AJAX) - requests finish in wrong order

I am working on a project for school and it's about jQuery, PHP, symfony and all that web stuff :). It is actually my first time using jQuery and even though I have already learned something, there are still many thing I dont know how to solve.
In this project, one of the things I am supposed to make is basically filtering some results. I have a database and when the site is loaded, all items from the database are displayed in a table. Then above the table, there is a text field. When I type in it, the items in the table are filtered as I type. But sometimes, when I write for example "HP", the jQuery first finishes the request for "HP" and displays the result and then it finished the request for "H" and so it overwrites the result of "HP" and this shouldnt happen. If I make the requests synchronous, it prevents me from writing in the text field when a request is being processed. How can I make it so that the requests are completed in the order they were called?
The jQuery code of this part of the project looks like this:
var oldTerm;
function filter() {
var term = $('#term').val();
//alert(term);
if(term != oldTerm) {
$.ajax({
url: url.replace('--', term).replace(/\/$/, '')
//musi bejt synchronni
}).done(function(data) {
$('#items_table tbody').html(data);
alert(term);
// udalost se musi registrovat po nacteni radku!
$('.edit_button').click(createForm);
});
oldTerm = term;
}
}
$(document).ready(function() {
oldTerm = null;
$('#term').keyup(filter);
});
I think your best shoot is to make a queue for the ajax call maybe use a lock too. You can also use this : Queue AJAX calls

Categories

Resources