Angularjs infinite scroll fails to load additional records - javascript

I'm a beginner to angularjs and ionic and i'm implementing infinite scroll, with my current script when it loads the second set of records, it not able to capture the lastid and the new generated records to pass it.
For example when the page loads for the first time (displaying 2 records at a time) and the lastid is 10 when a user scroll to the bottom of the page it passes the lastid 10 to get the next set of records when you scroll down again, it passes that same lastid of 10 instead of 8
$scope.lastid = "";
$http.get('http://localhost/myapp/feeds.php').success(function(data){
console.log(JSON.stringify(data));
$scope.feeds=data;
$scope.lastid = $scope.feeds[$scope.feeds.length - 1].user_id;
});
$scope.addMoreItem = function(){
$http.get('http://localhost/myapp/feeds_more.php?user_id='+$scope.lastid).success(function(data){
$scope.temp=data;
for(var i = 0; i < $scope.temp.length - 1; i++) {
$scope.feeds.push($scope.temp[i]);
if(i == $scope.temp.length - 1){
$scope.lastid = $scope.temp[i].user_id;
}
}
});
$scope.$broadcast('scroll.infiniteScrollComplete');
};
HTML
<ion-infinite-scroll on-infinite="addMoreItem()" distance="1%"> </ion-infinite-scroll>
And one thing is before the first record displays the chrome console read a lot of this error:Cannot read property 'push' of undefined and when the page is still it automatically reloads the same records again

Related

Open pages with user lists and download the user ids

So I have a page which has a list of users, my total list of users is separated into 10 pages with each page showing 20 users. I want to open each page in a new window, pull the user ids on that window, close the window, and open the next page. Later I'll compile all this into a report. The problem I seem to be having is that the user_id_list only gets populated by the users on the first page so I have a bunch of duplicates.
Some of the code for parsing the pages.
full_page_string = document.getElementsByClassName("pagination")[0].outerText;
index_of_next = full_page_string.lastIndexOf("Next");
last_page_number = full_page_string.substring(index_of_next-3, index_of_next);
last_page_number.trim();
last_page_number = 2; /*DELETE LATER*/
page_array = [];
user_id_list = [];
/*Programatically create an array of pages*/
for (var page_num = 1; page_num <= last_page_number; page_num++) {
url = "example.com/users/"+ user_account_id + "/friends?page=" + page_num;
/*Open Each Page*/
var loaded_page = window.open(url, "page_" + page_num, "width=400, height=600");
page_array.push(loaded_page)
/*
For loop keps going even with settimeout. See if there is a way to delay a forloop. The thing is we need enough time to load a page, wait for it, grab users, close page, load a new page and repeat. Right now the floor loop makes it too fast.
Maybe Asyncronously open each page so they're their own instance or "thread"?
*/
loaded_page.onload = function () {
/*Find all users on the page by class*/
friends_on_page = document.getElementsByClassName("link span f5 fw7 secondary");
for (var i = 0; i <= friends_on_page.length; i++) {
pathname = friends_on_page[i].pathname;
user_id = pathname.substring(pathname.lastIndexOf("/")+1)
user_id_list.push(user_id)
console.log(user_id)
}
loaded_page.cose()
};
}

Global Variable not affected in JQuery Ajax Success Function

I have a recursive function that populates a list until the bottom of the screen is reached, then stops.
Each time the recursive function is called, the "start" global variable increments by the limit (5). For example, after 3 times, the "start" variable should be 15. This shows up correctly in the console.
However, outside the recursive function, it seems the "start" variable is still at "0". I thought using "var start = 0" outside of the function makes it global and should be changed by the Ajax success function. The code is below:
//****************************************************************
// Loading questions and answers listings
//****************************************************************
var tag = '';//initialize as blank
var search = '';//initialize as blank
var limit = 5;//number of records to autoload each time
var start = 0;//start at record 0
var action = 'inactive';//initial status to get initial load
var autoscroll = 'false';//check box to engage auto scroll or keep manual load more
var checked = '';//check box value for autoscroll
function load_data(limit, start, search, tag){//recursive function for auto loading
search = $('#search').val();
var loads;
$.ajax({
url:"/modules/posts/questions_all_autoscroll_fetchdata.php",
method:"POST",
data:{limit:limit, start:start, search:search, tag:tag},
cache:false,
success:function(data){
$('#load_data_message').show();//bring loading button back once load successful.
//It is removed during tag click search to avoid glitchy appearance of button showing at top left briefly.
$('#load_data').append(data);
//checks if quantity "limit" amount loaded. If not, that means end of data reached.
//Each data piece has id="container", so counting them tells how many data pieces returned in "loads"
loads = $(data).find('.card-header').length;
if(loads<limit){button_name = 'End of Data';}else{button_name='Loading More <i class="fas fa-spinner fa-lg fa-spin"></i>';}
if(autoscroll == 'false'){button_name = 'Load More'};
//append data returned to bottom of existing data
$('#load_data_message').html("<div id='please_wait' class='form-row text-center'>\
<div class='col-12'><button type='button' class='btn btn-warning'>\
"+button_name+"</button>\
<label style='cursor:pointer;'><input id='autoscroll' type='checkbox' name='autoscroll' value='true' "+checked+"\
style='transform:scale(2.0);margin-left:10px;margin-top:15px;cursor:pointer;'> Autoscroll</label><br></div></div>");
action = "inactive";
//recursive part - keep loading data until bottom of screen reached, stop when reached, or when end of data
start = start + limit;
console.log(start);
if(loads>=limit){
if($("#load_data").height() < $(window).height()){load_data(limit,start,search,tag);}
}
}
});
}
I do an initial load of the listing on page load with:
//for initial loading of data to the bottom of page (through recursive load_data function
if(action == 'inactive') {
action = 'active';
load_data(limit, start,search, tag);
}
Then if I want to initiate an auto/infinite scroll, I click the checkbox which initiates the code below. However, the "start" value is "0", where it should have been affected by the Ajax recursive function previously, and start at "15" instead. I get a repeat of previously posted data, which is not wanted.
//auto scroll checkbox clicked, putting into autoload/autoscroll mode
$(document).on("change", "#autoscroll", function(){
autoscroll = this.checked;
if(autoscroll == true){checked = 'checked';}else{checked = '';}
console.log(start);
load_data(limit, start, search, tag);
});
Then auto/infinite scroll works as follows. The "start" variable is continually updated successfully, but probably within the loop, rather than the recursive Ajax part.
//autoload portion. when scrolling reaches bottom of screen, triggers another load of data
$(window).scroll(function(){
if(autoscroll == true){
if($(window).scrollTop() + $(window).height() > $("#load_data").height() && action == 'inactive' && button_name != 'End of Data'){
action = 'active';
start = start + limit;
//load_data(limit, start, search, tag);
setTimeout(function(){
load_data(limit, start, search, tag);
}, 500);
console.log('scroll function called!');
}
}
});
Bottom line question - I would like to use the global variable "start" and have it changed by the recursive function's Ajax success function. How can this be achieved?
You have not mentioned what your 'data' response looks like in your ajax call.
I tried a response string that looked like this:
<div class='card-header'>hello</div>
<div class='card-header'>world</div>
<div class='card-header'>foo</div>
<div class='card-header'>bar</div>
<div class='card-header'>howdy</div>
In this case, loads = $(data).find('.card-header').length does not provide a length of 5. If loads is only what you loaded in that specific ajax call, then you need $(data).length. Then, the console log for start in the ajax call gets incremented.
Note: Jquery $.find works on a DOM tree. $(data) returns an array of individual nodes, and $(data).length will return the pieces of data returned.
The "loads = $(data).find('.card-header').length" does count the number of class='card-header' instances, contrary to what user2137480 has mentioned above, and everything does increment properly. The issue was that the "start" variable outside the Ajax success function was not being updated as the "load_data" function was called recursively.
Found a clumsy way to make this work. I used a session storage variable, "sessionStorage.start" that gets affected within the Ajax success function, even at recursive levels. Seems like session variables scopes are truly "global"! Then this sessionStorage.start variable is use elsewhere in the code to update the global "start" variable. This value is then maintained consistently throughout the code. Just have to remember that the session variables are text and must be converted to numbers (for this application anyways). See below if you are interested:
//****************************************************************
// Loading questions and answers listings
//****************************************************************
var limit = 5;//number of records to autoload each time
sessionStorage.start = 0;
var start = 0;//start at record 0
sessionStorage.start = start;
sessionStorage.scroll_function_enable = 'false';
var action = 'inactive';//initial status to get initial load
var autoscroll = 'false';//check box to engage auto scroll or keep manual load more
var checked = '';//check box value for autoscroll
function load_data(limit, start, search, tag){//recursive function for auto loading
console.log('load data begin');
console.log('recursive start: ' + start);
sessionStorage.scroll_function_enable = 'false';
search = $('#search').val();
var loads;
$.ajax({
url:"/modules/posts/questions_all_autoscroll_fetchdata.php",
method:"POST",
data:{limit:limit, start:start, search:search, tag:tag},
cache:false,
success:function(data){
$('#load_data_message').show();//bring loading button back once load successful.
//It is removed during tag click search to avoid glitchy appearance of button showing at top left briefly.
$('#load_data').append(data);
//checks if quantity "limit" amount loaded. If not, that means end of data reached.
//Each data piece has id="container", so counting them tells how many data pieces returned in "loads"
loads = $(data).find('.card-header').length;
//alert(loads);
if(loads<limit){button_name = 'End of Data';}else{button_name='Loading More <i class="fas fa-spinner fa-lg fa-spin"></i>';}
if(autoscroll == 'false'){button_name = 'Load More'};
//append data returned to bottom of existing data
$('#load_data_message').html("<div id='please_wait' class='form-row text-center'>\
<div class='col-12'><button id='load_button' type='button' class='btn btn-warning'>\
"+button_name+"</button>\
<label style='cursor:pointer;'><input id='autoscroll' type='checkbox' name='autoscroll' value='true' "+checked+"\
style='transform:scale(2.0);margin-left:10px;margin-top:15px;cursor:pointer;'> Autoscroll</label><br></div></div>");
action = "inactive";
//recursive part - keep loading data until bottom of screen reached, stop when reached, or when end of data
start = start + limit;
sessionStorage.start = start;//needed because recursive routine does not update the global "start" variable. Needed to pass value outside of recursive routine
console.log('recursive end: '+start);
if(loads>=limit){
if($("#load_data").height() < $(window).height())
{
load_data(limit,start,search,tag);
}else
sessionStorage.scroll_function_enable = 'true';
}
}
});
}
//for initial loading of data to the bottom of page (through recursive load_data function
if(action == 'inactive') {
action = 'active';
load_data(limit, start,search, tag);
start = Number(sessionStorage.start);//to get recursive value of start, otherwise will not retain its value
}
//auto scroll checkbox clicked, putting into autoload/autoscroll mode
$(document).on("change", "#autoscroll", function(){
autoscroll = this.checked;
if(autoscroll == true){checked = 'checked';}else{checked = '';}
start = Number(sessionStorage.start);//to get recursive value of start, otherwise will not retain its value
console.log('autoscroll start: ' + start);
load_data(limit, start, search, tag);
start = Number(sessionStorage.start);//to get recursive value of start, otherwise will not retain its value
});
//autoload portion. when scrolling reaches bottom of screen, triggers another load of data
$(window).scroll(function(){
if(autoscroll == true){
if($(window).scrollTop() + $(window).height() > $("#load_data").height() && action == 'inactive' && button_name != 'End of Data' && sessionStorage.scroll_function_enable == 'true'){
action = 'active';
start = Number(sessionStorage.start);//to get number where other processes have left off
console.log('scroll start: ' + start);
//load_data(limit, start, search, tag);
setTimeout(function(){
load_data(limit, start, search, tag);
}, 500);
start = Number(sessionStorage.start);//to get recursive value of start, otherwise will not retain its value
}
}
});

Reload a content almost invisibly and no blinking effect using JAVASCRIPT

I'm writing a small progam wherein I'm getting data using $.get then display the data so far so good and then there's this part then when I click a certain link it refresh the page but it has this blinking effect. Is there a way on how to reload the content get the new updated content then replace the previously loaded data.
NOTE: I didn't use setInterval or setTimeout function because it slows down the process of my website. any answer that does not include those functions are really appreciated.
Here's the code
function EmployeeIssues(){
$('#initial_left').css({'display' : 'none'});
var table = $('#table_er');
$.get('admin/emp_with_issues', function(result){
var record = $.parseJSON(result);
var data = record.data,
employees = data.employees,
pages = data.pages;
if(employees){
$('#er_tab_label').html('<b>Employees with Issues</b>');
for (var i = 0; i < employees.length; i++) {
$('#table_er').fadeIn('slow');
table.append(write_link(employees[i])); // function that displays the data
}
if(pages){
$('#pagination').html(pages);
}
}else{
$('#er_tab_label').html('<b>No employees with issues yet.</b>');
}
});
table.html('');
}
then this part calls the function and display another updated content
$('#refresh_btn').on('click', function(e){
e.preventDefault();
var tab = $('#tab').val();
if(tab == 'er'){
EmployeeIssues();
}
});
What should I do to display the content without any blinking effect?
thanks :-)
This section might be the issue :
if(employees){
$('#er_tab_label').html('<b>Employees with Issues</b>');
for (var i = 0; i < employees.length; i++) {
$('#table_er').fadeIn('slow');
table.append(write_link(employees[i])); // function that displays the data
}
if(pages){
$('#pagination').html(pages);
}
} else ...
It seems you're asking table_er to fade in once per run of the loop whereas s there can only be one such table, you only need to do it once ?
first try re-arringing it like this:
if(employees){
$('#er_tab_label').html('<b>Employees with Issues</b>');
$('#table_er').hide(); // hide it while we add the html
for (var i = 0; i < employees.length; i++) {
table.append(write_link(employees[i])); // function that displays the data
}
$('#table_er').fadeIn('slow'); // only do this after the table has all its html
if(pages){
$('#pagination').html(pages);
}
} else ....
Another possibility is that you're running through a loop and asking jquery to do stuff while the loop is running. It might be better to work out the whole HTML for the new page data in a string and then get the screen to render it in one line. I cna't do this for you as I don't know what's in write_link etc but something like this ..
if(employees){
$('#er_tab_label').html('<b>Employees with Issues</b>');
var sHTML ="";
$('#table_er').hide(); // hide it while we add the html
for (var i = 0; i < employees.length; i++) {
sHTML+=write_link(employees[i]); // maybe this is right ? if write_link returns an HTML string ?
}
table.append(sHTML); // add the HTML from the string in one go - stops the page rendering while the code is running
$('#table_er').fadeIn('slow'); // now show the table.
if(pages){
$('#pagination').html(pages);
}
} else ...

ngInfiniteScroll is being called more than it needs to

I have the following unordered list that uses ngInfiniteScroll:
<ul class="list-group" infinite-scroll="loadMore()">
<li ng-repeat="post in posts | filter:search" class="list-group-item isteacher-{{post.isteacher}}"><h4>{{post.title}}</h4> by {{post.author}} on <small>{{post.date}}</small></li>
</br>
</ul>
My loadMore() function queries the database with the offset. The offset being the number of items that are loaded thus far. I've tested this by hand and it works fine.
$scope.offset = 0;
$scope.posts = [];
$scope.loadMore = function(){
$http.get('/getposts?offset='+$scope.offset)
.success(function(data){
var newList = data.post_list;
if(newList.length>0){
for(var x=0; x<newList.length; x++){
$scope.posts.push(newList[x]);
}
$scope.offset+=newList.length;
}
});
}
The database has a fetch limit of "10" everytime it is queried, and accepts an offset. I have a dataset of 11 posts, just to test. If it works, it should load the first 10 when the page loads, and the 11th one as soon as I scroll. While this works some of the time, it breaks most of the time. What I mean by it breaking is that it loads the last post 3-4 times. I tested it by logging $scope.posts.length every time the function is called. When the page loads, the length is 10, but as I scroll down it keeps adding the last element multiple times. Any help would be great!
The problem is, you start the http get request and waiting for the response. Meanwhile you are scrolling up and done and your function would be called again. That could be the reason why the last posts are loaded multiple times. However, and if the query was successful than you are adding newList.length to your offset. Possible solution for this problem:
$scope.offset = 0;
$scope.posts = [];
$scope.isBusy = false;
$scope.loadMore = function(){
if($scope.isBusy === true) return; // request in progress, return
$scope.isBusy = true;
$http.get('/getposts?offset='+$scope.offset)
.success(function(data){
var newList = data.post_list;
if(newList.length>0){
for(var x=0; x<newList.length; x++){
$scope.posts.push(newList[x]);
}
$scope.offset+=newList.length;
}
$scope.isBusy = false; // request processed
});
}

How can i loop through bootstrap tooltips forever using jQuery?

I have some thumbnails on my site, that use Twitters Bootstrap tooltips to display the name of each thumbnail, what i'm trying to do is loop through each one, with a delay of say 2 seconds showing the tooltip, then hiding it as the next one pops up. I tried to do this a few ways but nothing was working.
I got as far as something like this, but that wasn't working.
$("[rel=tooltip]").each(function (i) {
$id=$(this).attr('id');
$($id).tooltip('show');
});
Here's a JSFiddle of my layout: http://jsfiddle.net/BWR5D/
Any ideas?
Try the following:
var ttid = 0, tooltipIds = [];
$("a[rel=tooltip]").each(function(){
tooltipIds.push(this.id);
});
var iid = setInterval(function(){
if (ttid) $('#'+tooltipIds[ttid-1]).tooltip("hide");
if (ttid === tooltipIds.length) ttid = 0;
$('#'+tooltipIds[ttid++]).tooltip("show");
}, 2000);
You can stop the tooltips from showing with: clearInterval(iid);
Following should hide current open tooltip, then show the next. Uses current index vs length of cached elements to determine when to start back at beginning
/* cache elements*/
var $els=$("a[rel=tooltip]").tooltip(), index=-1;
var tipLoop=setInterval(function(){
index++;
index = index < $els.length ? index : 0;
$els.tooltip("hide").eq( index).tooltip('show');
},2000)
DEMO: http://jsfiddle.net/BWR5D/1/

Categories

Resources