So I have a script that pulls data from the database and displays it when the user nears the bottom of the page.
The problem:
When the user reaches the bottom, the script should only return one post back, but instead, multiple requests are being made, causing all of the posts to be being pulled from the database at a rapid pace, which in turn returns them in the wrong order.
My question is, is there anyone who knows how to stop it from going haywire and prevent the spamming of articles?
Note:
I'm not looking to completely cut the AJAX requests off once one has been made, as this script is an 'infinite scroll', pulling articles one by one from the database when the user reaches the bottom.
Thanks in advance, Rich.
$(document).ready(function() {
$(window).scroll(function() {
if($(window).scrollTop() + $(window).height() > $(document).height() - 200) {
$('div#loadMoreArticles').show( function(){
$.ajax({
url: "loadMoreArticles.php?lastArticle="+ $(".postedArticle:last").attr('id') ,
success: function(html) {
if(html){
$("#postedArticle").append(html);
$('div#loadMoreArticles').hide();
} else {
$('div#loadMoreArticles').replaceWith("<p>There are no more articles.</p>");
}
}
});
});
}
});
});
Hope this helps
$(document).ready(function() {
var AjaxRequestOn;
$(window).scroll(function() {
if ($(window).scrollTop() + $(window).height() > $(document).height() - 200) {
$('div#loadMoreArticles').show(function() {
if (!AjaxRequestOn) {
AjaxRequestOn = $.ajax({
url: "/",
success: function(html) {
}
});
}
});
}
});
});
Just use a variable to set the ajax request , when the first ajax is set then if user again scroll up and comes down then the variable has some value so we should not do the call again(check if loop before ajax call). If the variable is not defined then we have to make the call to server. so this results in only one call to server.
Try defining handler as named function , using .off() to detach scroll event before $.ajax() call , reattach scroll event after $.ajax() completes
function scroller() {
if($(window).scrollTop() + $(window).height() > $(document).height() - 200) {
$(this).off("scroll.ajax");
$('div#loadMoreArticles').show( function(){
$.ajax({
url: "loadMoreArticles.php?lastArticle="+ $(".postedArticle:last").attr('id') ,
success: function(html) {
if(html){
$("#postedArticle").append(html);
$('div#loadMoreArticles').hide();
} else {
$('div#loadMoreArticles').replaceWith("<p>There are no more articles.</p>");
};
// setTimeout(function() {
$(window).on("scroll.ajax", scroller)
// }, 500)
}
});
});
}
}
$(window).on("scroll.ajax", scroller);
Related
Im trying to show a loading div while waiting for an ajax call to complete. I have tried a couple of methods but cant seem to get anything to work consistently.
with my current code it works if i have a break point on the function that shows the div once the ajax is complete.
Fiddle
var https = 'https://www.googleapis.com/calendar/v3/calendars/';
function HideCheckShowLoading(checkId) {
$("#check_" + checkId).hide('slow', function() {
$("#loading_" + checkId).show('slow');
});
};
function HideLoadingShowCheck(checkId) {
$("#loading_" + checkId).finish().hide('slow', function() {
$("#check_" + checkId).finish().show('slow');
});
};
$(document).ready(function() {
$('#get').click(function() {
HideCheckShowLoading(1);
$.ajax({
url: https,
dataType: 'jsonp',
type: "GET",
success: function(response) {
//do something
},
error: function() {
//do something else
}
}).done(function() {
HideLoadingShowCheck(1)
});
});
$('#get2').click(function() {
HideLoadingShowCheck(1);
});
});
#check_1
{
background-color:red;
}
#loading_1
{
background-color:blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="check_1">Check</div>
<div hidden id="loading_1">LOADING</div>
<button id="get">Get</button>
<button id="get2">Get2</button>
What i would like to happen is,
on the click of a button we hide the check div
we show the loading div
make the ajax call
if successful do something(Reload the contents of the check div)
hide the loading div
show the check div
As said I have tried a few methods that i have found but i repeatedly get stuck with just the loading div shown
Thanks
I believe you may be slightly over-complicating things here. Something simple like this would suffice:
$('#get').click(function() {
HideCheckShowLoading();
$.ajax({
url: https,
dataType: 'jsonp',
type: "GET",
success: function (response) {
//do something
},
error: function() {
//do something else
},
complete: HideLoadingShowCheck
});
});
If you don't want the HideLoadingShowCheck routine to happen after success or error (standard behavior of complete), you can just move a function call HideLoadingShowCheck(); into your success and error blocks instead of using complete.
When you add () to a function name, it calls it immediately and returns the result. What you want to do is pass the function itself, not the result of the function - and you do that without the ().
There's no need for the $.when (assuming HideCheckShowLoading() doesn't make an ajax call, the jquery animations work differently), and $.ajax returns the promise itself, so you can update your code to:
$(document).ready(function() {
$('#get').click(function() {
HideCheckShowLoading();
$.ajax({
url: https,
dataType: 'jsonp',
type: "GET",
success: function (response) {
//do something
},
error: function() {
//do something else
}
})
//.done(HideLoadingShowCheck);
.done(function() { HideLoadingShowCheck(otherparams); })
});
});
I would change the showcheck function to add .finish() incase it's still animating from the showhide:
function HideLoadingShowCheck() {
$("#loading").finish().hide('slow',function () {
$("#check").finish().show('slow');
});
};
I have been trying to scroll the page to a dynamic div that is created by the an ajax call.
When #divnotifications div clicked (below), I make the first ajax call that adds the Post details, then within this ajax call, another ajax call is made to add the related comments to the div.
The part explained so far works great. Then, I use $.when().then() to scroll to a div item created based on the ajax calls. However, the page does not scroll to the element that was created by LoadCommentsForPost ajax call.
Did I get the logic of $.when().then() wrong?
$(document).on('click', '#divnotifications div', function (event) {
event.preventDefault();
$.ajax({
//other details
success: function (postid) {
$.when(DisplayPostWithFullDetails(postid)).then(function () {
//scroll to the content created by
//LoadCommentsForPost function nested
//inside DisplayPostWithFullDetails
});
}
});
});
function DisplayPostWithFullDetails(postId) {
$.ajax({
//other details
success: function (post) {
//The code to build the div to display the post -- working fine
LoadCommentsForPost(post.PostId);
}
});
}
function LoadCommentsForPost(postid) {
$.ajax({
//other details
success: function (response) {
var comments = JSON.parse(response);
DisplayComments(comments);//builds the div to display the comments - working fine
}
});
}
UPDATED CODE
After receiving some feedback, I ended up with the following code. However, it is still not working. It works only if I add some delay to make sure the div is loaded:
$(document).on('click', '#divnotifications div', function (event) {
event.preventDefault();
$.ajax({
//other ajax stuff
success: function (postid) {
DisplayPostWithFullDetails(postid).done(function () {
setTimeout(function () {
var scrollto = $("div[data-" + type.toLowerCase() + "displayform='" + relateditem + "']").offset().top;
$("html, body").animate({ scrollTop: scrollto }, 600);
}, 500);
});
}
});
});
function DisplayPostWithFullDetails(postId) {
jQuery.support.cors = true;
return $.ajax({
//other ajax stuff
success: function (post) {
post = JSON.parse(post);
//display the post details
LoadCommentsForPost(post.PostId);
}
});
}
function LoadCommentsForPost(postid) {
var promise = new $.Deferred();
jQuery.support.cors = true;
$.ajax({
//other ajax stuff
success: function (response) {
var comments = JSON.parse(response);
DisplayComments(comments);//this is not ajax
promise.resolve('loadedcomments');
}
});
return promise;
}
Did I get the logic of $.when().then() wrong?
Yes, you need to return a promise from the functions if you want to use the function with $.when:
function DisplayPostWithFullDetails(postId) {
return $.ajax({...
// ^^^^^^
That said, wrapping a single promise in $.when is useless.
$.when(DisplayPostWithFullDetails(postid)).then(function () {
should just be:
DisplayPostWithFullDetail(postid).then(function () {
Did I get the logic of $.when().then() wrong?
No, but you are NOT returning the promise so you can't use the promise functions like .then().
UPDATE:
I use $.when().then() to scroll to a div item created based on the ajax calls. However, the page does not scroll to the element that was created by LoadCommentsForPost ajax call.
For me this means that you need to wait that both ajax calls are resolved.
This fiddle show how it should work emulating the ajax call using setTimeout Fiddle.
Your code may look similar to:
function DisplayPostWithFullDetails(postId) {
var promise = new $.Deferred();
$.ajax({
//other details
success: function (post) {
//The code to build the div to display the post -- working fine
LoadCommentsForPost(post.PostId).then(function() {
promise.resolve();
});
}
});
return promise;
}
function LoadCommentsForPost(postid) {
return $.ajax({
//other details
success: function (response) {
var comments = JSON.parse(response);
DisplayComments(comments);//builds the div to display the comments - working fine
}
});
}
Now when you execute the function DisplayPostWithFullDetails it return a promise.
So you can use .then() method;
DisplayPostWithFullDetails(postid)).then(function () {});
or...
var promise = DisplayPostWithFullDetails(postid);
promise.then(function(data){});
Also the major advantage of use $.when() is that you can execute the .then() method when all the promises that you pass to it are resolved.
There are not need to use it when you are waiting for a single promise.
I'm building a Joomla module that uses slideDown and ajax of jQuery.
The way it works is that it populates the slideDown div, compute the div child element with highest height, and resizes the containing div height for display.
Problem is if the page is not cached (i.e. if it is on first load of the page) the height is not displayed properly as below
But on second click and so on, it displays correctly as follows
I'm thinking it is because the contents of the div child element are not completely populated before the height is computed, hence a false height is generated. I've tried some things to ensure that does not happen - right now I'm using a callback function along with the function that populates the div tag.
Quick help will be highly appreciated, thanks!
Edit - here's the code that populates
menuItemAjax: function (urlContent, dataContent) {
jQuery.ajax({
type: "POST",
url: urlContent,
data: dataContent, // data to send along with url
complete: function () {
//console.log("Process completed");
},
success: function (returnedData) {
WetvCreateHtml.popDropDownDiv(returnedData, function() {
var ddChildren = dropdownDiv.children(), highestHeight = 0;
ddChildren.each(function(){
if (jQuery(this).height() > highestHeight) {
highestHeight = jQuery(this).height();
}
});
dropdownDiv.animate({ height: highestHeight });
});
},
error: function () {
//console.log("Error occured");
},
statusCode: {
404: function() {
//console.log("Page not found");
}
}
});
},
popDropDownDiv: function(returnedData, callback) {
dropdownDiv.html(returnedData);
if (typeof(callback) == "function") {
callback();
}
}
I am trying to do an ajax pagination with the following code:
// AJAX pagination
$(".pages .prev").live('click', function(event) {
event.preventDefault()
var current_page = parseInt(getParameterByName('page'))-1;
$.get('/ajax/financial_page/', {'page': current_page}, function(response) {
$(".content table").replaceWith(response)
});
})
And in my view function:
def financial_page(request):
"""
Returns a single financials page, without extra HTML (used in AJAX calls).
"""
page = int(request.GET.get('page', 1))
if request.user.is_superuser:
fs = FinancialStatements.objects.order_by('-date', 'statement_id')
else:
up = request.user.get_profile()
providers = up.provider.all()
fs = FinancialStatements.objects.filter(provider__in=providers).order_by('-date', 'statement_id')
fs_objects, current_page_object, page_range = paginator(request, objects=fs, page=page, number_per_page=30)
data = { 'fs':fs_objects,
'page_range': page_range,
'current_page': current_page_object,
}
page = render_to_string('financial_section.html', data, RequestContext(request))
return HttpResponse(simplejson.dumps([page]))
However, there are two problems I'm running into. The first is that the response is not really HTML, and has a bunch of n\t\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\, etc. Also, I'm having trouble keeping track of the current page/changing the url as needed. How would I build a functional ajax pagination here?
Update: I figured out the first one, by doing response = $.parseJSON(response);. How would I keep track of which page I am on though?
To keep track of the page, you can increment/decrement a variable on click with your AJAX function. Try this:
var counter="0";
$(document.body).on('click', ".pages .prev, .pages .next", function(event) {
if($(this).hasClass('prev')
counter--;// <--decrement for clicking previous button
else if($(this).hasClass('next')
counter++; // <--increment for clicking next button
event.preventDefault()
$.get('/ajax/financial_page/', {'page': counter}, function(response) {
$(".content table").replaceWith(response)
});
})
I would also not use live method as it is deprecated as of jQuery 1.7. It has been replace by the on method. See the jQuery on() API here: http://api.jquery.com/on/
Check this tutorial about "Ajax Scroll Paging Using jQuery, PHP and MySQL", it may simplify your job:
http://www.bewebdeveloper.com/tutorial-about-ajax-scroll-paging-using-jquery-php-and-mysql
Here is the essential from:
var is_loading = false; // initialize is_loading by false to accept new loading
var limit = 4; // limit items per page
$(function() {
$(window).scroll(function() {
if($(window).scrollTop() + $(window).height() == $(document).height()) {
if (is_loading == false) { // stop loading many times for the same page
// set is_loading to true to refuse new loading
is_loading = true;
// display the waiting loader
$('#loader').show();
// execute an ajax query to load more statments
$.ajax({
url: 'load_more.php',
type: 'POST',
data: {last_id:last_id, limit:limit},
success:function(data){
// now we have the response, so hide the loader
$('#loader').hide();
// append: add the new statments to the existing data
$('#items').append(data);
// set is_loading to false to accept new loading
is_loading = false;
}
});
}
}
});
});
Try using the javascript String.replace() method:
// AJAX pagination
$(".pages .prev").live('click', function(event) {
event.preventDefault()
var current_page = parseInt(getParameterByName('page'))-1;
$.post('/ajax/financial_page/', {'page': current_page}, function(response) {
response = response.replace(/\n/g,'<br>').replace(/\t/,' ');
$(".content table").replaceWith(response)
});
})
jQuery.get(url, [data], [callback], [type])
type :xml, html, script, json, text, _default。
how about trying to define the last parameter as "html" ?
$( document ).bind( 'mousemove', function ( e )
{
if ( e.pageY > $( document ).height() - 400 )
{
$.ajax( {
url: '/Tweet/GetFiveUserTweets',
type: 'POST',
async: false, // preventing a lot of asynchronous requests
success: function ( result )
{
// result
}
} );
}
} );
‘async:false’ hangs the browser until request completes and that’s not good.
and when remove 'async:false', dozen of simultaneous request made because mousemove event....
I don’t want to hang the browser.
I just want a single asynchronous Ajax request at a time.
Can anyone let me know how to do a better coding for this situation?
Edit:
Actually when user scroll down at bottom, I want to get five next records and append them at bottom. www.twitter.com do this with tweets....
what's about:
$(window).bind('scroll', function () {
if (nearBottomOfPage()) {
// load things here ...
}
});
I think it's better than mousemove...am I right?
make async true.
To avoid multiple simultaneous requests, before starting a request, check a variable, for example if(!active_check) {...} and then set that variable when you start, active_check=true. When the request completes, set the variable to false/null again.
if(!active_check) {
active_check=true;
//do request with callback to change active check when done
}
or using your code...
$( document ).bind( 'mousemove', function ( e )
{
if ( (e.pageY > $( document ).height() - 400) && !active_check)
{
active_check = true;
$.ajax( {
url: '/Tweet/GetFiveUserTweets',
type: 'POST',
async: true,
success: function ( result )
{
active_check = false;
}
} );
}
} );
That said, the mousemove event fires extremely frequently. You'll want to use something else, if you can.
It's probably a really bad idea to fire request on a mousemove event.
As you mentioned correctly, this will cause dozens of request, more than any average server will take/accept and are useless anyway in this case. You should reconsider your logic.
If you need those request to get fired on mousemove, you should throttle them. This could look like:
$(function() {
var did_fire = false;
setInterval(function() {
if( did_fire ) {
$.ajax({});
did_fire = false;
}
}, 2000);
$(element).mouseover(function() {
did_fire = true;
});
});
This is a very simple technique to reduce the created requestes to 1/2000ms.
Like always you can go crazy about this and write your own request manager (or use a plugin for that) which stores all the request and fires them in order.
Have you tried making async = true? What happened? If you get "then dozen of simultaneous requests...what to do with them" who/what in your code is issuing these requests? You will get one response per request.
Think about it: Ajax is pull technology. Ajax push would be great but it doesn't exist.
So make async: true always and thn find out how your code is making dozens of requests.
-- pete
although you have accepted Jonathan Fingland's answer, it has got some problems
Usually twitter or 3rd party app require JSONP as data type(its a constrain because of cross domain request). In jQuery when dataType=JSONP, error function specified in jQuery.ajax is never invoked if any error occurs(for that you can use a plugin). That means if any error occurs on server active_check variable will remain true forever.
Suppose a user moves his mouse for 50 seconds and ur ajax request end successfully in 10 seconds, that means you are still making 4 or 5 requests with this method
A better Solution
jQuery(function(){
var delay=50;
var handler;
$(document).bind('mousemove', function(e)
{
if (e.pageY > $(document).height() - 400)
{
if(handler)
{
clearTimeout(handler);
}
else
{
handler= setTimeout(makeAjaxRequest,delay);
}
}
});
function makeAjaxRequest()
{
$.ajax( {
url: '/Tweet/GetFiveUserTweets',
type: 'POST',
async: true,
success: function ( result )
{
// do something
}
} );
}
});