Custom JS files conflicting with eachother - javascript

Not exactly sure how to describe this properly, but I have a feeling that my two (custom) JS files are conflicting. When I enable them both, only one of them works. If I enable them seperatly, they work perfectly.
These are the files (wrapped in Drupal JS)
The first one makes sure my navbar (a vertical navbar at the left of the screen) can be scrolled on screens smaller than the navbar, but it will become fixed if the page is longer than the navbar.
/**
* #file
* A JavaScript file for the theme.
*
* In order for this JavaScript to be loaded on pages, see the instructions in
* the README.txt next to this file.
*/
// JavaScript should be made compatible with libraries other than jQuery by
// wrapping it with an "anonymous closure". See:
// - https://drupal.org/node/1446420
// - http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth
(function ($, Drupal, window, document, undefined) {
// To understand behaviors, see https://drupal.org/node/756722#behaviors
Drupal.behaviors.my_custom_behavior = {
attach: function(context, settings) {
$( document ).ready(function() {
$(window).scroll(function(){
var navHeight = $('#left-bar').height() + 60;
var windowHeight = jQuery( window ).height();
var currentPosition = $('body').scrollTop();
console.log(currentPosition + ' ' + (navHeight - windowHeight));
if (currentPosition > (navHeight - windowHeight) - 1) {
$('#left-bar').css({'position': 'fixed', 'top': (windowHeight - navHeight)});
} else {
$('#left-bar').css({'position': 'relative', 'top': 0});
}
});
});
}
};
})(jQuery, Drupal, this, this.document);
The second one makes a certain div appear and fade out in random places on my page.
/**
* #file
* A JavaScript file for the theme.
*
* In order for this JavaScript to be loaded on pages, see the instructions in
* the README.txt next to this file.
*/
// JavaScript should be made compatible with libraries other than jQuery by
// wrapping it with an "anonymous closure". See:
// - https://drupal.org/node/1446420
// - http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth
(function ($, Drupal, window, document, undefined) {
// To understand behaviors, see https://drupal.org/node/756722#behaviors
Drupal.behaviors.my_custom_behavior = {
attach: function(context, settings) {
$( document ).ready(function() {
showRandomQuote();
setInterval(swapQuotes, 5500);
});
function showRandomQuote() {
var numItems = $('.running-quote').length;
var randomNumber = randomNumberFromRange(0, numItems-1);
var quoteToDisplay = $( ".running-quote:eq(" + randomNumber + ")" );
quoteToDisplay.addClass('displayed-quote');
randomPlacement(quoteToDisplay);
quoteToDisplay.fadeIn(800);
}
function swapQuotes() {
var quoteToHide = $('.displayed-quote');
quoteToHide.removeClass('displayed-quote');
quoteToHide.fadeOut(800, showRandomQuote);
}
function randomPlacement(element) {
var parent = element.parent().parent().parent();
var parentWidth = parent.width();
var parentHeight = parent.height();
var randomWidth = randomNumberFromRange(200, 500);
var randomXPos = randomNumberFromRange(0, parentWidth - randomWidth - 80);
var randomYPos = randomNumberFromRange(0, parentHeight - element.height() - 60);
element.width(randomWidth);
element.css({"top": randomYPos, "left": randomXPos});
}
function randomNumberFromRange(min,max) {
var randomNumber = Math.floor(Math.random()*(max-min+1)+min);
return randomNumber;
}
}
};
})(jQuery, Drupal, this, this.document);
I have absolutely no clue what would cause one of them to break the other one.
Any clues?

As #Pointy stated, your behaviors must have unique names.
General code review:
your use of $( document ).ready(function() {, from the
documentation, the attach
function behaviors is called each time an element is refresh (either
by page load or ajax), so you do not need to use jQuery.ready
function.
showRandomQuote should be inlined

Related

Run casper.evaluate() in included / external script

Introduction
I am using casperJS together with grunt-casper plugin for automating Tests for our new GUI Framework and just have a question about running jQuery / JS Code in the casper.evaluate() function to point out elements for capturing them.
First steps creating functionality
At first i build the tests a described in the casperJS HowTo like this:
casper.test.begin('LOGIN FORM TEST', function(test) {
casper.start('http://www.sample.org');
casper.waitForSelector("form.login-box",
function success() {
casper.test.assertElementCount('form.login-box > .well', 3, 'WORKS');
},
function fail() {
/* Create overlay over malicious element */
casper.evaluate(function () {
/* Get boundaries of malicous element */
var buffer = 6;
var height = $(selector).height() + buffer + "px";
var width = $(selector).width() + "px";
var position = $(selector).offset();
var posX = position.left + "px";
var posY = position.top + buffer + "px";
/* Add a overlay which matches the element and overlays it */
$("body").append("<div id='errormarker'></div>");
$("#errormarker")
.css({
'opacity': 0.4,
'position': 'absolute',
'top': posY,
'left': posX,
'height': height,
'width': width,
'background-color': '#f00',
'z-index': 5000
});
});
casper.test.fail('NOT COOL');
}, 200);
casper.capture('image.png');
casper.run(function() {
test.done();});
});
This worked fine, at first i created a DIV which has the measurements and position of the malicious element. Could be verified on the screenshot.
Second step make it a general UtilFunction
But as i have a lot of tests which need this functionality for taking a screenshot when a test fails, i assumed to create a Utils.js, include it to the script and call the function with parameters whenever i need it so i created this:
Gruntfile (because i use grunt-casper the include of the script is here, its just a simple include nothing specific)
casper: {
MyTest: {
options: {
includes: ['tests/testutils/Testutils.js']
Testutils.js
/**
* Constructor of TestingUtils
* #constructor
*/
function Testutils() {}
/**
* Function for creating a Screenshot with a marked malicious element for logging erroneous created objects
* #param selector CSS selector of the element
* #param pathForScreenshot the path where the screenshots are stored
* #param casper the casper test object
* #param screenshotName the name of the Screenshot which has to be created
*/
Testutils.prototype.createErrorScreenshot = function (selector, pathForScreenshot, casper, screenshotName) {
/* Set thin border around malicous element */
casper.evaluate(function () {
/* Get boundaries of malicous element */
var buffer = 6;
var height = $(selector).height() + buffer + "px";
var width = $(selector).width() + "px";
var position = $(selector).offset();
var posX = position.left + "px";
var posY = position.top + buffer + "px";
/* Add a overlay which matches the element and overlays it */
$("body").append("<div id='errormarker'></div>");
$("#errormarker")
.css({
'opacity': 0.4,
'position': 'absolute',
'top': posY,
'left': posX,
'height': height,
'width': width,
'background-color': '#f00',
'z-index': 5000
});
});
/* screenshot the whole screen with marker element */
casper.capture(pathForScreenshot + screenshotName);
/* Cleanup the content from marker */
casper.evaluate(function () {
$('#errormarker').remove();
});
/* Create specific screenshot of the element */
casper.captureSelector(pathForScreenshot + screenshotName, selector);
};
Calling the Function in Test.js
casper.test.begin('LOGIN FORM TEST', function(test) {
casper.start('http://www.sample.org');
casper.waitForSelector("form.login-box",
function success() {
casper.test.assertElementCount('form.login-box > .well', 3, 'WORKS');
},
function fail() {
/* THIS HERE IS NEW */
var testutils = new Testutils();
actUtils.createErrorScreenshot('form.login-box > .well > .form-group:nth-child(1)', tempCaptureFolder, casper, 'image.png');
});
casper.test.fail('NOT COOL');
}, 200);
casper.capture('image.png');
casper.run(function() {
test.done();});
});
Problem now
The casper specific functions (casper.capture) work in the included js file, BUT casper.evaluate is not run....never, i debugged and logged this but i cannot use this functionality here.
So my question is, what can i do here? I need to use jQuery functionality here and especially evaluate for marking the DOM content before screenshotting it.
I think it has to do with the following mechanism how evaluate works:
http://docs.casperjs.org/en/1.1-beta2/_images/evaluate-diagram.png
I would be very very glad if someone can help me here.
Next steps
I now went on and no errors are provided. Another problem occurred and i am wondering what happens here.
But now magically casper.evaluate is entered, but i got errors that the parameters
var height = $(selector).height() + buffer + "px";
var width = $(selector).width() + "px";
var position = $(selector).offset();
var posX = position.left + "px";
var posY = position.top + buffer + "px";
could not be initialised, o.e. the $(selector) returned NULL, so i tried to get the HTML context and when i got the DOM with jQuery i got the following output:
<html><head></head><body></body></html>
so the content is empty.
SSL Problem?
Now i know the problem with SSL and Casper and as i said when i ran the casper.evaluate in the function calling script it worked fine because i set the params
args: ['--ssl-protocol=any', '--ignore-ssl-errors=true', '--web-security=no']
in GRUNT configuration.
Wrong page?
Now i thought that i am on the wrong website so i got the URL from casper.getCurrentUrl() and it is the the correct URL, so i took a capture inside of the evaluate() function, and the screenshot was correct too what proved that i am on the correct page.
But as i said the gotten HTML Content is empty, so what can i do here?
I think it must be a small problem, maybe with the sandboxed content, i do not have a concrete idea here.

jQuery - Changing function parameters based on breakpoints

Pretty new to jquery so bear with me. I’ve got two functions, one that is intended to be used on desktop and one that is used at the tablet breakpoint. They both check for the length of a particular DOM element and pass in the width as a parameter. I’ve got another function that currently calls only one of the functions but is there a way to somehow pass in one or the other based on if they are at the tablet or mobile breakpoint? You can see in the setWidth function it's using the calculateDesktop function. I could create two different functions to do this but that would seem redundant. Kind of a newb to jquery please include code samples as necessary.
function calculateDesktop(width) {
var desktop= $('.header-item').length;
return width * ($('.header-section').length - desktop);
}
function calculateTablet(width) {
var tablet = $('.header-item.tablet-none').length;
return width * ($('.header-section').length - tablet);
}
function setWidth() {
$('.expand .main-section').each(function() {
var headerClass = $(this).closest('.header-item')).filter(function(it){
return it.match(/^width-/); });
var width = headerClass ? headerClass[0].split('-')[1] : 75;
$(this).css("width", calculateDesktop(width) + "%");
});
}
SUDO CODE (doesn't work, but something I'm looking to achieve)
if ($(window).width() <= 768) {
setWidth(calculateTablet)
} else {
//desktop goes here
setWidth(calculateDesktop)
}
You can pass the function reference as you have done then invoke that function reference to get the width
function setWidth(fn) {
$('.expand .main-section').each(function () {
var headerClass = $(this).closest('.header-item').filter(function (it) {
return it.match(/^width-/);
});
var width = headerClass ? headerClass[0].split('-')[1] : 75;
$(this).css("width", fn(width) + "%");
});
}
if ($(window).width() <= 768) {
setWidth(calculateTablet)
} else {
//desktop goes here
setWidth(calculateDesktop)
}

Jquery .height() not working until resize of window

I'm using this code to resize a div on my page:
function sizeContent() {
var newHeight = ($("html").height() - $(".header").height() -3) + "px";
$(".content").height(newHeight);
}
I am triggering this using:
$(window).resize(sizeContent());
But I also call it inside
$(document).ready(sizeContent());
to set all the heights properly.
If i resize the browser window by dragging at its borders it works great.
But the initial call does not seem to have any effect. Putting an alert inside the sizeContent function I can see that it is being called at page ready, and is setting the right height, but nothing is changed on the page.
It's as if the browser does not recognize that it needs to redraw anything unless the window itself is changed.
Solved:
In the end it was not the javascript that was the problem, using div's with display:table and display:table-row was causing it. Removed these from the css and everything worked.
// If you put your code at the bottom of the page to avoid needing`$(document).ready`, it gets even simpler:
$(window).on('resize', function () {
var newheight = ($(window).height() - $('.header').height() - 3);
$(".content").css("height", newheight);
}).trigger('resize');
// Another way to do that same thing
$(document).ready(sizeContent);
$(window).on('resize', sizeContent);
function sizeContent() {
var newheight = ($(window).height() - $('.header').height() - 3);
$(".content").css("height", newheight);
}
// Another technique is to`.trigger()`one event inside the other:
$(window).on('resize', function () {
var newheight = ($(window).height() - $('.header').height() - 3);
$(".content").css("height", newheight);
});
$(document).ready(function () {
$(window).trigger('resize');
});
Replace
$(".content").css({height:newHeight}) //replace this
with
(".content").height(newHeight);
Use below code:
function sizeContent() {
var newHeight = ($(window).height() - $(".header").css('height')-3) ;
$(".content").css('height',newHeight);
}

Synchronized scrolling using jQuery?

I am trying to implement synchronized scrolling for two DIV with the following code.
DEMO
$(document).ready(function() {
$("#div1").scroll(function () {
$("#div2").scrollTop($("#div1").scrollTop());
});
$("#div2").scroll(function () {
$("#div1").scrollTop($("#div2").scrollTop());
});
});
#div1 and #div2 is having the very same content but different sizes, say
#div1 {
height : 800px;
width: 600px;
}
#div1 {
height : 400px;
width: 200px;
}
With this code, I am facing two issues.
1) Scrolling is not well synchronized, since the divs are of different sizes. I know, this is because, I am directly setting the scrollTop value. I need to find the percentage of scrolled content and calculate corresponding scrollTop value for the other div. I am not sure, how to find the actual height and current scroll position.
2) This issue is only found in firefox. In firefox, scrolling is not smooth as in other browsers. I think this because the above code is creating a infinite loop of scroll events.
I am not sure, why this is only happening with firefox. Is there any way to find the source of scroll event, so that I can resolve this issue.
Any help would be greatly appreciated.
You can use element.scrollTop / (element.scrollHeight - element.offsetHeight) to get the percentage (it'll be a value between 0 and 1). So you can multiply the other element's (.scrollHeight - .offsetHeight) by this value for proportional scrolling.
To avoid triggering the listeners in a loop you could temporarily unbind the listener, set the scrollTop and rebind again.
var $divs = $('#div1, #div2');
var sync = function(e){
var $other = $divs.not(this).off('scroll'), other = $other.get(0);
var percentage = this.scrollTop / (this.scrollHeight - this.offsetHeight);
other.scrollTop = percentage * (other.scrollHeight - other.offsetHeight);
// Firefox workaround. Rebinding without delay isn't enough.
setTimeout( function(){ $other.on('scroll', sync ); },10);
}
$divs.on( 'scroll', sync);
http://jsfiddle.net/b75KZ/5/
Runs like clockwork (see DEMO)
$(document).ready(function(){
var master = "div1"; // this is id div
var slave = "div2"; // this is other id div
var master_tmp;
var slave_tmp;
var timer;
var sync = function ()
{
if($(this).attr('id') == slave)
{
master_tmp = master;
slave_tmp = slave;
master = slave;
slave = master_tmp;
}
$("#" + slave).unbind("scroll");
var percentage = this.scrollTop / (this.scrollHeight - this.offsetHeight);
var x = percentage * ($("#" + slave).get(0).scrollHeight - $("#" + slave).get(0).offsetHeight);
$("#" + slave).scrollTop(x);
if(typeof(timer) !== 'undefind')
clearTimeout(timer);
timer = setTimeout(function(){ $("#" + slave).scroll(sync) }, 200)
}
$('#' + master + ', #' + slave).scroll(sync);
});
This is what I'm using. Just call the syncScroll(...) function with the two elements you want to synchronize. I found pawel's solution had issues with continuing to slowly scroll after the mouse or trackpad was actually done with the operation.
See working example here.
// Sync up our elements.
syncScroll($('.scroll-elem-1'), $('.scroll-elem-2'));
/***
* Synchronize Scroll
* Synchronizes the vertical scrolling of two elements.
* The elements can have different content heights.
*
* #param $el1 {Object}
* Native DOM element or jQuery selector.
* First element to sync.
* #param $el2 {Object}
* Native DOM element or jQuery selector.
* Second element to sync.
*/
function syncScroll(el1, el2) {
var $el1 = $(el1);
var $el2 = $(el2);
// Lets us know when a scroll is organic
// or forced from the synced element.
var forcedScroll = false;
// Catch our elements' scroll events and
// syncronize the related element.
$el1.scroll(function() { performScroll($el1, $el2); });
$el2.scroll(function() { performScroll($el2, $el1); });
// Perform the scroll of the synced element
// based on the scrolled element.
function performScroll($scrolled, $toScroll) {
if (forcedScroll) return (forcedScroll = false);
var percent = ($scrolled.scrollTop() /
($scrolled[0].scrollHeight - $scrolled.outerHeight())) * 100;
setScrollTopFromPercent($toScroll, percent);
}
// Scroll to a position in the given
// element based on a percent.
function setScrollTopFromPercent($el, percent) {
var scrollTopPos = (percent / 100) *
($el[0].scrollHeight - $el.outerHeight());
forcedScroll = true;
$el.scrollTop(scrollTopPos);
}
}
If the divs are of equal sizes then this code below is a simple way to scroll them synchronously:
scroll_all_blocks: function(e) {
var scrollLeft = $(e.target)[0].scrollLeft;
var len = $('.scroll_class').length;
for (var i = 0; i < len; i++)
{
$('.scroll_class')[i].scrollLeft = scrollLeft;
}
}
Here im using horizontal scroll, but you can use scrollTop here instead. This function is call on scroll event on the div, so the e will have access to the event object.
Secondly, you can simply have the ratio of corresponding sizes of the divs calculated to apply in this line $('.scroll_class')[i].scrollLeft = scrollLeft;
I solved the sync scrolling loop problem by setting the scroll percentage to fixed-point notation: percent.toFixed(0), with 0 as the parameter. This prevents mismatched fractional scrolling heights between the two synced elements, which are constantly trying to "catch up" with each other. This code will let them catch up after at most a single extra step (i.e., the second element may continue to scroll an extra pixel after the user stops scrolling). Not a perfect solution or the most sophisticated, but certainly the simplest I could find.
var left = document.getElementById('left');
var right = document.getElementById('right');
var el2;
var percentage = function(el) { return (el.scrollTop / (el.scrollHeight - el.offsetHeight)) };
function syncScroll(el1) {
el1.getAttribute('id') === 'left' ? el2 = right : el2 = left;
el2.scrollTo( 0, (percentage(el1) * (el2.scrollHeight - el2.offsetHeight)).toFixed(0) ); // toFixed(0) prevents scrolling feedback loop
}
document.getElementById('left').addEventListener('scroll',function() {
syncScroll(this);
});
document.getElementById('right').addEventListener('scroll',function() {
syncScroll(this);
});
I like pawel's clean solution but it lacks something I need and has a strange scrolling bug where it continues to scroll and my plugin will work on multiple containers not just two.
http://www.xtf.dk/2015/12/jquery-plugin-synchronize-scroll.html
Example & demo: http://trunk.xtf.dk/Project/ScrollSync/
Plugin: http://trunk.xtf.dk/Project/ScrollSync/jquery.scrollSync.js
$('.scrollable').scrollSync();
If you don't want proportional scrolling, but rather to scroll an equal amount of pixels on each field, you could add the value of change to the current value of the field you're binding the scroll-event to.
Let's say that #left is the small field, and #right is the bigger field.
var oldRst = 0;
$('#right').on('scroll', function () {
l = $('#left');
var lst = l.scrollTop();
var rst = $(this).scrollTop();
l.scrollTop(lst+(rst-oldRst)); // <-- like this
oldRst = rst;
});
https://jsfiddle.net/vuvgc0a8/1/
By adding the value of change, and not just setting it equal to #right's scrollTop(), you can scroll up or down in the small field, regardless of its scrollTop() being less than the bigger field. An example of this is a user page on Facebook.
This is what I needed when I came here, so I thought I'd share.
From the pawel solution (first answer).
For the horizzontal synchronized scrolling using jQuery this is the solution:
var $divs = $('#div1, #div2'); //only 2 divs
var sync = function(e){
var $other = $divs.not(this).off('scroll');
var other = $other.get(0);
var percentage = this.scrollLeft / (this.scrollWidth - this.offsetWidth);
other.scrollLeft = percentage * (other.scrollWidth - other.offsetWidth);
setTimeout( function(){ $other.on('scroll', sync ); },10);
}
$divs.on('scroll', sync);
JSFiddle
An other solution for multiple horizontally synchronized divs is this, but it works for divs with same width.
var $divs = $('#div1, #div2, #div3'); //multiple divs
var sync = function (e) {
var me = $(this);
var $other = $divs.not(me).off('scroll');
$divs.not(me).each(function (index) {
$(this).scrollLeft(me.scrollLeft());
});
setTimeout(function () {
$other.on('scroll', sync);
}, 10);
}
$divs.on('scroll', sync);
NB: Only for divs with same width
JSFiddle

infinite-scroll jquery plugin

I am trying to set up infinite-scroll on a site I am developing with Coldfusion, I am new to javascript and jquery so I am having some issues wrapping my head around all of this. Do I need to have pagination on my site in order to use the infinite-scroll plugin, or is there a way to do it with out it?
You do not need infinite scroll plug-in for this. To detect when scroll reaches end of page, with jQuery you can do
$(window).scroll(function () {
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 10) {
//Add something at the end of the page
}
});
Demo on JsFiddle
I'm using Hussein's answer with AJAX requests. I modified the code to trigger at 300px instead of 10px, but it started causing my appends to multiply before the AJAX request was finished since the scroll call triggers much more frequently in a 300px range than a 10px range.
To fix this, I added a trigger that would be flipped on successful AJAX load. My code looks more like this:
var scrollLoad = true;
$(window).scroll(function () {
if (scrollLoad && $(window).scrollTop() >= $(document).height() - $(window).height() - 300) {
scrollLoad = false;
//Add something at the end of the page
}
});
then in my AJAX response, I set scrollLoad to true.
I built on top of Hussein's little example here to make a jQuery widget. It supports localStorage to temporarily save appended results and it has pause functionality to stop the appending every so often, requiring a click to continue.
Give it a try:
http://www.hawkee.com/snippet/9445/
$(function(){
$(window).scroll(function(){
if($(document).height()<=$(window).scrollTop()+$(window).height()+100){
alert('end of page');
}
});
});
Some one asked for explanation so here is the explanation
here $(document).height()-->is the height of the entire document.In most cases, this is equal to the element of the current document.
$(window).height()-->is the height of the window (browser) means height of whatever you are seeing on browser.
$(window).scrollTop()-->The Element.scrollTop property gets or sets the number of pixels that the content of an element is scrolled upward. An element's scrollTop is a measurement of the distance of an element's top to its topmost visible content. When an element content does not generate a vertical scrollbar, then its scrollTop value defaults to 0.
$(document).height()<=$(window).scrollTop()+$(window).height()+100
add $(window).scrollTop() with $(window).height() now check whether the result is equal to your documnet height or not. if it is equal means you reached at the end.we are adding 100 too because i want to check before the 100 pixels from the bottom of document(note <= in condition)
please correct me if i am wrong
I had same problem but didn't find suitable plugin for my need. so I wrote following code. this code appends template to element by getting data with ajax and pagination.
for detecting when user scrolls to bottom of div I used this condition:
var t = $("#infiniteContent").offset().top;
var h = $("#infiniteContent").height();
var ws = $(window).scrollTop();
var dh = $(document).height();
var wh = $(window).height();
if (dh - (wh + ws) < dh - (h + t)) {
//now you are at bottom of #infiniteContent element
}
$(document).ready(function(){
$.getJSON("https://jsonplaceholder.typicode.com/comments", { _page: 1, _limit:3 }, function (jsonre) {
appendTemplate(jsonre,1);
});
});
function appendTemplate(jsonre, pageNumber){
//instead of this code you can use a templating plugin like "Mustache"
for(var i =0; i<jsonre.length; i++){
$("#infiniteContent").append("<div class='item'><h2>"+jsonre[i].name+"</h2><p>"+jsonre[i].body+"</p></div>");
}
if (jsonre.length) {
$("#infiniteContent").attr("data-page", parseInt(pageNumber)+1);
$(window).on("scroll", initScroll);
//scroll event will not trigger if window size is greater than or equal to document size
var dh = $(document).height() , wh = $(window).height();
if(wh>=dh){
initScroll();
}
}
else {
$("#infiniteContent").attr("data-page", "");
}
}
function initScroll() {
var t = $("#infiniteContent").offset().top;
var h = $("#infiniteContent").height();
var ws = $(window).scrollTop();
var dh = $(document).height();
var wh = $(window).height();
if (dh - (wh + ws) < dh - (h + t)) {
$(window).off('scroll');
var p = $("#infiniteContent").attr("data-page");
if (p) {
$.getJSON("https://jsonplaceholder.typicode.com/comments", { _page: p, _limit:3 }, function (jsonre) {
appendTemplate(jsonre, p);
});
}
}
}
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<div id="infiniteContent"></div>
If you have a scrollable element, like a div with scroll overflow, but no scrollable document/page, you can take this way.
$(function () {
var s = $(".your-scrollable-element");
var list = $("#your-table-list");
/* On element scroll */
s.scroll(function () {
/* The scroll top plus element height equals to table height */
if ((s.scrollTop() + s.height()) == list.height()) {
/* you code */
}
});
});
I wrote this function using Hussein and Nick's ideas, but I wanted it to use promises for the callback. I also wanted the infinite scrolling area to be on a fixed div and not just the window if the div is sent into the options object. There is an example of that in my second link below. I suggest using a promise library like Q if you want to support older browsers. The cb method may or may not be a promise and it will work regardless.
It is used like so:
html
<div id="feed"></div>
js
var infScroll = infiniteScroll({
cb: function () {
return doSomethingPossiblyAnAJAXPromise();
}
});
If you want the feed to temporarily stop you can return false in the cb method. Useful if you have hit the end of the feed. It can be be started again by calling the infiniteScroll's returned object method 'setShouldLoad' and passing in true and example to go along with the above code.
infScroll.setShouldLoad(true);
The function for infinite scrolling is this
function infiniteScroll (options) {
// these options can be overwritten by the sent in options
var defaultOptions = {
binder: $(window), // parent scrollable element
loadSpot: 300, //
feedContainer: $("#feed"), // container
cb: function () { },
}
options = $.extend(defaultOptions, options);
options.shouldLoad = true;
var returnedOptions = {
setShouldLoad: function (bool) { options.shouldLoad = bool; if(bool) { scrollHandler(); } },
};
function scrollHandler () {
var scrollTop = options.binder.scrollTop();
var height = options.binder[0].innerHeight || options.binder.height();
if (options.shouldLoad && scrollTop >= (options.binder[0].scrollHeight || $(document).height()) - height - options.loadSpot) {
options.shouldLoad = false;
if(typeof options.cb === "function") {
new Promise(function (resolve) {resolve();}).then(function() { return options.cb(); }).then(function (isNotFinished) {
if(typeof isNotFinished === "boolean") {
options.shouldLoad = isNotFinished;
}
});
}
}
}
options.binder.scroll(scrollHandler);
scrollHandler();
return returnedOptions;
}
1 feed example with window as scroller
2 feed example with feed as scroller

Categories

Resources