How to generate page numbers like the below using javascript/jquery?
If the 5 th page is selected i have to show 3,4 and 6,7 and also 1,last page with prev,next...
Any suggestion....
EDIT:
How to work with json data that use these pagination div? (ie) My json data contains 50 records
I want to 10 in page 1 and so on... How to paginate json data with these numbers...
I want a jquery function to pass currentpageno,lastpagenumber and the function should generate me page numbers like the below for me
If it is the first page
If it is in the middle,
If it is the last page,
Second EDIT:
I have tried this function but doesn't seem to get the desired result
function generatePages(currentPage, LastPage) {
if (LastPage <= 5) {
var pages = '';
for(var i=1;i<=5;i++)
{
pages += "<a class='page-numbers' href='#'>" + i + "</a>"
}
$("#PagerDiv").append(pages);
}
if (LastPage > 5) {
var pages = '';
for (var i = 1; i <= 5; i++) {
pages += "<a class='page-numbers' href='#'>" + i + "</a>"
}
$("#PagerDiv").append(pages);
}
}
I have the lastPage and currentPage values please help me out getting this...
What you are looking for is called "pagination" and there's (as always) a jQuery plugin that does the job for you:
http://d-scribe.de/webtools/jquery-pagination/demo/demo_options.htm
(Download it here)
Edit: Since you don't seem to be able to get it working, here is one way (of several different) how you can use the plugin.
Step 1: Generate markup from your JSON-data like the following:
<div id="display">
<!-- This is the div where the visible page will be displayed -->
</div>
<div id="hiddenData">
<!-- This is the div where you output your records -->
<div class="record">
<!-- create one record-div for each record you have in your JSON data -->
</div>
<div class="record">
</div>
</div>
The idea is to copy the respective record to the display div when clicking on a page-link. Therefore, the plugin offers a pageSelect-callback function. Step 2 is to implement this function, for instance:
function pageselectCallback(pageIndex, jq){
// Clone the record that should be displayed
var newContent = $('#hiddenData div.record:eq('+pageIndex+')').clone();
// Update the display container
$('#display').empty().append(newContent);
return false;
}
This would mean that you have one page per record. If you want to display multiple records per page, you have to modify the above function accordingly.
The third and final step is to initialize the whole thing correctly.
function initPagination() {
// Hide the records... they shouldn't be displayed
$("#hiddenData").css("display", "none");
// Get the number of records
var numEntries = $('#hiddenData div.result').length;
// Create pagination element
$("#pagination").pagination(numEntries, {
num_edge_entries: 2,
num_display_entries: 8, // number of page links displayed
callback: pageselectCallback,
items_per_page: 1 // Adjust this value if you change the callback!
});
}
So, you just have to generate the HTML markup from your JSON data and call the init-function afterwards.
It's not that difficult, is it?
yeah #SLaks is right. nothing too crazy here. You will have 2 variables currentPageNumber and lastPageNumber.
$("div.paginator").append("<a...>prev</a>");
$("div.paginator").append("<a...>1</a>");
for (x = (currentPageNumber - 2; x <= (currentPageNumber + 2); x++) {
$("div.paginator").append("<a...>"+ x +"</a>");
}
$("div.paginator").append("<a...>"+ lastPageNumber +"</a>");
$("div.paginator").append("<a...>next</a>");
// you could apply styles to and a tag in the div.paginator
// you could apply a special class to the a tag that matches the currentPageNumber
// you can also bind some click events to each a tag and use the $(this).text() to grab the number of the page to go to
Use THIS or THAT plugin. They're both easy html pagination plugins. Put everything in the html at once and paginate with one of those.
Add two new hidden inputs
<input type='hidden' id='current_page' />
<input type='hidden' id='show_per_page' />
Next add an empty div to create pagination controls
<!-- An empty div which will be populated using jQuery -->
<div id='page_navigation'></div>
$(document).ready(function(){
//how much items per page to show
var show_per_page = 5;
//getting the amount of elements inside content div
var number_of_items = $('#content').children().size();
//calculate the number of pages we are going to have
var number_of_pages = Math.ceil(number_of_items/show_per_page);
//set the value of our hidden input fields
$('#current_page').val(0);
$('#show_per_page').val(show_per_page);
//now when we got all we need for the navigation let's make it '
/*
what are we going to have in the navigation?
- link to previous page
- links to specific pages
- link to next page
*/
var navigation_html = '<a class="previous_link" href="javascript:previous();">Prev</a>';
var current_link = 0;
while(number_of_pages > current_link){
navigation_html += '<a class="page_link" href="javascript:go_to_page(' + current_link +')" longdesc="' + current_link +'">'+ (current_link + 1) +'</a>';
current_link++;
}
navigation_html += '<a class="next_link" href="javascript:next();">Next</a>';
$('#page_navigation').html(navigation_html);
//add active_page class to the first page link
$('#page_navigation .page_link:first').addClass('active_page');
//hide all the elements inside content div
$('#content').children().css('display', 'none');
//and show the first n (show_per_page) elements
$('#content').children().slice(0, show_per_page).css('display', 'block');
});
function previous(){
new_page = parseInt($('#current_page').val()) - 1;
//if there is an item before the current active link run the function
if($('.active_page').prev('.page_link').length==true){
go_to_page(new_page);
}
}
function next(){
new_page = parseInt($('#current_page').val()) + 1;
//if there is an item after the current active link run the function
if($('.active_page').next('.page_link').length==true){
go_to_page(new_page);
}
}
function go_to_page(page_num){
//get the number of items shown per page
var show_per_page = parseInt($('#show_per_page').val());
//get the element number where to start the slice from
start_from = page_num * show_per_page;
//get the element number where to end the slice
end_on = start_from + show_per_page;
//hide all children elements of content div, get specific items and show them
$('#content').children().css('display', 'none').slice(start_from, end_on).css('display', 'block');
/*get the page link that has longdesc attribute of the current page and add active_page class to it
and remove that class from previously active page link*/
$('.page_link[longdesc=' + page_num +']').addClass('active_page').siblings('.active_page').removeClass('active_page');
//update the current page input field
$('#current_page').val(page_num);
}
Related
I have a function that is supposed to perform pagination on a table. Within that function is another function that needs to be executed when I click on the numbers in the navigation bar. The code works fine in VSCode. When I put the code in index.jsp in eclipse, the function gives the error: Uncaught ReferenceError: sort is not defined at HTMLButtonElement.onclick.
// get the table element
var table = document.getElementById("disposalTable"),
// number of rows per page
n = 5,
// number of rows of the table
rowCount = table.rows.length,
// get the first cell's tag name (in the first row)
firstRow = table.rows[0].firstElementChild.tagName,
// boolean var to check if table has a head row
hasHead = (firstRow === "TH"),
// an array to hold each row
tr = [],
// loop counters, to start count from rows[1] (2nd row) if the first row has a head tag
i,ii,j = (hasHead)?1:0,
// holds the first row if it has a (<TH>) & nothing if (<TD>)
th = (hasHead?table.rows[(0)].outerHTML:"");
// count the number of pages
var pageCount = Math.ceil(rowCount / n);
// if we had one page only, then we have nothing to do ..
if (pageCount > 1) {
// assign each row outHTML (tag name & innerHTML) to the array
for (i = j,ii = 0; i < rowCount; i++, ii++)
tr[ii] = table.rows[i].outerHTML;
// create a div block to hold the buttons
table.insertAdjacentHTML("afterend","<div id='buttons'></div");
// the first sort, default page is the first one
sort(1);
}
// ($p) is the selected page number. it will be generated when a user clicks a button
function sort(p) {
/* create ($rows) a variable to hold the group of rows
** to be displayed on the selected page,
** ($s) the start point .. the first row in each page, Do The Math
*/
var rows = th,s = ((n * p)-n);
for (i = s; i < (s+n) && i < tr.length; i++)
rows += tr[i];
// now the table has a processed group of rows ..
table.innerHTML = rows;
// create the pagination buttons
document.getElementById("buttons").innerHTML = pageButtons(pageCount,p);
// CSS Stuff
document.getElementById("id"+p).setAttribute("class","active");
}
// ($pCount) : number of pages,($cur) : current page, the selected one ..
function pageButtons(pCount,cur) {
/* this variables will disable the "Prev" button on 1st page
and "next" button on the last one */
var prevDis = (cur == 1)?"disabled":"",
nextDis = (cur == pCount)?"disabled":"",
/* this ($buttons) will hold every single button needed
** it will creates each button and sets the onclick attribute
** to the "sort" function with a special ($p) number..
*/
buttons = "<input type='button' value='<< Prev' onclick='sort("+(cur - 1)+")' "+prevDis+">";
for (i=1; i<=pCount;i++)
buttons += "<input type='button' id='id"+i+"'value='"+i+"' onclick='sort("+i+")'>";
buttons += "<input type='button' value='Next >>' onclick='sort("+(cur + 1)+")' "+nextDis+">";
return buttons;
}
I figured it out. Instead of trying to access the nested function. Put the pager code into a function. Then create an instance of the function as a variable. And call that variable every time.
For instance:
let pager = new Pager();
Then the onclick method will call pager.sort(1) or pager.sort(2) everytime.
Example 1: I have a js script that I have in a script editor to wrap my promoted links. I want to replace this with a reference to a js script I will place in the Site Assets and passing one parameter that equals the number of links per row.
So I moved my code into the Site assets and reference it using the following and it did not seem to work. I am using a script editor. Not passing any parameters yet.
<script type="text/javascript" src="../Site%20Assets/js-enterprise/WrapPromotedLinks.js"></script>
My code in my Site Assets is:
<script type="text/javascript" src="https://code.jquery.com/jquery-1.10.2.min.js Jump "></script>
<script type="text/javascript">
$(document).ready(function () {
// Update this value to the number of links you want to show per row
var numberOfLinksPerRow = 3;
alert(numberOfLinksPerRow);
// local variables
var pre = "<tr><td><div class='ms-promlink-body' id='promlink_row_";
var post = "'></div></td></tr>";
var numberOfLinksInCurrentRow = numberOfLinksPerRow;
var currentRow = 1
// find the number of promoted links we're displaying
var numberOfPromotedLinks = $('.ms-promlink-body > .ms-tileview-tile-root').length;
// if we have more links then we want in a row, let's continue
if (numberOfPromotedLinks > numberOfLinksPerRow) {
// we don't need the header anymore, no cycling through links
$('.ms-promlink-root > .ms-promlink-header').empty();
// let's iterate through all the links after the maximum displayed link
for (i = numberOfLinksPerRow + 1; i <= numberOfPromotedLinks; i++) {
// if we're reached the maximum number of links to show per row, add a new row
// this happens the first time, with the values set initially
if (numberOfLinksInCurrentRow == numberOfLinksPerRow) {
// i just want the 2nd row to
currentRow++;
// create a new row of links
$('.ms-promlink-root > table > tbody:last').append(pre + currentRow + post);
// reset the number of links for the current row
numberOfLinksInCurrentRow = 0 }
// move the Nth (numberOfLinksPerRow + 1) div to the current table row
$('#promlink_row_' + currentRow).append($('.ms-promlink-body > .ms-tileview-tile-root:eq(' + (numberOfLinksPerRow) + ')'));
// increment the number of links in the current row
numberOfLinksInCurrentRow++; }
}
});
</script>
I want to keep a reference only on my page passing in the parameter 3 for now.
Follow the steps below to achieve it.
1.Save the code below as js file "WrapPromotedLinks.js".
$(document).ready(function () {
// Update this value to the number of links you want to show per row
var numberOfLinksPerRow = 3;
//alert(numberOfLinksPerRow);
// local variables
var pre = "<tr><td><div class='ms-promlink-body' id='promlink_row_";
var post = "'></div></td></tr>";
var numberOfLinksInCurrentRow = numberOfLinksPerRow;
var currentRow = 1
// find the number of promoted links we're displaying
var numberOfPromotedLinks = $('.ms-promlink-body > .ms-tileview-tile-root').length;
// if we have more links then we want in a row, let's continue
if (numberOfPromotedLinks > numberOfLinksPerRow) {
// we don't need the header anymore, no cycling through links
$('.ms-promlink-root > .ms-promlink-header').empty();
// let's iterate through all the links after the maximum displayed link
for (i = numberOfLinksPerRow + 1; i <= numberOfPromotedLinks; i++) {
// if we're reached the maximum number of links to show per row, add a new row
// this happens the first time, with the values set initially
if (numberOfLinksInCurrentRow == numberOfLinksPerRow) {
// i just want the 2nd row to
currentRow++;
// create a new row of links
$('.ms-promlink-root > table > tbody:last').append(pre + currentRow + post);
// reset the number of links for the current row
numberOfLinksInCurrentRow = 0;
}
// move the Nth (numberOfLinksPerRow + 1) div to the current table row
$('#promlink_row_' + currentRow).append($('.ms-promlink-body > .ms-tileview-tile-root:eq(' + (numberOfLinksPerRow) + ')'));
// increment the number of links in the current row
numberOfLinksInCurrentRow++;
}
}
});
2.Upload the file into the folder "js-enterprise" in Site Assets library.
3.Use the references below in script editor web part in the SharePoint page to make it works.
<script src="https://code.jquery.com/jquery-1.12.4.min.js" type="text/javascript"></script>
<script type="text/javascript" src="../SiteAssets/js-enterprise/WrapPromotedLinks.js"></script>
I have a working search bar that is added through the html. However to make the code unobtrusive i am trying to append the search bar and button through JavaScript. I am able to display the search bar and button, but the functionality of bringing up results has stopped working.
Here is the section to add the search bar in JS.
var $searchSection = $('<div class="student-search"></div>');
$searchSection.append('<input id = "search-criteria" placeholder="Search for students..."></input>');
$searchSection.append('<button>Search</button>');
//Append search section
$('.page-header').append($searchSection);
I am trying to get the functionality of search working. Here is a link to the code with the search working, as the search bar is included in the html. http://codepen.io/fun/pen/RRyaNm
This is a link to the code with search bar added through the js but with no search functionality. http://codepen.io/fun/pen/VjraNd?editors=1010
How do you get the search to work through adding from the js?
Any help or pointers would be awesome.
Thank you,
Harry
You don't have to add more function, just move your codes to the top. Check this
jsfiddle https://jsfiddle.net/xt5193z1/
//Search section
var $searchSection = $('<div class="student-search"></div>');
$searchSection.append('<input id = "search-criteria" placeholder="Search for students..."></input>');
$searchSection.append('<button>Search</button>');
//Append search section
$('.page-header').append($searchSection);
var $studentItem = $('.student-item');
var $pagination = $('.pagination');
var $searchCriteria = $('#search-criteria');
var perPage = 10;
// count number of student items
var studentCount = $studentItem.length;
// number of pages = number of students / 10 rounded up
var pageNumber = Math.ceil(studentCount / perPage);
// remove all student items
var initialTen = $studentItem.hide();
// display first 10 student items
initialTen = $studentItem.slice(0, perPage).show();
// pagination ul
var paginationHTML = '<ul>';
// calc number of links
for (var i = 1; i < pageNumber + 1; i++) {
// li and link for each page
paginationHTML += '<li>' + i + '</li>';
}
// end of ul
paginationHTML += '</ul>';
// display list to page
$pagination.html(paginationHTML);
// pagination link click
$('.pagination li a').on('click', function() {
// remove active
$('.pagination li a.active').removeClass('active');
// add active class
$(this).addClass('active');
// page number of clicked
var pageNum = this.text;
// Start point for slice
// e.g 3 * 10
var startFrom = pageNum * perPage - perPage;
// end point for slice
// e.g 30 + 10
var endOn = startFrom + perPage;
// display students based on number clicked
$studentItem.hide().slice(startFrom, endOn).show();
});
// Error message for no matches found
var $noMatches = $('<h2>No matches found please try again</h2>');
// Add to page
$('.page').append($noMatches);
// hide initially
$noMatches.hide();
// search box on type
$searchCriteria.on('input', function() {
// remove all result classes
$studentItem.each(function() {
$(this).removeClass("result");
});
// value of searched
var text = $(this).val().toLowerCase();
// results of search
var results = $("ul.student-list li:contains('" + text.toLowerCase() + "')");
results.addClass("result");
// show or hide based on result matching div
$studentItem.each(function() {
if ($(this).hasClass('result')) {
$(this).show("slow");
} else {
$(this).hide();
}
});
if (results.length > 10) {
// remove all student items
var initialTen = $studentItem.hide();
// display first 10 student items
initialTen = $studentItem.slice(0, perPage).show();
// show pagination
$('.pagination').show();
// hide no matches message
$noMatches.hide();
} else if (results.length === 0) {
$pagination.hide();
$noMatches.show();
} else {
$pagination.hide();
}
});
As Siguza said, $('#search-criteria') doesn't exist at the time you're fetching it. So, the on function is a good idea, but it should be given like this :
$('.page-header').on('input', '#search-criteria', function() {
//your code
});
What it does is , it will bind the function to the element that is added dynamically in DOM
Here is the jsFiidle
It will work for you. :)
Problem
Suppose that in the backend of my Web application I have a generic string of letters:
seq = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
and an array of positions in such a string:
pos = [(0, 2), (4, 8)]
I need to render this sequence in the frontend by splitting it every n characters. Then when a user clicks a button I need to highlight the sequence between two parameters (taken from pos) for which the button refers to.
My solution
I solve this by implementing a Javascript function formatSequence which splits seq every n characters and iterates through the pos array in order to wrap each substring inside a span tag. The result is something like this:
<pre>
<span class="A">AA</span>AA<span class="B">A</span>
<span class="B">AAA</span>AA
AAAAA
</pre>
When the user clicks the button referring to the class A I simply change the CSS background rule for class A.
It works :) But the function formatSequence is way too complicated imho. It was a pain dealing with multiple lines. I prefer not posting the code since I am looking for other approaches not changing the code of such function.
A better solution?
I think that a (better?) solution would be to implement a function that given two parameters start and end it dynamically highlights the text between them. But it appears to be even more complicated than the previous one (remember that the sequence must be split every n characters and thus the highlight must be multilines).
Any suggestions? Better approach to solve this?
One simple solution would be just to print the full seq multiple times into the HTML and hide every row you don't need at the time. When a user clicks on a button, another row would be displayed (and the first one would be hidden).
HTML:
<div class="rows"></div>
<div class="buttons"></div>
JavaScript (depending on jQuery):
(function generateRowsAndButtons() {
var sequence = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
var position = [ [0,2], [4,8] ];
var $rows = $('.rows');
var $buttons = $('.buttons');
for(var i = 0; i < position.length; i++) {
if(position[i].length !== 2 || position[i][0] > position[i][1]) {
console.log("every position array needs exactly two values with the second larger than the first one");
continue;
}
// the index is used for mapping the button the highlight position
var row = '<div class="row" data-index="' + i + '" style="display: none;">';
// you should add some checks here, if position larger then the length of the string to avoid some misbehaviors. this is of course only necessary if you aren't validating the values on another place.
row += sequence.substring(0, position[i][0]);
row += '<span class="highlighted">';
row += sequence.substring(position[i][0], position[i][1]);
row += '</span>';
row += sequence.substring(position[i][1]);
row += '</div>';
var $row = $(row);
$rows.append($row);
// a button needs the index to find the link the highlighted value
var $button = $('<button data-index="' + i + '">' + position[i] + '</button>');
$buttons.append($button);
}
$buttons.find('button').click(function() {
var index = $(this).data('index');
// hide every row, except the one with the correct index
$rows.find('.row').hide().filter('[data-index="' + index + '"]').show();
});
})();
CSS:
.row .highlighted {
background: yellow;
}
Here is a jsFiddle: https://jsfiddle.net/y8uoou1L/2
I have developed an Android app, which consists in a listview of items populated from strings, which changes the color of each list row depending on a word coincidence.
Now i'm trying to develop same app, for the web. After being investigating, the best way I did found, was using JQuery Mobile.
So, now I want to accomplish the same, a ListView that conditionally changes each list item background-color conditionally.
After several days investigating and learning, I'm populating the list from a JSON, like you can see here in JSFiddle (This is what I've achieved until now, based on another JSFiddle I did found, because I had never used JQuery Mobile.)
//JSON goes above here
$(document).on("pageinit", "#info-page", function () {
//set up string for adding <li/>
var li = "";
//container for $li to be added
$.each(info, function (i, name) {
//add the <li> to "li" variable
//note the use of += in the variable
//meaning I'm adding to the existing data. not replacing it.
//store index value in array as id of the <a> tag
li += '<li>' + name.Número + '<p>' + name.Origen + '</p></li>';'</a></li>';
});
//append list to ul
$("#prof-list").append(li).promise().done(function () {
//wait for append to finish - thats why you use a promise()
//done() will run after append is done
//add the click event for the redirection to happen to #details-page
$(this).on("click", ".info-go", function (e) {
e.preventDefault();
//store the information in the next page's data
$("#details-page").data("info", info[this.id]);
//change the page # to second page.
//Now the URL in the address bar will read index.html#details-page
//where #details-page is the "id" of the second page
//we're gonna redirect to that now using changePage() method
$.mobile.changePage("#details-page");
});
//refresh list to enhance its styling.
$(this).listview("refresh");
});
});
//use pagebeforeshow
//DONT USE PAGEINIT!
//the reason is you want this to happen every single time
//pageinit will happen only once
$(document).on("pagebeforeshow", "#details-page", function () {
//get from data - you put this here when the "a" wa clicked in the previous page
var info = $(this).data("info");
//string to put HTML in
var info_view = "";
//use for..in to iterate through object
for (var key in info) {
//Im using grid layout here.
//use any kind of layout you want.
//key is the key of the property in the object
//if obj = {name: 'k'}
//key = name, value = k
info_view += '<div class="ui-grid-a"><div class="ui-block-a"><div class="ui-bar field" style="font-weight : bold; text-align: left;">' + key + '</div></div><div class="ui-block-b"><div class="ui-bar value" style="width : 75%">' + info[key] + '</div></div></div>';
}
//add this to html
$(this).find("[data-role=content]").html(info_view);
});
So, basically what I want is to change (if it is possible) the colour of each row, depending of the of the word under the row title (or any other variable I could include in the JSON, would only be three variables):
This is what i have in Android, just to clarify what I want:
if (additiveslist.get(position).getOrigen().equals("Vegano")) {
holder.relativeLayout.setBackgroundColor(0xB790D55D);
}
if (additiveslist.get(position).getOrigen().equals("Dudoso")) {
holder.relativeLayout.setBackgroundColor(0x96F6B22D);
}
if (additiveslist.get(position).getOrigen().equals("No vegano")) {
holder.relativeLayout.setBackgroundColor(0x84f51000);
}
And this is how it looks like on Android App:
Hope I explained well and someone can help me, because I am a complete beginner in JQuery Mobile (or maybe I did wrong choosing JQuery Mobile to do this kind of web app...)
You can create CSS classes for each of the background colors e.g.:
.vegano {
background-color: #ABDD87 !important;
}
.dudoso {
background-color: #F5CB98 !important;
}
.novegano {
background-color: #F47D75 !important;
}
Then in the script when you are iterating the data, add the appropriate class to the anchor within the LI based on your criteria, e.g.:
$.each(info, function (i, name) {
//add the <li> to "li" variable
//note the use of += in the variable
//meaning I'm adding to the existing data. not replacing it.
//store index value in array as id of the <a> tag
var bColor = "vegano";
if (name.Origen == "Dudoso") {
bColor = "dudoso";
} else if (name.Origen == "No vegano") {
bColor = "novegano";
}
li += '<li>' + name.Número + '<p>' + name.Origen + '</p></li>';'</a></li>';
});
Here is your updated FIDDLE
P.S. Once you start changing the backcolor, you might want to get rid of the default jQM text shadows with this CSS:
#prof-list li a{
text-shadow: none;
}