ngInfiniteScroll "load next page" function being called repeatedly - javascript

Using the "loading remote data" example from the ngInfiniteScroll website I have tried to implement infinite scrolling. My issue;
The function nextPage() gets called continuously until there are no more records left to load (controlled by an offset value in the SQL query).
I'd appreciate any input on this as I'm rather lost.
Thanks in advance.
HTML
<tbody>
<div id="infinite_scroll" infinite-scroll='visits.nextPage()' infinite-scroll-disabled='visits.busy' infinite-scroll-distance='1'>
<tr ng-repeat="visit in visits.items" ng-class="{active: visit.uuid == data.detailItem.uuid}" ng-click="openDetailItem(visit.uuid)">
<td>{{visit.details.name}}</td>
<td>{{visit.created_at}}</td>
</tr>
</div>
</tbody>
Javascript - AngularJs Factory
angular.module('app').factory('Visits', function(VisitResource) {
// new visits object
var Visits = function () {
this.items = [];
this.busy = false;
this.offset = 0;
};
Visits.prototype.nextPage = function () {
// busy - stop
if (this.busy == true) {
// DEBUG
console.log('busy test 1.1: ' + this.busy);
return;
} else {
// DEBUG
console.log('busy test 1.2: ' + this.busy);
}
// busy now
this.busy = true;
VisitResource.getVisitations({
limit: 500,
offset: this.offset
}, function (response) {
// stop loading if no data returned
if(response.data.length == 0) {
// DEBUG
console.log('busy test 2: ' + this.busy);
return;
} else {
// DEBUG
console.log('Payload: ' + response.data.length);
}
var _this = this;
angular.forEach(response.data, function (a_visit) {
_this.items.push(a_visit);
});
// set the last acquired record value
this.offset = this.items[this.items.length - 1].id;
// not busy
this.busy = false;
}.bind(this));
};
return Visits;
});

As it turns out you can't get vanilla nginfinitescroll to trigger when the container is scrolled as nginfinitescroll is looking at the height of the window.
Here is a link to the answer on SO:
angularjs infinite scroll in a container

Related

consume events in the right order

Im using channel's of pusher in a Laravel application.
So when im fired an event from my controller this is received to my client, and with the pusher function I add some text with this lib https://github.com/albburtsev/jquery.typist on my front page:
channel.bind('App\\Events\\TextAdded', function(data) {
if(data.txt){
printPhrase(data.txt);
i++;
}
});
function printPhrase(txt) {
$('<span>')
.addClass('txt_' + i)
.appendTo('.typist_dialog')
.typist({
text:txt,
speed: 15,
}).on('end_type.typist', function() {
console.log('end') ;
}).typistStop() ;
}
});
As you can see I can catch the event "end_type" (when the function stop writing).
The problem is that i cannot -or I've no idea howto- puts "channel.bind" on queue, and so waiting untill that the printPhrase(txt) is finished... so not showing more than one printing for time at screen...
You'll have to set up some sort of queue to make sure they don't fire until the previous one is done. This code isn't tested but should do the trick:
var printQueue = [];
var queueWorking = false;
channel.bind('App\\Events\\TextAdded', function(data) {
if(data.txt){
printQueue.push(data.txt);
workQueue();
}
});
function printPhrase(txt) {
i++;
$('<span>')
.addClass('txt_' + i)
.appendTo('.typist_dialog')
.typist({
text:txt,
speed: 15,
}).on('end_type.typist', function() {
queueWorking = false;
workQueue();
}).typistStop() ;
}
function workQueue(){
if(printQueue.length && !queueWorking){
queueWorking = true;
printPhrase(printQueue.shift());
}
}

How to handle click event being called multiple times with jquery animation?

I have a click event that has a Jquery animation in it.
How can i guarantee that the animation has finished when multiple click events are being fired.
$(this._ScrollBarTrack).click(function(e) {
if(e.target === this && _self._horizontalClickScrollingFlag === false){
_self._horizontalClickScrollingFlag = true;
if(_self._isVertical){
} else{ //horizontal
if(e.offsetX > (this.firstChild.offsetWidth + this.firstChild.offsetLeft)){ // Moving Towards Right
var scrollableAmountToMove = _self._arrayOfCellSizes[_self._scrollBarCurrentStep + 1]; // additional amount to move
var scrollableCurrentPosition = -($(_self._bodyScrollable).position().left);
var scrollBarCurrentPosition = $(_self._ScrollBarTrackPiece).position().left;
var scrollBarAmountToMove = _self.getScrollBarTrackPiecePositionBasedOnScrollablePosition(scrollableAmountToMove);
$(".event-scroll-horizontally").animate({left:-(scrollableCurrentPosition+ scrollableAmountToMove)});
$(_self._ScrollBarTrackPiece).animate({left: (scrollBarCurrentPosition + scrollBarAmountToMove)});
_self._scrollBarCurrentStep += 1;
} else{
var scrollableAmountToMove = _self._arrayOfCellSizes[_self._scrollBarCurrentStep - 1]; // additional amount to move
var scrollableCurrentPosition = -($(_self._bodyScrollable).position().left);
var scrollBarCurrentPosition = $(_self._ScrollBarTrackPiece).position().left;
var scrollBarAmountToMove = _self.getScrollBarTrackPiecePositionBasedOnScrollablePosition(scrollableAmountToMove);
$(".event-scroll-horizontally").animate({left:-(scrollableCurrentPosition - scrollableAmountToMove)});
$(_self._ScrollBarTrackPiece).animate({left: (scrollBarCurrentPosition - scrollBarAmountToMove)});
_self._scrollBarCurrentStep -= 1;
}
}
_self._horizontalClickScrollingFlag = false;
}
});
jQuery has a hidden (I'm not sure why it's not in the docs someplace) variable $.timers that you can test against.
I made this function a long time ago to handle situations like this. Mind you, this will test to make sure there are NO animations currently being executed.
function animationsTest (callback) {
var testAnimationInterval = setInterval(function () {
if ($.timers.length === 0) { // any page animations finished
clearInterval(testAnimationInterval);
callback(); // callback function
}
}, 25);
};
Useage: jsFiddle DEMO
animationsTest(function () {
/* your code here will run when no animations are occuring */
});
If you want to test against one individually you could do a class/data route.
$('#thing').addClass('animating').animate({ left: '+=100px' }, function () {
// your callback when the animation is finished
$(this).removeClass('animating');
});
You could declare a global boolean called isAnimating and set it to true right when you begin the animation. Then add a done or complete function to the animation that sets it back to false. Then set your click event to only begin the animation if isAnimating is false.

ng-grid infinite scroll - ngGridEventScroll emited twice

I try to implement infinite scrolling grid based on ngGridEventScroll event. But I have it emited twice every time I scroll to the bottom of grid.
Here's my code for update data ($scope.mydata is used as source for grid):
$scope.$on('ngGridEventScroll', function () {
chunkStart += chunkSize;
$http.get('/api/mydata/' + chunkStart + '/' + chunkSize)
.success(function(mydata) {
$scope.mydata = $scope.mydata.concat(mydata);
});
});
Where's my mistake, can you give me any advice?
I had similar problem, here's my solution:
$scope.load = true;
$scope.$on('ngGridEventScroll', function() {
if ($scope.load) {
$scope.load = false;
$http.get('your/url/here')
.success(function(data) {
//operations here
$timeout(function() {
//or here
$scope.load = true;
});
});
}
});
I used $scope.load flag to indicate when to load data and angular $timeout() function fix time-related issues.

not able to scrape anything from lenskart website

I'm trying to scrape some product information from the site http://www.lenskart.com/eyeglasses/frame-style/half-rim.html using phantomjs. Below is the script I have used:
var page = require('webpage').create();
page.onConsoleMessage = function(msg){
console.log(msg);
};
page.open('http://www.lenskart.com/eyeglasses/frame-style/half-rim.html', function () {
console.log('1234');
// Checks for bottom div and scrolls down from time to time
window.setInterval(function() {
console.log('ddddddddddd');
// Checks if there is a div with class=".has-more-items"
// (not sure if this is the best way of doing it)
var count = page.evaluate(function() {
try{
return document.getElementsByClassName('top-to-bottom')[0].style.display;
}catch(e){return e.message;}
});
//count = 1
console.log(count);
console.log('1111 '+count);
if(count === 'block' || count ==='inline' ) { // Didn't find
console.log('count '+count);
//this.echo('wdc');
page.evaluate(function() {
// Scrolls to the bottom of page
window.document.body.scrollTop = document.body.scrollHeight;
});
}
else
{ // Found
//Do what you want
console.log('len123');
try {
var links = page.evaluate(function() {
return [].map.call(document.querySelectorAll('div.product-view-region a.product-image'), function(link) {
//console.log(link.getAttribute('href'));
return link.getAttribute('href');
});
});
} catch (e) {
console.log(e.message); return [];
}
//console.log(links.join(','));
//console.log(links);
phantom.exit();
}
}, 1000); // Number o ms to wait between scrolls
});
But I am continuosly getting this error:
TypeError: 'undefined' is not a function (evaluating 'this.each(function(value,i
ndex){results.push(iterator.call(context,value,index));})')
http://d37l6i9uhpr090.cloudfront.net/js/top_common.js:809 in collect
phantomjs://webpage.evaluate():6
phantomjs://webpage.evaluate():7
phantomjs://webpage.evaluate():7
null
I also tried to scrape some other information but got the same result. I don't understand where am I going wrong!

NEED HELP. Author has abandoned to fix this jQuery plugin!

I am trying to implemented this jQuery news ticker style plugin from http://www.makemineatriple.com/2007/10/bbcnewsticker
Like mentioned in the comments (around May) there is a bug and the author lost its will to give a bug fix.
The bug is:
In Mac browsers (Firefox, Opera and Safari, all OSX) - links (a href) don’t ‘work’ until each list item has finished scrolling/revealing. Basically after this plugin has loaded, all the a href stops working.
Here is the code for the plugin (http://plugins.jquery.com/project/BBCnewsTicker):
/*
News ticker plugin (BBC news style)
Bryan Gullan,2007-2010
version 2.2
updated 2010-04-04
Documentation at http://www.makemineatriple.com/news-ticker-documentation/
Demo at http://www.makemineatriple.com/jquery/?newsTicker
Use and distrubute freely with this header intact.
*/
(function($) {
var name='newsTicker';
function runTicker(settings) {
tickerData = $(settings.newsList).data('newsTicker');
if(tickerData.currentItem > tickerData.newsItemCounter){
// if we've looped to beyond the last item in the list, start over
tickerData.currentItem = 0;
}
else if (tickerData.currentItem < 0) {
// if we've looped back before the first item, move to the last one
tickerData.currentItem = tickerData.newsItemCounter;
}
if(tickerData.currentPosition == 0) {
if(tickerData.newsLinks[tickerData.currentItem].length > 0) {
$(tickerData.newsList).empty().append('<li></li>');
}
else {
$(tickerData.newsList).empty().append('<li></li>');
}
}
//only start the ticker itself if it's defined as animating: otherwise it's paused or under manual advance
if (tickerData.animating) {
if( tickerData.currentPosition % 2 == 0) {
var placeHolder = tickerData.placeHolder1;
}
else {
var placeHolder = tickerData.placeHolder2;
}
if( tickerData.currentPosition < tickerData.newsItems[tickerData.currentItem].length) {
// we haven't completed ticking out the current item
var tickerText = tickerData.newsItems[tickerData.currentItem].substring(0,tickerData.currentPosition);
if(tickerData.newsLinks[tickerData.currentItem].length > 0) {
$(tickerData.newsList + ' li a').text(tickerText + placeHolder);
}
else {
$(tickerData.newsList + ' li').text(tickerText + placeHolder);
}
tickerData.currentPosition ++;
setTimeout(function(){runTicker(settings); settings = null;},tickerData.tickerRate);
}
else {
// we're on the last letter of the current item
if(tickerData.newsLinks[tickerData.currentItem].length > 0) {
$(tickerData.newsList + ' li a').text(tickerData.newsItems[tickerData.currentItem]);
}
else {
$(tickerData.newsList + ' li').text(tickerData.newsItems[tickerData.currentItem]);
}
setTimeout(function(){
if (tickerData.animating) {
tickerData.currentPosition = 0;
tickerData.currentItem ++;
runTicker(settings); settings = null;
}
},tickerData.loopDelay);
}
}
else {// settings.animating == false
// display the full text of the current item
var tickerText = tickerData.newsItems[tickerData.currentItem];
if(tickerData.newsLinks[tickerData.currentItem].length > 0) {
$(tickerData.newsList + ' li a').text(tickerText);
}
else {
$(tickerData.newsList + ' li').text(tickerText);
}
}
}
// Core plugin setup and config
jQuery.fn[name] = function(options) {
// Add or overwrite options onto defaults
var settings = jQuery.extend({}, jQuery.fn.newsTicker.defaults, options);
var newsItems = new Array();
var newsLinks = new Array();
var newsItemCounter = 0;
// Hide the static list items
$(settings.newsList + ' li').hide();
// Store the items and links in arrays for output
$(settings.newsList + ' li').each(function(){
if($(this).children('a').length) {
newsItems[newsItemCounter] = $(this).children('a').text();
newsLinks[newsItemCounter] = $(this).children('a').attr('href');
}
else {
newsItems[newsItemCounter] = $(this).text();
newsLinks[newsItemCounter] = '';
}
newsItemCounter ++;
});
var tickerElement = $(settings.newsList); // for quick reference below
tickerElement.data(name, {
newsList: settings.newsList,
tickerRate: settings.tickerRate,
startDelay: settings.startDelay,
loopDelay: settings.loopDelay,
placeHolder1: settings.placeHolder1,
placeHolder2: settings.placeHolder2,
controls: settings.controls,
ownControls: settings.ownControls,
stopOnHover: settings.stopOnHover,
newsItems: newsItems,
newsLinks: newsLinks,
newsItemCounter: newsItemCounter - 1, // -1 because we've incremented even after the last item (above)
currentItem: 0,
currentPosition: 0,
firstRun:1
})
.bind({
stop: function(event) {
// show remainder of the current item immediately
tickerData = tickerElement.data(name);
if (tickerData.animating) { // only stop if not already stopped
tickerData.animating = false;
}
},
play: function(event) {
// show 1st item with startdelay
tickerData = tickerElement.data(name);
if (!tickerData.animating) { // if already animating, don't start animating again
tickerData.animating = true;
setTimeout(function(){runTicker(tickerData); tickerData = null;},tickerData.startDelay);
}
},
resume: function(event) {
// start from next item, with no delay
tickerData = tickerElement.data(name);
if (!tickerData.animating) { // if already animating, don't start animating again
tickerData.animating = true;
// set the character position as 0 to ensure on resume we start at the right point
tickerData.currentPosition = 0;
tickerData.currentItem ++;
runTicker(tickerData); // no delay when resuming.
}
},
next: function(event) {
// show whole of next item
tickerData = tickerElement.data(name);
// stop (which sets as non-animating), and call runticker
$(tickerData.newsList).trigger("stop");
// set the character position as 0 to ensure on resume we start at the right point
tickerData.currentPosition = 0;
tickerData.currentItem ++;
runTicker(tickerData);
},
previous: function(event) {
// show whole of previous item
tickerData = tickerElement.data(name);
// stop (which sets as non-animating), and call runticker
$(tickerData.newsList).trigger("stop");
// set the character position as 0 to ensure on resume we start at the right point
tickerData.currentPosition = 0;
tickerData.currentItem --;
runTicker(tickerData);
}
});
if (settings.stopOnHover) {
tickerElement.bind({
mouseover: function(event) {
tickerData = tickerElement.data(name);
if (tickerData.animating) { // stop if not already stopped
$(tickerData.newsList).trigger("stop");
if (tickerData.controls) { // ensure that the ticker can be resumed if controls are enabled
$('.stop').hide();
$('.resume').show();
}
}
}
});
}
tickerData = tickerElement.data(name);
// set up control buttons if the option is on
if (tickerData.controls || tickerData.ownControls) {
if (!tickerData.ownControls) {
$('<ul class="ticker-controls"><li class="play">Play</li><li class="resume">Resume</li><li class="stop">Stop</li><li class="previous">Previous</li><li class="next">Next</li></ul>').insertAfter($(tickerData.newsList));
}
$('.play').hide();
$('.resume').hide();
$('.play').click(function(event){
$(tickerData.newsList).trigger("play");
$('.play').hide();
$('.resume').hide();
$('.stop').show();
event.preventDefault();
});
$('.resume').click(function(event){
$(tickerData.newsList).trigger("resume");
$('.play').hide();
$('.resume').hide();
$('.stop').show();
event.preventDefault();
});
$('.stop').click(function(event){
$(tickerData.newsList).trigger("stop");
$('.stop').hide();
$('.resume').show();
event.preventDefault();
});
$('.previous').click(function(event){
$(tickerData.newsList).trigger("previous");
$('.stop').hide();
$('.resume').show();
event.preventDefault();
});
$('.next').click(function(event){
$(tickerData.newsList).trigger("next");
$('.stop').hide();
$('.resume').show();
event.preventDefault();
});
};
// tell it to play
$(tickerData.newsList).trigger("play");
};
// News ticker defaults
jQuery.fn[name].defaults = {
newsList: "#news",
tickerRate: 80,
startDelay: 100,
loopDelay: 3000,
placeHolder1: " |",
placeHolder2: "_",
controls: true,
ownControls: false,
stopOnHover: true
}
})(jQuery);
Any solutions? I am not a programmer so if someone could point out where to patch it greatly appreciated!
UPDATE: it seems only the links with ? mark becomes disabled.
Example: http://url.com/blog/index.html?page=2
I just happened to come across this post. I do still support the ticker, and there have been a few releases since last July.
The way to mitigate this issue was that there's now a "stop on hover" option, which pauses the ticker and completes (immediately) the display of an item when the user hovers over it (including of course being about to click it).
If this is still of relevance to you, if you still have issues with the latest version it'd be worth reading through the thread of comments; please do get in touch if you've still a problem (if one of the comments was yours and I missed it, then sorry!). The "official" way is to post a bug report on the jQuery plugins site, which fully tracks any reported issues, but I do try to respond to anyone who requests support via the blog.
If there are any elements with the ID of news in your document, there might be a collision happening... Might this be the case? I'd search your html document for any occurrences of id="news" and correct them, seeing as though passing the proper parameters into the plugin might require a bit of extra research.

Categories

Resources