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
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;
}
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>
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.
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
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