Backbone pagination 10 at a time - javascript

Im building an pagination in backbone. The problem is that the amount of pages has grown and are now that many that it ruins the layout of the site. So i want to implement a functionality where i can render lets say the first 10 pages and then with a next/prev button control which page numbers should be shown. But always only show 10 pages like so:
< 1 2 3 4 5 6 7 8 9 10 >
< 2 3 4 5 6 7 8 9 10 11 >
So now i append this to my pagination (its all pages)
updateTotal: function () {
var self = this;
self.totalModel.fetch({
success:function(model,response) {
var total = response.data; //all iems
var p = total/self.perPage;
var r = total-Math.round(p)
self.pagination = _.template($("#pagination_template").html(), {
pages:Math.ceil(p)
});
self.render();
}
});
},
This is how i print it out in html (underscore.js)
<script type="text/template" id="pagination_template">
<section class="pagination">
<ul>
<% for (var i = 0; i < pages; i++) { %>
<li>
<a href="#" data-offset="<%= i*9 %>" data-page="<%= i+1 %>">
<%= i+1 %>
</a>
</li>
<% } %>
</ul>
<div class="paging prev">◄</div>
<div class="paging next">►</div>
</section>
</script>
I have a variable the represents the current page and i know the total amount of pages. But i dont know how to implement this that i describes as my problem.
Anyone knows how to do this and can come with an example? Would be very appreciated!

You can do it like this :
updateTotal: function () {
var self = this;
self.totalModel.fetch({
success:function(model,response) {
var total = response.data; //all iems
var p = total/self.perPage;
var r = total-Math.round(p);
var c = ... // current page
self.pagination = _.template($("#pagination_template").html(), {
pages:Math.ceil(p),
current: c
});
self.render();
}
});
},
And the html
<script type="text/template" id="pagination_template">
<section class="pagination">
<ul>
<%
var renderPage;
for (var i = 1; i <= pages; i++) {
renderPage = false;
if (pages < 10) {
renderPage = true;
} else {
if (current <= 5) {
if (i < 10) {
renderPage = true;
}
} else if (current <= pages - 5) {
if ((current - 5) < i || (current + 5) > i) {
renderPage = true;
}
} else {
if ((pages - 9) < i) {
renderPage = true;
}
}
};
if (renderPage) { %>
<li>
<a href="#" data-offset="<%= i*9 %>" data-page="<%= i %>">
<%= i %>
</a>
</li>
<% }
} %>
</ul>
<div class="paging prev">◄</div>
<div class="paging next">►</div>
</section>
</script>
That will print the current page and the 4 pages before and after.

Related

Rails: Show and hide a div

I have a rails app and I'm looping through some db values:
<ul>
<% #categories.each do |category| %>
<li onclick="showHide(event)"> <%= category.name %>
<% unless category.children.empty? %>
<ul class="categories" style="display:none;">
<% category.children.each do |subcategory| %>
<li><%= link_to "#{subcategory.name}", search_path(:search => subcategory.id) %></li>
<% end %>
</ul>
<% end %>
</li>
<% end %>
</ul>
And with the following javascript I'm able to show and hide the div when I click on it:
function showHide(e) {
var categoryList = e.currentTarget.querySelector(".categories");
categoryList.style.display = categoryList.style.display === "none" ? "block" : "none"
}
This does work, but I need to implement two more things to this.
1. When I click on one category and another one is open, I want to close the other one.
2. Even after I refresh the page, I want to figure out a way to remember the last target(the last div that was open).
Any ideas on how to implement both of the above?
Update 1
Ok I followed #Panomosh advise I got the first one to work. And on the second one when the cookie doesn't exist I create it and then it gives me this error in the browser console:
TypeError: undefined is not an object (evaluating 'categoryList.currentTarget.querySelector')
Any ideas why?
function getCookie(c_name) {
var i, x, y, ARRcookies = document.cookie.split(";");
for (i = 0; i < ARRcookies.length; i++) {
x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("="));
y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
x = x.replace(/^\s+|\s+$/g, "");
if (x == c_name) {
return unescape(y);
}
}
}
function showHide(e) {
var divsToHide = document.getElementsByClassName("categories");
for(var i = 0; i < divsToHide.length; i++){
divsToHide[i].style.display = "none"; // depending on what you're doing
}
var myCookie = getCookie(".Cl");
if (myCookie == null) {
var categoryList = e.currentTarget.querySelector(".categories");
setCookie(".Cl", categoryList)
categoryList.style.display = categoryList.style.display === "none" ? "block" : "none"
}
else {
var categoryList = getCookie(".Cl");
categoryList.currentTarget.querySelector(".categories");
categoryList.style.display = categoryList.style.display === "none" ? "block" : "none"
}
}
function setCookie(c_name, value) {
var now = new Date();
var time = now.getTime();
time += 300 * 1000;
now.setTime(time);
var c_value = escape(value) + ((time == null) ? "" : "; expires=" + now.toUTCString());
document.cookie = c_name + "=" + c_value;
}

Limit number of links to show in custom paging

Now with my code i see all pages, but i want to limit the number of links.
If i have 10 pages, but i want to see only five:
1 2 3 4 5,
5 6 7 8 9.
How can i do that? This is plunk demo on part of my code
This is my controller:
var booksController = function () {
function all(context) {
var size = 2,
page = +context.params['page'] || 0;
templates.get('books')
.then(function (template) {
var booksRef = firebase.database().ref('books');
booksRef = booksRef.orderByChild('timestamp');
booksRef.on('value', function (snapshot) {
this.data = [];
snapshot.forEach(function (child) {
this.data.push(child.val());
}.bind(this));
var pagesLen = Math.ceil(data.length / size),
pages = [];
for (var i = 0; i < pagesLen; i+= 1) {
pages.push({
page: i,
displayPage: i + 1
});
}
data = data.slice(page * size, (page + 1) * size);
context.$element().html(template({
books: data,
pages: pages
}));
});
});
}
return { all: all };
}();
And my hadlebars template:
<section id="primary-content">
<div class="wrapper">
<h1 class="above">Books: </h1>
{{#each books}}
<h1>{{title}}</h1>
{{/each}}
<div id="medium">
</div> {{!--end medium--}}
<ul class="pagination">
{{#pages}}
<li>
<a class="btn btn-sm btn-default" href="#/books/{{page}}">{{displayPage}}</a>
</li>
{{/pages}}
</ul>
</div>

Hiding specific elements after creating them with ng-repeat

I'm trying to create a piano on my page using two image files: white-key and black-key.
I've created them, but the black keys on the piano alternate in groups of 2 and 3 and I'd hide the black key images for indices [1, 4(1+3), 8(4+4), 11(8+3), 15(11+4), .., 54]. I'm unsure of how to go about doing this though.
This is how I created them.
HTML:
<div ng-controller="DrawCtrl as draw">
<ul class="white-keys">
<li ng-repeat="t in draw.range(56) track by $index">
<img ng-src={{draw.white_key}} />
</li>
</ul>
<ul class="black-keys">
<li ng-repeat="t in draw.range(55) track by $index">
<img ng-src={{draw.black_key}} />
</li>
</ul>
</div>
JS:
angular.module('app')
.controller('DrawCtrl', function() {
var self = this;
self.piano_back = 'img/background.png';
self.white_key = 'img/midi_white_up.png';
self.black_key = 'img/midi_black_up.png';
self.range = function(num) {
return new Array(num);
};
});
EDIT: Got it working thanks to hansmaad's answer.
HTML:
<ul class="black-keys">
<li ng-repeat="key in draw.keys" ng-switch="key.black">
<img ng-switch-when="true" ng-src={{draw.black_key}} />
<img ng-switch-when="false" ng-src={{draw.black_key}} class="black-hidden" />
</li>
</ul>
JS:
self.keys = [];
var keyGroupOf3 = true;
self.keys.push({black: true}); // first key is shown
var i = 1;
while (i < 54) {
self.keys.push({black: false});
// alwasy followed by at least two
self.keys.push({black: true});
self.keys.push({black: true});
if (keyGroupOf3){
self.keys.push({black: true});
i += 4;
} else {
i += 3;
}
I think you should create your keyboard in the controller as array of keys. You can then use a single ng-repeat to draw all the keys. To draw the right img for a key you can use ng-switch or store the imgage url in the key.
A simple example without images but using ng-class:
http://plnkr.co/edit/kIvRqdkbHHNcUXKzSLZC?p=preview
<div ng-controller="DrawCtrl as draw">
<ul >
<li ng-repeat="key in draw.keys" ng-class="{ 'black' : key.black, 'white' : !key.black}">
</li>
</ul>
</div>
Controller:
function DrawCtrl() {
this.keys = []
for(var i = 0, e = 55; i < e; ++i) {
this.keys.push({
black : isBlackKey(i)
});
}
function isBlackKey(i) {
// your piano logic here
return i % 2 == 0;
}
}
Using ng-switch you could do:
<ul>
<li ng-repeat="key in draw.keys" ng-switch="key.black">
<span ng-switch-when="true">Black key</span>
<span ng-switch-when="false">White key</span>
</li>
</ul>
Edit: This could be a simple, stupid algorithm to fill the keys array:
this.keys = []
var lastWasBlack = true;
var d = 5;
var next = 5;
for(var i = 0, e = 55; i < e; ++i) {
var isBlack = !lastWasBlack;
if (i === next) {
isBlack =!isBlack;
d = d === 5 ? 7 : 5;
next += d;
}
this.keys.push({
black : isBlack
});
lastWasBlack = isBlack;
}
}
http://plnkr.co/edit/kIvRqdkbHHNcUXKzSLZC?p=preview
Have a look at the below plunker. I haven't added any css. But just to hide and show the images you can use this link.
http://plnkr.co/edit/pgFKHShXpeS4EQhoaFTI?p=preview
<ul class="white-keys">
<li ng-repeat="t in draw.range(20) track by $index">
<img ng-src='http://lorempixel.com/g/50/15/technics' ng-hide="($index == 1 || $index == 4 || $index == 8 || $index == 11)"/>
</li>
</ul>
I have used ng-hide to hide the images at specific position.
Is this you are looking for? If not let me know.

How can I show next 15 items in ng-repeat?

I am currently using angular ng-repeat.
When a user clicks a button that says "Next 15", I would like to show next 15 items.
I don't want to pop items from array, I would just like to hide first 15, and limit show to just the next 15.
Also, when the user clicks "Prev 15", I would like to show just the previous 15 items.
Here is what I have so far:
HTML:
<div ng-controller="ctrlIndex as vm">
<ul ng-repeat=" item in vm.items | limitTo: 15 * vm.page
| limitTo: 15 * vm.page < count ? limitTo: 15 * vm.page : 15 - (15 * vm.page - count)"/>
<li>{{ item }}</li>
</ul>
<div><button ng-click="vm.next()">Next 15</button></div>
<div><button ng-click="vm.back()">Prev 15</button></div>
Javascript:
var app = angular.module('app', []);
3app.controller('ctrlIndex', function(){
var vm = this;
vm.numRecords = 15;
vm.page = 1;
vm.items = []
for (var i = 0; i < 1000000; ++i) {
vm.items.push('item : ' + i);
}
vm.next = function(){
vm.page = vm.page + 1;
};
vm.back = function(){
vm.page = vm.page - 1;
};
});
Here you go - Plunker
Markup
<body ng-app="app">
<div ng-controller="ctrlIndex as vm">
<ul ng-repeat="item in vm.items track by $index"
ng-show="(($index < (vm.page * vm.numRecords)) && ($index >= ((vm.page - 1) * vm.numRecords)))">
<li>{{ item }}</li>
</ul>
<div><button ng-click="vm.next()">Next 15</button></div>
<div><button ng-click="vm.back()">Prev 15</button></div>
</div>
</body>
Something like the following will allow you to keep your view tidy and your logic testable:
// controller
var vm = this;
vm.numRecords = 15;
vm.page = 0;
vm.items = [];
vm.data = {};
vm.data.shownItems = [];
vm.limit = 100;
vm.maxPages = Math.floor(vm.limit / vm.numRecords);
for (var i = 0; i < vm.limit; ++i) {
vm.items.push('item : ' + i);
}
vm.data.shownItems = vm.items.slice(0, this.numRecords);
vm.next = function() {
if (vm.page >= vm.maxPages) {
return
}
vm.page += 1;
var begin = vm.page * vm.numRecords;
var end = begin + vm.numRecords;
vm.data.shownItems = vm.items.slice(begin, end);
};
vm.back = function() {
if (vm.page <= 0) {
return
}
vm.page -= 1;
var begin = vm.page * vm.numRecords;
var end = begin + vm.numRecords;
vm.data.shownItems = vm.items.slice(begin, end);
};
// view
<ul ng-repeat="item in vm.data.shownItems">
<li>{{ item }}</li>
</ul>
Plunker

Possible to count # of specific div class within a div id?

Have the following script:
var CurrentPageTop = 0;
var PageHeight = 496;
var TotalPages = 9;
var CurrenPage = 1;
function Slide( control, panel ){
if ( control.name == "SlideDown" ){
if ( (CurrenPage >= 1) && (CurrenPage <= TotalPages-1) ){
CurrenPage++;
CurrentPageTop = ( CurrentPageTop - PageHeight );
}
}
if ( control.name == "SlideUp" ){
if ( (CurrenPage > 1) && (CurrenPage <= TotalPages) ){
CurrenPage--;
CurrentPageTop = (CurrentPageTop + PageHeight);
}
}
var PanelScroller = document.getElementById(panel);
PanelScroller.style.top = CurrentPageTop + 'px';
var CurrenPageId = document.getElementById("CurrenPageId");
CurrenPageId.innerHTML = "Page " + CurrenPage + " of 9";
}
which accompanies a single image gallery on a page:
<table cellpadding="0" cellspacing="0">
<tr>
<td>
<div class="SlidingPanel">
<div id="PanelScroller">
<div class="Page">
<img src="i/gal/g1.jpg">
</div>
How would I set this up to have multiple instances on one page?
Some galleries have 9 images, some have 6, etc.
Is there a way to count the number of <div class="Page"> within a <div id="PanelScroller"> ?
I want to avoid having to use 3 slightly different instances of this script for 3 different galleries. I just can't wrap my head around it because I'm a novice.
function number_of_elements_with_class_name(class_name) {
var elements = getElementsByClassName(class_name);
var count = 0;
for(var i in elements) {
count++;
}
return count;
}
node.getElementsByClassName()
http://www.quirksmode.org/blog/archives/2008/05/getelementsbycl.html

Categories

Resources