Paginition refresh issue in AngularJS - javascript

I am showing items using pagination in AngularJS.
For example, I have 12 items and number of items per page is 5. So I have 3 pages to show with the first two pages have 5 items each and the last page has two items.
When I switch pages, say from page-1 to page-2, all 10 items from both page-1 and page-2 are displayed together for a while first before the page-2 items are displayed.
Same thing happened from page-2 to page-3, all 7 items from both page-2 and page-3 are displayed together for a while first before the page-3 items are displayed.
Whenever I switch pages, the same thing is observed.
What could be wrong?
My code is as follow.
html
<div class="adds-wrapper">
<div ng-show="Available">
<div class="item-list" ng-repeat="hotel in pagedItems[currentPage]">
<!-- this is how items are displayed -->
</div>
<div class="pagination-bar">
<ul class="pagination">
<li ng-class="{disabled: currentPage == 0}">
<a class="pagination-btn" href ng-click="prevPage()">« Prev</a></li>
<li ng-repeat="n in range(pagedItems.length)" ng-class="{active: n == currentPage}" ng-click="setPage()">
<a href ng-bind="n + 1">1</a>
</li>
<li ng-class="{disabled: currentPage == pagedItems.length - 1}">
<a class="pagination-btn" href ng-click="nextPage()">Next »</a></li>
</ul>
</div>
Javascript
function groupToPages() {
$scope.pagedItems = [];
for (var i = 0; i < $scope.filteredItems.length; i++) {
var j = Math.floor(i / $scope.itemsPerPage);
if (i % $scope.itemsPerPage === 0) {
$scope.pagedItems[j] = [$scope.filteredItems[i]];
} else {
$scope.pagedItems[j].push($scope.filteredItems[i]);
}
}
};
var loadPagination = function () {
$scope.sortingOrder = $scope.sortingOrder;
$scope.reverse = false;
$scope.filteredItems = [];
$scope.groupedItems = [];
$scope.itemsPerPage = 5;
$scope.pagedItems = [];
$scope.currentPage = 0;
$scope.items = $scope.HotelAndResorts;
$scope.filteredItems = $scope.HotelAndResorts;
$scope.hotelAvailable = true;
if ($scope.HotelAndResorts) {
if ($scope.HotelAndResorts.length == 0) {
$scope.hotelAvailable = false;
$scope.errorMessage = "No Post Found.";
}
} else {
$scope.hotelAvailable = false;
$scope.errorMessage = "No Post Found."
}
/*var searchMatch = function (haystack, needle) {
if (!needle) {
return true;
}
return haystack.toLowerCase().indexOf(needle.toLowerCase()) !== -1;
};*/
groupToPages();
$scope.range = function (start, end) {
var ret = [];
if (!end) {
end = start;
start = 0;
}
for (var i = start; i < end; i++) {
ret.push(i);
}
return ret;
};
$scope.prevPage = function () {
if ($scope.currentPage > 0) {
$scope.currentPage--;
}
};
$scope.nextPage = function () {
if ($scope.currentPage < $scope.pagedItems.length - 1) {
$scope.currentPage++;
}
};
$scope.setPage = function () {
$scope.currentPage = this.n;
};
$scope.sort_by = function (newSortingOrder) {
if ($scope.sortingOrder == newSortingOrder)
$scope.reverse = !$scope.reverse;
$scope.sortingOrder = newSortingOrder;
// icon setup
$('th i').each(function () {
// icon reset
$(this).removeClass().addClass('icon-sort');
});
if ($scope.reverse)
$('th.' + new_sorting_order + ' i').removeClass().addClass('icon-chevron-up');
else
$('th.' + new_sorting_order + ' i').removeClass().addClass('icon-chevron-down');
};
}

When you paginate after updating the paged items try calling $scope.apply() this tells AngularJS to look fixup various javascript things. Angular does some sorcery under the hood to make Javascript behave asynchronously, apply makes thing sync up. I'm oversimplifying, if you like you can read the exact documentation, but I find when htis kind of thing happens 95% of the time it's because I didn't apply.

Related

create pagination for array of objects

I have a nice list of 200 pokemons from pokeapi.co and I have tried to paginate them (20 item/page, 10 pages). I found a nice tutorial, made my own pagination based on that but at the end just doesnt works.
I have tried to call the nextPage, previousPage, firstPage and lastPage. fuctions via HTML button but I get the following error in all 4 cases:
Uncaught ReferenceError: previousPage is not defined
at HTMLButtonElement.onclick (index.html:21)
I am beginner and I dont see the whole picture as clean as a pro, I dont know lot of things and cant figure it out whats wrong with my code!
Please take a look at my code.
Thank you for your time!
//wrapping pokemonList array in an IIFE
const pokemonRepository = (function() {
const pokemonList = [];
const apiUrl = 'https://pokeapi.co/api/v2/pokemon/?limit=200';
//Pagination
var list = new Array();
var pageList = new Array();
var currentPage = 1;
var itemPerPage = 20;
var numberOfPages = 0;
function makeList() {
for (let x = 0; x < 200; x++)
list.push(x);
numberOfPages = getNumberOfPages();
}
function getNumberOfPages() {
return Math.ceil(list.length / itemPerPage);
}
function nextPage() {
currentPage += 1;
loadTheList();
}
function previousPage() {
currentPage -= 1;
loadTheList();
}
function firstPage() {
currentPage = 1;
loadTheList();
}
function lastPage() {
currentPage = numberOfPages;
loadTheList();
}
function loadTheList() {
var begin = ((currentPage - 1) * itemPerPage);
var end = begin + itemPerPage;
pageList = list.slice(begin, end);
drawList(); //draws out our data
check(); //determines the state of the pagination button
}
function drawList() {
document.getElementById('pokemon-list').innerHTML = '';
for (let r = 0; r < pageList.length; r++) {
document.getElementById('pokemon-list').innerHTML += pageList[r] + '';
}
}
function check() {
document.getElementById("next").disabled = currentPage == numberOfPages ? true : false;
document.getElementById("previous").disabled = currentPage == 1 ? true : false;
document.getElementById("first").disabled = currentPage == 1 ? true : false;
document.getElementById("last").disabled = currentPage == numberOfPages ? true : false;
}
function load() {
makeList();
loadTheList();
}
//pagination end
return {
...
};
})();
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
<div id="loading"><h1>Loading...</h1></div>
<h1 class="main-title">Pokédex</h1>
<ul class="pokemon-list" id="pokemon-list">
</ul>
<!-- buttons for pagination-->
<button id="first" onClick="firstPage()">first</button>
<button id="previous" onClick="previousPage()">previous</button>
<button id="next" onClick="nextPage()">next</button>
<button id="last" onClick="lastPage()">last</button>
<script src="js/promise-polyfill.js"></script>
<script src="js/fetch-polyfill.js"></script>
<script src="js/scripts.js"></script>
</body>
</html>

Onclick event in JS shows results for a second before automatically resetting form

This is a simple quiz/questionnaire, that'll display results of the quiz on submission. It shows the results, but only for about half a second before resetting the page. I would also like for the page to show an alert if the user says they're under 18 when the quiz is submitted; it wouldn't keep them from seeing the answers, but just giving them a message.
function checkAge() {
if(age<18) {
alert("Always make sure you have adult supervision while caring for and handling any venomous arachnid.");
} }
function generateAnswers() {
var choice1score = 0;
var choice2score = 0;
var choice3score = 0;
var choice4score = 0;
}
var chosenAnswers = document.getElementsByTagName('result');
for (i=0; i<chosenAnswers.length; i++) {
if (chosenAnswers[i].checked) {
// add 1 to that choice's score
if (chosenAnswers[i].value == 'choice1') {
choice1score = choice1score + 1;
}
if (chosenAnswers[i].value == 'choice2') {
choice2score = choice2score + 1;
}
if (chosenAnswers[i].value == 'choice3') {
choice3score = choice3score + 1;
}
if (chosenAnswers[i].value == 'choice4') {
choice4score = choice4score + 1;
}
}
}
var maxscore = Math.max(choice1score,choice2score,choice3score,choice4score);
var resultBox = document.getElementById('result');
if (choice1score == maxscore) {
resultBox.innerHTML = "Asian Forest Scorpion"
}
if (choice2score == maxscore) {
resultBox.innerHTML = "Deathstalker Scorpion"
}
if (choice3score == maxscore) {
resultBox.innerHTML = "Desert Hairy Scorpion"
}
if (choice4score == maxscore) {
resultBox.innerHTML = "Emperor Scorpion"
}
}
This is where I put the code:
https://codepen.io/cryceks/pen/vjgzOZ
Use:
event.preventDefault();
This prevents the webpage from reloading and therefore clearing form data

Orchard CMS default Pager issues

The scenario is this:
There are 13 items in a projection in total. In default Orchard displays 2 pages (10 on the 1st, 3 on the 2nd page). If the user is on the 2nd page then chooses the option to show 50, then Orchard leaves the ?page=2 in the url and it messes the pager up. Showing 51-13 of 13 items. A bug report has been filled with the community behind Orchard, but I though someone could help with this, as it's a small code snippet. I guess the Javascript at the end needs to be modified, but I'm not really sure...
The pager.cshtml (copied from AdminView):
#{
Model.PreviousText = T("<");
Model.NextText = T(">");
var routeData = new RouteValueDictionary(ViewContext.RouteData.Values);
var queryString = ViewContext.HttpContext.Request.QueryString;
if (queryString != null) {
foreach (string key in queryString.Keys) {
if (key != null && !routeData.ContainsKey(key)) {
var value = queryString[key];
routeData[key] = queryString[key];
}
}
}
if (routeData.ContainsKey("id") && !HasText(routeData["id"])) {
routeData.Remove("id");
}
var totalPageCount = (int)Math.Ceiling((double)Model.TotalItemCount / Model.PageSize);
Model.Metadata.Type = "Pager_Links";
IHtmlString pagerLinks = Display(Model);
Model.Classes.Add("selector");
var pageSizeTag = Tag(Model, "ul");
if (Model.RouteData != null) {
foreach (var rd in Model.RouteData.Values) {
routeData[rd.Key] = rd.Value;
}
}
var pageSizes = new List<int?> { 10, 50, 100 };
var defaultPageSize = WorkContext.CurrentSite.PageSize;
if (!pageSizes.Contains(defaultPageSize)) {
pageSizes.Add(defaultPageSize);
}
Script.Require("jQuery");
}
#if (Model.TotalItemCount > 1) {
<div class="pager-footer">
<span class="page-results">#T("Showing {0} - {1} of {2} jobs", (Model.Page - 1) * (int)Model.PageSize + 1, Model.PageSize == 0 ? Model.TotalItemCount : Math.Min(Model.TotalItemCount, (Model.Page) * (int)Model.PageSize), Model.TotalItemCount)</span>
#if (totalPageCount > 1 || Model.PageSize == 0 || Model.PageSize > pageSizes.First()) {
<div class="page-size-options group">
#T("Show:") #pageSizeTag.StartElement
#{ routeData["pageSize"] = 0; }
#if ((int)Model.PageSize == 0) {
<li class="selected"><span>#T("All").ToString()</span></li>
} else {
<li>#Display.ActionLink(Value: T("All"), Action: (string)routeData["action"], Controller: (string)routeData["controller"], RouteValues: routeData)</li>
}
#foreach (int size in pageSizes.OrderBy(p => p)) {
routeData["pageSize"] = size;
if ((int)Model.PageSize == size) {
<li class="selected"><span>#size.ToString()</span></li>
} else {
<li>#Display.ActionLink(Value: size, Action: (string)routeData["action"], Controller: (string)routeData["controller"], RouteValues: routeData)</li>
}
}
#pageSizeTag.EndElement
</div>
}
#if (totalPageCount > 1 || Model.PageSize != 0) {
#pagerLinks
}
</div>
}
#using (Script.Foot()) {
<script type="text/javascript">
//<![CDATA[
$(function () {
$('ul.selector').each(function () {
var self = $(this),
options = $.map(self.find("li"), function (li) {
var self = $(li);
return $("<option/>", {
value: self.children("a").attr("href"),
text: self.text(),
selected: self.hasClass("selected")
})[0];
}),
select = $("<select/>", {
id: self.attr("id") + "Selector",
"class": self.attr("class"),
name: self.attr("name") + "Selector"
}).change(onSelectChange).append(options);
self.replaceWith(select);
});
function onSelectChange() {
// redirect to page with new page size
// disable button so that no other value can be chosen while the form is submited
window.location = $(this).attr("disabled", true).val();
}
})
//]]>
</script>
}
I've found the fix on codeplex
I'll give it a try.

backbone pagination current page bug

im trying to get a pagination in backbone/underscore to work properly. It works fine on init and on next/prev navigation.
But when i try to set the current page on run time it flips out and renders the wrong page numbers. It only gets wrong if i set the current page to something more than 8. Everyting under 8 works fine. Here is my template, it renders only 10 page numbers at a time, credits to
Rida BENHAMMANE!
Template:
<script type="text/template" id="pagination_template">
<section class="pagination">
<ul>
<li>
<div class="paging prev">◄</div>
</li>
<%
var renderPages;
for (var i = 0; i <= pages-1; i++) {
renderPages = false;
if (pages < 10) {
renderPages = true;
} else {
if (current <= 5) {
if (i < 10) {
renderPages = true;
}
} else if (current <= pages - 5) {
if ((current - 5) < i && (current + 5) > i) {
renderPages = true;
}
} else {
if ((pages - 9) < i) {
renderPages = true;
}
}
};
if(renderPages) { %>
<li>
<a href="#" data-offset="<%= i*9 %>" data-page="<%= i %>">
<%= i+1 %>
</a>
</li>
<% }
}
%>
<li>
<div class="paging next">►</div>
</li>
</ul> <br><br>
total pages <%= pages %>
</section>
</script>
And here is the function the changes the current page and renders the navigaton.
Current pages is set to a data-attribute of the clicked element.
updatePageNum: function () {
var self = this;
self.totalModel.fetch({
success:function(model,response) {
var total = response.data;
var p = total/self.perPage;
var r = total-Math.round(p)
self.maxPage = Math.ceil(p);
self.pagination = _.template($("#pagination_template").html(), {
pages:self.maxPage,
current:self.currentPage
});
}
});
},
Anyone that can help on this?
As it has been solved in the comments, I'm posting it as an answer so it can be accepted.
You should wrap your numbers with parseInt():
var total = parseInt(response.data, 10);
var p = parseInt(total/self.perPage, 10);
var r = parseInt(total-Math.round(p), 10);
Cheers.

Auto refresh a div containing Twitter posts

I am working with Twitter APIv1.1 and currently I am trying to implement a box which will display my latest tweets. This can be seen here:
http://www.jdiadt.com/twitterv1_1feed/testindex.html
However I would like to make this so that when I tweet, the box is automatically updated. I am quite new to JQuery and Javascript so I would appreciate any advice on how I can do this. I've hear AJAX can be used for something like this. Currently I have to refresh the entire page to display any new tweets. I'd like to only refresh the box.
Here is my script: twitterfeed.js
$(document).ready(function () {
var displaylimit = 10;
var twitterprofile = "jackcoldrick";
var screenname = "Jack Coldrick";
var showdirecttweets = false;
var showretweets = true;
var showtweetlinks = true;
var showprofilepic = true;
var headerHTML = '';
var loadingHTML = '';
headerHTML += '<a href="https://twitter.com/" ><img src="http://www.jdiadt.com/twitterv1_1feed/twitteroauth/images/birdlight.png" width="34" style="float:left;padding:3px 12px 0px 6px" alt="twitter bird" /></a>';
headerHTML += '<h1>'+screenname+' <span style="font-size:13px"><a href="https://twitter.com/'+twitterprofile+'" >#'+twitterprofile+'</a></span></h1>';
loadingHTML += '<div id="loading-container"><img src="http://www.jdiadt.com/twitterv1_1feed/twitteroauth/images/ajax-loader.gif" width="32" height="32" alt="tweet loader" /></div>';
$('#twitter-feed').html(headerHTML + loadingHTML);
$.getJSON('http://www.jdiadt.com/twitterv1_1feed/get_tweets.php',
function(feeds) {
//alert(feeds);
var feedHTML = '';
var displayCounter = 1;
for (var i=0; i<feeds.length; i++) {
var tweetscreenname = feeds[i].user.name;
var tweetusername = feeds[i].user.screen_name;
var profileimage = feeds[i].user.profile_image_url_https;
var status = feeds[i].text;
var isaretweet = false;
var isdirect = false;
var tweetid = feeds[i].id_str;
//If the tweet has been retweeted, get the profile pic of the tweeter
if(typeof feeds[i].retweeted_status != 'undefined'){
profileimage = feeds[i].retweeted_status.user.profile_image_url_https;
tweetscreenname = feeds[i].retweeted_status.user.name;
tweetusername = feeds[i].retweeted_status.user.screen_name;
tweetid = feeds[i].retweeted_status.id_str
isaretweet = true;
};
//Check to see if the tweet is a direct message
if (feeds[i].text.substr(0,1) == "#") {
isdirect = true;
}
//console.log(feeds[i]);
if (((showretweets == true) || ((isaretweet == false) && (showretweets == false))) && ((showdirecttweets == true) || ((showdirecttweets == false) && (isdirect == false)))) {
if ((feeds[i].text.length > 1) && (displayCounter <= displaylimit)) {
if (showtweetlinks == true) {
status = addlinks(status);
}
if (displayCounter == 1) {
feedHTML += headerHTML;
}
feedHTML += '<div class="twitter-article">';
feedHTML += '<div class="twitter-pic"><a href="https://twitter.com/'+tweetusername+'" ><img src="'+profileimage+'"images/twitter-feed-icon.png" width="42" height="42" alt="twitter icon" /></a></div>';
feedHTML += '<div class="twitter-text"><p><span class="tweetprofilelink"><strong><a href="https://twitter.com/'+tweetusername+'/status/'+tweetid+'">'+relative_time(feeds[i].created_at)+'</span><br/>'+status+'</p></div>';
feedHTML += '</div>';
displayCounter++;
}
}
}
$('#twitter-feed').html(feedHTML);
});
//Function modified from Stack Overflow
function addlinks(data) {
//Add link to all http:// links within tweets
data = data.replace(/((https?|s?ftp|ssh)\:\/\/[^"\s\<\>]*[^.,;'">\:\s\<\>\)\]\!])/g, function(url) {
return '<a href="'+url+'" >'+url+'</a>';
});
//Add link to #usernames used within tweets
data = data.replace(/\B#([_a-z0-9]+)/ig, function(reply) {
return '<a href="http://twitter.com/'+reply.substring(1)+'" style="font-weight:lighter;" >'+reply.charAt(0)+reply.substring(1)+'</a>';
});
return data;
}
function relative_time(time_value) {
var values = time_value.split(" ");
time_value = values[1] + " " + values[2] + ", " + values[5] + " " + values[3];
var parsed_date = Date.parse(time_value);
var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);
var shortdate = time_value.substr(4,2) + " " + time_value.substr(0,3);
delta = delta + (relative_to.getTimezoneOffset() * 60);
if (delta < 60) {
return '1m';
} else if(delta < 120) {
return '1m';
} else if(delta < (60*60)) {
return (parseInt(delta / 60)).toString() + 'm';
} else if(delta < (120*60)) {
return '1h';
} else if(delta < (24*60*60)) {
return (parseInt(delta / 3600)).toString() + 'h';
} else if(delta < (48*60*60)) {
//return '1 day';
return shortdate;
} else {
return shortdate;
}
}
});
This is the get_tweets.php script where I encode the results in a JSON format.
<?php
session_start();
require_once('twitteroauth/twitteroauth/twitteroauth.php');
$twitteruser = "jackcoldrick";
$notweets = 30;
$consumerkey="xxxxxxxxxxxxxx";
$consumersecret="xxxxxxxxxxxxxxx";
$accesstoken="xxxxxxxxx";
$accesstokensecret="xxxxxxxxxxxxxx";
function getConnectionWithAccessToken($cons_key, $cons_secret, $oauth_token, $oauth_token_secret){
$connection = new TwitterOAuth($cons_key, $cons_secret, $oauth_token, $oauth_token_secret);
return $connection;
}
$connection = getConnectionWithAccessToken($consumerkey, $consumersecret, $accesstoken, $accesstokensecret);
$tweets = $connection->get("https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=".$twitteruser."&count=".$notweets);
echo json_encode($tweets);
?>
This seems doable with your current code. Things to consider:
I'm not sure, but Twitter might have a limit on requests (I imagine it's not a huge one)
Just encapsulate the reusable parts of your code in a function called updateTweets, and call that with a setInterval. There isn't anyway to really "push" tweet updates to your JavaScript, that I know of.
I would put your update code into a function that has a SetTimeout() that does a recursive call to the new function every x seconds. An example below.
$(document).ready(function () {
// Call to your update twitter function
updateTwitter(data);
});
function updateTwitter(data) {
// do your original update twitter GET
$.getJSON('http://www.jdiadt.com/twitterv1_1feed/get_tweets.php', function () {
//... all that code
});
// Sets a timer that calls the updateTwitter function 1x a minute
setTimeout(function () { updateTwitter(data); }, 60000);
}

Categories