Something not right with AJAX code - javascript

I have a page with a menu of categories and subcategories of products.
Categories have a class 'category' and subcategories have a class 'subcategory'. When either is clicked some AJAX sends the category to some php to compile the html which the AJAX then sends back to the page to populate a div. This part works fine.
There is a function in the code to split the returned records. So say there are 6 records and the page is to show 2 at a time then there are 3 pages. I get the correct amount of pages displayed(1 2 3) but all 6 records displayed on each!
Can anyone see the problem?
$('a.category, a.subcategory').click(function (e) {
// first stop the link to go anywhere
e.preventDefault();
// get the class of the link
var linkClass = $(this).attr("class");
//get the text of the link by converting the clicked object to string
var linkText = new String(this);
// the value after the last / is the category ID
var categoryValue = linkText.substring(linkText.lastIndexOf('/') + 1);
// put the post parameters into 'params' to pass through the AJAX post request
var params = {};
params[linkClass] = categoryValue;
// send the category ID to the getProductData.php script using jquery ajax post method
// send along a category ID
// on success insert the returned text into the chosen div
$.post('../inc/showproducts.php', params, function (data) {
//find total number of records
var totalRecords = $(data).length;
//define how many records shown per page
var pageSize = 2
//work out number of pages needed to hold records
var numOfPages = Math.ceil(totalRecords / pageSize);
//make page links
var i,
pageLinks = '<div class="pageLinks">';
for (i = 0; i < numOfPages; i++) {
pageLinks += '<a href="#" onclick="showProductPage(' + i + ');return false;">' + (i + 1) + '<\/a> ';
}
pageLinks += '<\/div>';
//display returned data and page links in chosen div (.showproduct)
$('.showproduct').html(pageLinks + data);
showProductPage(0);
});
});
//function to slice up records into pages
function showProductPage(pageNo) {
var perPage = 2;
var start = pageNo * perPage;
var end = start + perPage;
$('.image').hide().filter(function (index) {
return ((index > (start - 1)) && (index < end));
}).show();
}

//check out this line of your code
$('.showproduct').html(pageLinks + data);
The data var has all the records in it still. You have to get each data[position] with a for loop that iterates based on pageSize * pageNum. So page 1 would look like
var iterationSize = pageSize * pageNum; //(2 * 1 = 2)
var i;
var j = 0;
var pageData[];
for(i = pageNum - 1; i < iterationSize; i++, j++){
pageData[j] = data[i];
}
$('.showproduct').html(pageLinks + pageData.join(''));

Related

Speeding up UrlFetch Google App Scripts?

The goal is to run through about 10,000 lines of links. Determine which have page numbers > 3 and highlight the first column. I have all of this done, but the problem is that it takes Url Fetch too long, I run into a maximum run time error. Is there anyway I can speed up this code so I can run through the 10,000 lines?
function readColumns() {
//program is going to run through column 3 by going through the amount of rows, truncating last three characters to see if pdf, then highlighting first column
var sheet = SpreadsheetApp.getActiveSheet();
var columns = sheet.getDataRange();
var rowNum = columns.getNumRows();
var values = columns.getValues();
var html;
var htmlString;
for(var i = 1; i <= rowNum; i++){
var columnLogger = values[i][2];
try{
html = UrlFetchApp.fetch(values[i][2],
{
muteHttpExceptions: true,
}
);
}catch(e){
Logger.log("Error at line " + i);
var error = true;
}
htmlString = html.getContentText();
var index = htmlString.indexOf("Pages") + 6;
var pageNumber = parseInt(htmlString.charAt(index),10);
var lastChars = "" + columnLogger.charAt(columnLogger.length-3) + columnLogger.charAt(columnLogger.length-2) + columnLogger.charAt(columnLogger.length-1);
if((error) || (!lastChars.equals("pdf") && values[i][6].equals("") && !pageNumber >= 3)){
//goes back to first column and highlights yellow
var cellRange = sheet.getRange(1, 1, rowNum, 3)
var cell = cellRange.getCell(i+1, 1)
cell.setBackground("yellow");
}
}
}
Edit - short scripts:
function foreverCall(){
var start = 1480;
for(;;){
readColumns(start);
start = start + 100;
}
}
function readColumns(start) {
//program is going to run through column 3 by going through the amount of rows, truncating last three characters to see if pdf, then highlighting first column
var sheet = SpreadsheetApp.getActiveSheet();
var columns = sheet.getDataRange();
var rowNum = columns.getNumRows();
var values = columns.getValues();
var html;
var htmlString;
var error;
for(var i = start; i < start+100; i++){
if(loop(values, error, html, htmlString, rowNum, sheet, columns, i)){
var cellRange = sheet.getRange(1, 1, rowNum, 3)
var cell = cellRange.getCell(i, 1)
cell.setBackground("yellow");
}
}
}
function loop(values, error, html, htmlString, rowNum, sheet, columns, i){
var columnLogger = values[i][2];
var lastChars = columnLogger.slice(-4);
if(!lastChars.equals(".pdf") && values[i][6].equals("")){
return true;
}else{
try{
error = false
html = UrlFetchApp.fetch(values[i][2].toString());
if(html == null){
error = true;
}
}catch(e){
Logger.log("Error at line " + i);
error = true;
}
if(!error){
htmlString = html.getContentText();
var index = htmlString.indexOf("Pages") + 6;
var pageNumber = parseInt(htmlString.charAt(index),10);
}
//goes back to first column and highlights yellow
if(error || !pageNumber >= 3){
return true;
}
}
return false;
}
You can replace this:
var lastChars = "" + columnLogger.charAt(columnLogger.length-3) + columnLogger.charAt(columnLogger.length-2) + columnLogger.charAt(columnLogger.length-1);
With this:
var lastChars = columnLogger.slice(-3);
You could also initiate the fetch script from an html sidebar or dialog to run short batches and then return back to the success handler which could then initiate another batch depending upon the return value. The return value could also be used to start the next batch at the next row. It would actually take longer to run but you could probably stay well under the script limit by keeping your batches small.
You can replace with the line with
var lastChars = columnLogger.slice(-3);

Return String variable delayed

I have a web page with a table identified by "table-rank" class.
This table has 3 pages : to go on next page, i use the .click function on the net button.
I tried to build a finalHtml string by capturing specific element in each lines of the table.
Problem : The finalHtml contains 3 times the datas of the first page of the table. No data of the second page and third page is captured..
It's because, when i click on the button, it's asynchronous, and the first loop continue to parse the table which have not been already refreshed. How can i do, to be sure that the data have been loaded when i click on the next button ?
function getClassement() {
var finalHtml = '' ;
for (var k=0; k<2; k++) {
for (var i=0; i<$(".table-rank tbody tr").length; i++) {
var currentLine = $(".table-rank tbody tr")[i];
// Get position
var positionEl = $(currentLine).find(".ng-binding")[0];
var position = $(positionEl).text();
// Get id
var idEl = $(currentLine).find(".ng-binding")[1];
var id = $(idEl).text();
// Get prenom/nom
var nomPrenom = "test";
// Nombre de paris
var nbrParisEl = $(currentLine).find(".ng-binding")[2];
var nbParis = $(nbrParisEl).text();
// Nombre de bons paris
var nbrBonsParisEl = $(currentLine).find(".ng-binding")[3];
var nbBonsParis = $(nbrBonsParisEl).text();
// Score exacts
var scoresExactsEl = $(currentLine).find(".ng-binding")[4];
var scoresExacts = $(scoresExactsEl).text();
// Points totals
var pointsTotalEl = $(currentLine).find(".ng-binding")[7];
var pointsTotals = $(pointsTotalEl).text();
finalHtml = finalHtml + "<tr><td><span class='position'>"+position+"</span></td><td>"+id+"</td><td>"+nomPrenom+"</td><td>"+nbParis+"</td><td>"+nbBonsParis+"</td><td>"+scoresExacts+"</td><td><span class='total'>"+pointsTotals+"</span></td></tr>";
}
// Go next page
$(".pager a")[1].click();
}
return finalHtml;
}

Array is not accessible outside of Casper repeat function

My goal is to get each job link of a job site, go to each Job detail page by following Job link, download and save the detail in html through CASPERJS.
As id of each Job link change each time we back & forth between job link and job detail page, I need to get all the Job id each time under casper.repeat . But NoOfLink array is become empty outside of repeat function [I comment that part in code]. What is the problem?
var casper = require('casper').create();
var noOfRecordsToLoop = 0;
var TotalNoofNullElement = 0;
var NoOfLink = [];
var x = require('casper').selectXPath;
casper.echo('\nStart loding site......');
//---------------------------------------------Load and Scroll the site---------------------------------------//
casper.start('https://........../...../.......Careers/');
casper.wait(10000, function () {
//---------Total no of Job posting------//
var noOfRecords = this.fetchText(x('//*[#id="...........................jobProfile......"]'));
noOfRecordsToLoop = noOfRecords.replace(/[^0-9]/g, "");
var totalNoOfPage = Math.ceil(parseInt(noOfRecords) / 50);
casper.echo('\nStart scrolling site......');
casper.repeat(totalNoOfPage, function () {
this.scrollToBottom(); //-----------------------Scroll down
casper.wait(10000, function () {})
})
})
//------------------------------------------------Load and Scroll the site---------------------------------------//
casper.then(function () {
//-----------------------------------------Get all the link elements --------------------------//
var countForLink = 0;
var numTimesForRpt = noOfRecordsToLoop;
var numTimes = noOfRecordsToLoop;
casper.repeat(numTimesForRpt, function () {
RetElement = this.evaluate(function () {
var startingRow = '//*[contains(#id, "...-uid-")]'
var element = __utils__.getElementByXPath(startingRow).getAttribute('id');
return element;
});
var count = RetElement.replace(/[^0-9]/g, "");
casper.repeat(numTimes, function () {
var MatchElements = this.evaluate(function (count) {
var xp = '//*[contains(#id, "...-uid-' + count + '")]'
var element = __utils__.getElementByXPath(xp).getAttribute('id');
return element;
}, count++);
if (!MatchElements) {
TotalNoofNullElement = TotalNoofNullElement + 1
} else {
NoOfLink.push(MatchElements);
}
//**Here array elements are accessible**
for (var k = 0; k < NoOfLink.length; k++) {
this.echo(NoOfLink[k]);
}
});
//**But here array elements are not accessible outside of repeat** function
this.echo("Size of array is" + NoOfLink.length);
for (var q = 0; q < NoOfLink.length; q++) {
this.echo(NoOfLink[q]);
}
//-----------------------------------------Get all the link elements----------------------------//
//------------------------------------Go to the Job Detail Page Extract HTML and Save---------------------------//
this.echo("\n Inside repeat to Generate HTML");
var num = NoOfLink[countForLink];
this.echo("\nLink id is " + NoOfLink[countForLink]);
num = parseInt(num.replace(/[^0-9]/g, ""));
this.echo("\nNum is " + num);
//-----------------Click to go to the Job Detail Page------------------//
casper.thenClick(x('//*[#id="..-uid-' + num + '"]/div/div'));
casper.wait(5000, function getJobDetail() {
var content = this.getElementInfo(x(".//*[contains(#id,'......t-uid-')]")).html;
var divStart = '<div id="extrdHtml">'
var divEnd = '</div>'
var body = divStart + content + divEnd
this.echo("\nContent of Job detail :" + body);
var fs = require('fs');
fs.write('extractedJob' + NoOfLink[countForLink] + '.html', body, 'w');
this.echo("\nFile saved");
//------------------------------------Go to the Job Detail Page Extract HTML and Save---------------------------//
}); //casper.wait
casper.back();
casper.wait(5000);
countForLink++
}); //casper.repeat
}); //casper.then
//-------------------------------------------Get all the link elements------------------------------//
casper.run();
There are two repeat loops.
casper.repeat(numTimesForRpt, function () { - This is main outer loop , where the 2nd loop resides.
casper.repeat(numTimes, function () – Where I am getting the link and populating NoOfLink array. I am trying to get the array element value outside of this 2nd loop(within main outer loop) but it is not working.
All then* and wait* functions are asynchronous step functions. If you call them, you're scheduling a step that is executed at the end of the current step. casper.repeat() is a function that uses casper.then() and is therefore also asynchronous. Every synchronous code that comes after casper.repeat() will be executed before the contents of the repeat callback.
You have two options:
Wrap everything that comes after casper.repeat() in a casper.then() to make it asynchronous or
Use a normal synchronous loop instead of repeat, if the callback of repeat doesn't need to be evaluated asynchronously like in your case.
By the way, you can oftentimes reduce your code a bit by utilizing the helper functions that CasperJS provides. For example, you don't need to use evaluate() only to get the id attributes of some elements by XPath. You can do that with casper.getElementsAttribute().
Example:
var count = RetElement.replace(/[^0-9]/g, "");
for(var i = count; i < (numTimes + count); i++) {
var MatchElements = this.getElementsAttribute(x('//*[contains(#id, "...-uid-' + i + '")]'), 'id');
if (!MatchElements) {
TotalNoofNullElement = TotalNoofNullElement + 1
} else {
NoOfLink.push(MatchElements);
}
//**Here array elements are accessible**
for (var k = 0; k < NoOfLink.length; k++) {
this.echo(NoOfLink[k]);
}
}

jQuery Pagination next and previous buttons fail after hitting zero or past last page

previous and Next buttons don't have limitations, ie: can move before and after first and last pages... cant seem to limit this.
I've created if statements to try and stop the button from executing but it wont work. any ideas?
jsFiddle: https://jsfiddle.net/s7ac8aq3/
$(function() {
$(document).ready(function(){
//amount of items on page
var num = $('.post').length;
//set items per page
var itemsPerPage = 1;
var nav = false;
//array of all items
var items = $(".post");
//rounds up to the nearest whole number -- number of pages needed to display all results
var numOfPages = Math.ceil((num / itemsPerPage));
//container div
var paginationContainer = $("#pagination-container");
//initial link num
var linkNum = 1;
paginationContainer.prepend("<button class='pagination' id='btn-prev' value='prev'>Prev</button>");
//creates all pagination links as input buttons (can be anything... li, a, div, whatever)
for(i = 0; i < numOfPages; i++)
{
paginationContainer.append("<button class='pagination' id='btn-" + (i + 1) +"' " + "value='" + (i + 1) + "'>" + (i + 1) + "</button>");
}
paginationContainer.append("<button class='pagination' id='btn-next' value='next'>Next</button>");
//does the initial filtering of the items, hides anything greater than page 1
items.filter(":gt(" + (itemsPerPage -1) + ")").hide();
//finds the input feilds and executes onclick
paginationContainer.find('button').on('click', function(){
//REQUIRED RESETS NAV BOOL SO CLICKS WILL REGISTER
nav = false;
//stores the value of the link in this var
var val = $(this).val();
//if value is next or prev
if(val == "prev")
{
if(linkNum > 1)
{
nav = true;
linkNum = linkNum - 1;
var currentBtn = paginationContainer.find("#btn-" + linkNum);
var otherButtons = paginationContainer.find('button');
otherButtons.attr('class', "pagination");
currentBtn.attr('class', "current");
currentBtn.focus();
}
}
else if (val == "next")
{
if(linkNum < numOfPages)
{
nav = true;
linkNum = linkNum + 1;
var currentBtn = paginationContainer.find("#btn-" + linkNum);
var otherButtons = paginationContainer.find('button');
otherButtons.attr('class', "pagination");
currentBtn.attr('class', "current");
currentBtn.focus();
}
}
if(nav == false)
{
//reoves the current class from all buttons before reassigning
var otherButtons = paginationContainer.find('button');
linkNum = $(this).val();
otherButtons.attr('class', "pagination");
//assigns current class to current button
$(this).attr("class", "current");
}
//creates an array of items to hide based on if the set results are less than the link num
var itemsToHide = items.filter(":lt(" + ((linkNum-1) * itemsPerPage) + ")");
// adds any items that are greater than the set results from the link num to the hide array
$.merge(itemsToHide, items.filter(":gt(" + ((linkNum * itemsPerPage) -1) + ")"));
// hides the items in hide array
itemsToHide.hide();
//shows all items NOT in the hide array
var itemsToShow = items.not(itemsToHide);
itemsToShow.show();
});
});
});
A little debugging of your jsFiddle identified the problem. In this part of the code:
} else if (val == "next") {
if (linkNum < numOfPages) {
nav = true;
linkNum = linkNum + 1;
the value of linkNum is sometimes being stored as a string. As a result, adding "3"+1 produces "31" in JavaScript.
The trivial solution is to convert it to an integer before the addition:
linkNum = parseInt(linkNum,10) + 1; // always use a radix
https://jsfiddle.net/mblase75/s7ac8aq3/3/
However, I would instead prefer to solve the problem at its source, a few lines down:
if (nav == false) {
var otherButtons = paginationContainer.find('button');
linkNum = $(this).val();
When you store linkNum in the first place, .val() returns a string. Parse it as an integer right away:
linkNum = parseInt($(this).val(),10);
https://jsfiddle.net/mblase75/s7ac8aq3/4/
and then you don't have to change it before performing the addition.
Your problem in linkNum variable, when you click on certain page number, variable gets a string value, after that when you trying to add 1 you receive a new string, for example "3" + 1 => "31", "4" + 1 => "41"

Add prev & next li's to pagination function

I want to add prev and next li's to my pagination function. The function itself works perfectly and shows the amount of pages by the amount of rows you want to view received from a dropdown .val();
function pagination() {
$('table[data-provide=pagination]').each(function () {
var $table = $('#foo');
var $pager = $('<ul></ul>');
var currentPage = 0;
var numPerPage = $("#bar").val();
var numRows = $table.find('.someclass').length;
var numPages = Math.ceil(numRows / numPerPage);
$table.unbind('repaginate');
$table.bind('repaginate', function () {
$table.find('.someclass').hide().slice(currentPage * numPerPage, (currentPage + 1) * numPerPage).show();
});
for (var page = 0; page < numPages; page++) {
var link = '' + page + '';
$('<li></li>').html(link).on('click', {
newPage: page
}, function (event) {
currentPage = event.data['newPage'];
$table.trigger('repaginate');
$(this).addClass('active').siblings().removeClass('active');
}).appendTo($pager);
};
var prev = '<li id="pagiprev">&laquo</li>';
var next = '<li id="paginext">&raquo</li>';
$pager.append(next);
$pager.prepend(prev);
$pager.find("li:first-child").addClass('active');
$($table.data('pager')).html($pager);
$table.trigger('repaginate');
});
};
Now Ive added:
var prev = '<li id="pagiprev">&laquo</li>';
var next = '<li id="paginext">&raquo</li>';
$pager.append(next);
$pager.prepend(prev);
But apparently it is not that easy as I thought. Of course making the next and prev li's work so it jumps to the next of prev page is step 1. It should also add or remove the 'active' class based on the last or first page as it does not make sense to be able to click on the prev button if you are on the first page.

Categories

Resources