Ajax GET is getting called twice (in Endless Scroll) - javascript

I have an endless scrolling made by ajax and jQuery. It's using the items paginated in Controller (Laravel5), getting it with ajax.
Everything works fine, however I have a problem. When I hit the bottom of the page, it makes an ajax call twice. I suspect it's because of the setInterval because when I change the time, it affects exactly that part.
// Creates the pagination pages [<[1]2]3]>]
{!! $boxes->render() !!}
// Html
<input type="hidden" id="page" value="1" />
<input type="hidden" id="max_page" value="{{{ $boxes-id }}}" />
<div id="end_of_page" class="center">
<hr/>
<span>End of the feed.</span>
<script>
$(document).ready(function() {
var didScroll = false;
$(window).scroll(function() { //watches scroll of the window
didScroll = true;
});
//Sets an interval so your window.scroll event doesn't fire constantly. This waits for the user to stop scrolling for not even a second and then fires the pageCountUpdate function (and then the getPost function)
setInterval(function() {
if (didScroll){
didScroll = false;
if(($(document).height()-$(window).height())-$(window).scrollTop() < 10){
pageCountUpdate();
}
}
}, 250);
When I change 250 to 5000 for example, it gives a time in between, but this is not what I want to make. I want to make the call only one time once I hit the bottom, maybe disable it with a boolean variable, and then reactivate it after new elements load (on ajax success state), but I couldn't figure it out where to put the blocking variable.
//Continuing
function pageCountUpdate(){
var page = parseInt($('#page').val());
var max_page = parseInt($('#max_page').val());
if(page < max_page){
$('#page').val(page+1);
getPosts();
$('#end_of_page').hide();
} else {
$('#end_of_page').fadeIn();
}
}
function getPosts(){
var data = { "page": $('#page').val() }
$.ajax({
type: "POST",
//Classic ajax call
beforeSend: function(){
..}
complete: function(){
..}
success: function(){
..}
});
}
}
});
Update: Regarding to John Resig's example mentioned in comments, I need to use var outerPane = $details.find(".details-pane-outer"),
didScroll = false;. I think not having this part creates my problem, but I couldn't figure out where to choose with find() method.

apart from your weird setinterval structure (just move the code into the scroll event, without an interval).
It seems that the scroll event is called multiple times inside the last 10 pixels of the bottom of the page. So while scrolling to the bottom, at 9 px away form the bottom, the event is fired which loads more posts. But even before the new posts are loaded, in the meanwhile you scroll a little further which again fires the scroll event. This makes your posts load twice or even more than twice.
To solve this you can add a simple boolean switch that makes sure that the posts don't get loaded again when they're already being loaded. Something like:
var loading=false;
function onReachScrollLimit(){
if(loading){return;}
loading=true;
load_new_posts();
}
function load_new_posts(){
//insert the posts
loading=false;
}

Related

Function initiated in ajax call only works one time

I am using a plugin called mixitup that makes sure I have a masonry layout with some animations.
The masonry comes from another page which gets loaded in through ajax. I have a search bar which searches for photos and returns them from the masonry page. The issue is this works the first time but not the second time and so on. Why is that?
My code for the search input:
$('.photosearchinput').keyup(function(e) {
clearTimeout($.data(this, 'timer'));
if (e.keyCode == 13){
searchphotos(true);
}else{
$(this).data('timer', setTimeout(searchphotos, 500));
}
});
My function that makes the ajax call and which has my masonry mixitup function in the complete:
function searchphotos(force) {
var photoform = $(".photosearchform").serialize();
$.ajax({
type:'post',
url:"includes/photoresults.php",
data:({photoform: photoform}),
success:function(data){
$( "#searchphotos" ).show().empty().append( data );
},
complete:function(){
// I tried calling #masongallery from the body (body always stays the same and does not get added again)
$('body').find('#masonrygallery').mixItUp({
selectors: {
target: '.tile',
filter: '.filter',
sort: '.sort-btn'
},
animation: {
animateResizeContainer: false,
effects: 'fade scale'
}
});
}
});
}
I thought maybe the DOM gets reloaded and jquery cannot find the element #masonrygallery anymore so I tried calling it like this: $('body').find('#masonrygallery').mixItUp({ the body never gets reloaded so maybe this would fix it, but no. I get the same result. It works the first time, but not any time after that.
I have made a video to show what I mean: https://streamable.com/njy6x7
I get no errors in my console. And when I look in the network tab to see what ajax is retrieving, I see the correct images, they are just not visible as masonry layout (in fact they are not visible on the page at all but this is because of the plugin).

HTML Load elements in a blank page

I have an empty HTML page with just a div and a button to load data.
<body>
<div id="main_div"></div>
<button class="load_more" onclick="myFunction()">Load More..</button>
</body>
myFunction is a function which creates and populate the div main_div.
I want to create an infinite scroll view out of it.
I have added scroll listener which call myFunction and loads the data once only 200px is left. (I got this code from a blog online)
$(window).on('scroll', function() {
console.log('Scroll detected')
var scrollHeight = $(document).height();
var scrollPos = Math.floor($(window).height() + $(window).scrollTop());
var isBottom = scrollHeight - 200 < scrollPos;
if (isBottom && currentscrollHeight < scrollHeight) {
$('.load_more').click();
currentscrollHeight = scrollHeight;
}
});
The infinite scroll works fine when I manually tap the load button a few times and the page is loaded with elements. After that when I scroll, it loads new data.
But what I want is to fill the initial space from the same API.
I thought of calling the same function multiple time, but I am not sure how many times should I call, as the page can be opened from a mobile or any browser and I would not know the height of that.
Also, I want to avoid JQuery or other frameworks to keep it minimal. I know the code is already using JQuery, but I plan to remove it.
you can call a function which will check your div height and compare it with windowHeight. Till div height less than windowHeight you should call that function
Like
document.addEventListener("DOMContentLoaded", function(e) {
function loadData(callBackFunction) {
// your function body
// in your ajax success request add following line
if (callBackFunction) {
callBackFunction();
}
}
function loadInitialData() {
if (document.getElementById('main_div').getBoundingClientRect().height < window.innerHeight) {
loadData(loadInitialData);
}
}
(function() {
loadInitialData();
})();
// Also Your click event won't work here(inside the listener function).
// So it isn't visible outside of this function's scope.
// If you want to call the method directly 'from the button', then you have to attach it to `window`
window.loadData = loadData;
})

ajax infinate scroll to preload content

I have an infinate scrolling function that loads data via ajax. I would like to load the next set of data or at least, images in advance - preload the next page of content.
I have tried adding .load instead of .ajax - but it still seems to load the data directly not from a 'cached' version.
Any ideas appreciated.
jQuery(document).ready(function($) {
var count = 2;
var total = <?php echo $wp_query->max_num_pages; ?>;
var ready = true; //Assign the flag here
var processing;
$(window).data('ajaxready', true).scroll(function() {
if ($(window).data('ajaxready') == false) return;
if ($(window).scrollTop() == ($(document).height() - $(window).height())){
$(window).data('ajaxready', false);
if (count > total){
return false;
}else{
loadArticle(count);
}
count++;
}
});
function loadArticle(pageNumber){
$('a#inifiniteLoader').show('fast');
$.ajax({
url: "<?php bloginfo('wpurl') ?>/wp-admin/admin-ajax.php",
type:'POST',
data: "action=infinite_scroll&page_no="+ pageNumber + '&loop_file=loop',
success: function(html){
$('a#inifiniteLoader').hide('1000');
$(".newsfeed").append(html); // This will be the div where our content will be loaded
console.log('fire');
//stop multiple firing
$(window).data('ajaxready', true);
}
});
return false;
}
});
First I should say what is infinite scroll:
Traditionally, the user would have to click on next page or previous page to visit older post content. However, recently there is
a new trend started by popular sites (such as facebook and twitter) in
which they automatically load the next page content once the user hits
the bottom of the post. This technique has proven to show an increase
in time spent on page by the user because the new content loads
automatically.
How to Add Infinite Scroll in WordPress
First thing you need to do is install and activate the Infinite Scroll plugin.
Upon activation, a new menu option will be added under your settings
tab called Infinite Scroll. On almost 90% of the blog sites, this
should work without changing a single setting. However, if you have a
relatively custom designed blog, then you will need to adjust the
“Selectors”. Go the plugin’s setting page and click on the selectors
tab.
plugin
Documentation 1
documentation 2

How do update a page element while inside a long running event?

I've got a long running method -- and I want to indicate to the user that an operation is underway. This is NOT and ajax call, so I can't use the common pattern I've used in the past to display, say a spinner, before the ajax event, then hiding it on success for example.
In my case -- I'm not making an ajax call, I'm instead doing some very heavy DOM manipulation.
I had a test example on jsFiddle.net -- would love to learn how to capture the event. At the moment, my "wait-message" div updates at the same exact time when my operation completes which is much too late :(
Complete sample code is here: http://jsfiddle.net/rsturim/97hrs/6/
Javascript (jQuery)
$(document).ready(function() {
$("#link-action").click(function(e) {
$("#wait-message").text("starting ...");
var count = longRunningMethod(1000000000);
$("#result").text(count);
$("#wait-message").text("completed.");
});
var longRunningMethod = function(countUpTo) {
var i = 0;
while (i <= countUpTo) {
i++;
}
return i;
};
});
HTML:
<div id="wait-message">
push button please
</div>
<hr />
<button id="link-action">Run Operation</button>
<hr />
<h1>Results:</h1>
<div id="result"> </div>
Here is a solution. I'm not sure if it works in all browsers, you may want to test it out in several, but I think it does:
$(document).ready(function() {
$("#link-action").click(function(e) {
$("#wait-message").text("starting ...");
// Stuff to do after a render
setTimeout(function(){
var count = longRunningMethod(1000000000);
$("#result").text(count);
$("#wait-message").text("completed.");
}, 0);
});
var longRunningMethod = function(countUpTo) {
var i = 0;
while (i <= countUpTo) {
i++;
}
return i;
};
});
Basically, the browser won't render any changes until a script finishes executing. That allows you to do things like:
Hide all divs with a certain class
Show one of those divs
In a row and the browser will never render the div that is being shown as hidden, so you won't get weird flickers or things moving around on the page.
Using setTimeout like I did, the anonymous click handler will finish executing, the browser will re-render, the the anonymous function in the setTimeout will run (immediately after the render since there is no actual delay).
Use setTimeout or setInterval instead of your while loop; a sub-second delay like 15ms should be enough to prevent your window freezing / UI locking.

Call a function only once

I've 3 divs (#Mask #Intro #Container) so if you click on Mask, Intro gets hidden and Container appears.
The problem is that I just want to load this only one time, not every time I refresh the page or anytime I click on the menu or a link, etc.
How can I do this?
This is the script I'm using for now:
$(document).ready(function(){
$("div#mask").click(function() {
$("div#intro").fadeToggle('slow');
$("div#container").fadeToggle('slow');
$("div#mask").css("z-index", "-99");
});
});
Thank you!
You can try using a simple counter.
// count how many times click event is triggered
var eventsFired = 0;
$(document).ready(function(){
$("div#mask").click(function() {
if (eventsFired == 0) {
$("div#intro").fadeToggle('slow');
$("div#container").fadeToggle('slow');
$("div#mask").css("z-index", "-99");
eventsFired++; // <-- now equals 1, won't fire again until reload
}
});
});
To persist this you will need to set a cookie. (e.g. $.cookie() if you use that plugin).
// example using $.cookie plugin
var eventsFired = ($.cookie('eventsFired') != null)
? $.cookie('eventsFired')
: 0;
$(document).ready(function(){
$("div#mask").click(function() {
if (eventsFired == 0) {
$("div#intro").fadeToggle('slow');
$("div#container").fadeToggle('slow');
$("div#mask").css("z-index", "-99");
eventsFired++; // <-- now equals 1, won't fire again until reload
$.cookie('eventsFired', eventsFired);
}
});
});
To delete the cookie later on:
$.cookie('eventsFired', null);
Just point to an empty function once it has been called.
var myFunc = function(){
myFunc = function(){}; // kill it
console.log('Done once!'); // your stuff here
};
Web pages are stateless in that they don't hold states between page refreshes. When you reload the page it has no clue what has happened in the past.
Cookies to the rescue! You can use Javascript (and jQuery has some nice plugins to make it easier) to store variables on the client's browser. Store a cookie when the mask is clicked, so that when the page is next loaded it never shows.
this code with will work perfect for you and it is the standard way provided by jquery to bind events that you want to execute only once
$(document).ready(function(){
$("div#mask").one('click', function() {
$("div#intro").fadeToggle('slow');
$("div#container").fadeToggle('slow');
$("div#mask").css("z-index", "-99");
});
});

Categories

Resources