How to avoid stop script error in browsers - javascript

I have a page of more than 2500 anchor tag to process. Now in IE it is throwing the stop script error. Is it possible to do as a batch? Taking 500 executing it and then take the another 500 executing it??
This is the code...
ajaxLinks : function(el, flag) {
var links = $(el).find('a');
var notLinkAr=["a[href^=javascript]","#toolbarId ul li>a","#tool_settings .link a",".page-action-links li>a","#tool_settings .label a",".success-map .success-tabs li>a",".success-map .sm_loggedin li>a", ".analyst_cat li>a",".modal",".layer",".newpage",".close",".hideFromPopup",".pagenum",".next",".prev",".delete_src",".tips","#hidr","#backr"];
$(notLinkAr).each(function(index){
var notLinkI=$(notLinkAr[index]);
if($(notLinkI).is("a")){
if($(notLinkI).length>0){
$(notLinkI).each(function(index1){
$(notLinkI[index1]).addClass("dontAjaxify");
});
}
}
});
$(links).each(function(i, obj){
var link = $(obj);
if(!$(obj).hasClass('dontAjaxify')){
link.attr('rel', link.attr('href'));
var rellnk = link.attr('rel');
if(flag=='ajaxified') {
if(/http/.test(rellnk)){
var relurl;
relurl=rellnk.replace((window.location.protocol + "//"+ window.location.hostname),'')
link.attr('rel', relurl);;
}
}
link.bind('click', function(e){}
Iam adding a class for all the anchor tag(which is 2500) in a page.

jQuery's .slice may help you.
http://api.jquery.com/slice/
var count = 0;
var ajaxify = function (el, flags) {
var links = $(el).find('a').slice(count, count + 500);
count = count + 500;
// Do the processing here
if (links.length) {
// Call it next time only if some data is returned in the current call
setTimeout("ajaxify()", 5000);
}
}
The above code is not tested, but should probably work.

Related

HTML/jQuery Save order

I'm using the jquery plugin called shapeshift. It's like jqueryui sortable but with better animations. The divs can be dragged and dropped. But I can't seem to figure out how to save their order so that on browser refesh the order remains the same where I left them.
Here is the jsfiddle http://jsfiddle.net/Shikhar_Srivastava/aC367/
$(".container").shapeshift({minColumns: 3});
I'm initiating the plugin as above.
Please help me on my fiddle.
Thanks.
I would create a cookie. So I would first include the jQuery Cookie script (found here: https://github.com/carhartl/jquery-cookie/blob/master/src/jquery.cookie.js), then create the cookies (one for each each .container) each time an element is moved:
/* save cookie */
$('.container').on("ss-drop-complete", function() {
var containerCookieCounter = 0;
$('.container').each(function() {
/* cookie = 12h */
var date = new Date();
date.setTime(date.getTime() + (720 * 60 * 1000));
$.cookie('savepositions' + containerCookieCounter, $(this).html(), { expires: date, path: '/' });
containerCookieCounter += 1;
});
});
Then, before initiating the shapeshift-function, check if there are existing cookies:
/* cookies... */
if ($.cookie('savepositions0')) {
var containerCounter = 0;
$('.container').each(function() {
$(this).html($.cookie('savepositions' + containerCounter));
containerCounter += 1;
});
}
Here is a working fiddle: http://jsfiddle.net/Niffler/FvUcQ/
Only one container
Fiddle
var $con=$(".container").shapeshift({
minColumns: 3
});
function getPos(id){
var p=localStorage[id];
var ro={left:100000,top:-1,unknown:true};
if(p!==undefined) ro=JSON.parse(p);
//alert('get Pos:'+id+' '+JSON.stringify(ro));
return ro;
}
function setPos(id,p){
//alert('set Pos:'+id+' '+JSON.stringify(p));
localStorage[id]=JSON.stringify(p);
}
function arrange(){
var o={};
var con=$(".container:nth-child(1)");
var els=$(".container:nth-child(1) div");
els.each(function(x){
var me=$(this);
var id=me.attr('id');
var o_=o[id]={};
o_.id=me.attr('id');
o_.p=getPos(id);
});
for(var i in o){
var oo=o[i];
var el=$('#'+oo.id);
if(!oo.unknown){
el.css('left',''+oo.p.left+'px');
}
}
}
function savePs(){
var els=$(".container:nth-child(1) div");
els.each(function(){
var me=$(this);
setPos(me.attr('id'),me.position());
});
}
var $con=$(".container:nth-child(1)");
$con.on('ss-rearranged',function(e,selected){
var id=$(selected);
setTimeout(function(){
//var me=$(selected);
savePs();
//setPos(me.attr('id'),me.position());
},500);
});
arrange();
//savePs();
Fiddle
As commenters have suggested, you need to use localStorage to store and retrieve the state, and save that state after the ss-drop-complete event.
Here is the entire JS I used in this updated jsFiddle:
$(function () {
// retrieve from localStorage if there is a saved state
var saved = localStorage.getItem('arrangement');
if (saved) {
populateArrangement($('.container').parent(), JSON.parse(saved));
}
$(".container").shapeshift({
minColumns: 3
}).on('ss-drop-complete', function () {
// get the new arrangement and serialise it to localStorage as a string
var rows = getArrangement();
localStorage.setItem('arrangement', JSON.stringify(rows));
});
// return the data needed to reconstruct the collections as an array of arrays
function getArrangement() {
var rows = [];
$('.container').each(function () {
var elementsInRow = [];
$(this).find('.ss-active-child').each(function () {
elementsInRow.push({
value: parseInt($(this).text(), 10),
colspan: $(this).data('ss-colspan') || 1
});
});
rows.push(elementsInRow);
});
return rows;
}
// use the arrangement to populate the DOM correctly
function populateArrangement(container, newArrangement) {
$(container).find('.container').remove();
$.each(newArrangement, function (index, row) {
var $container = $('<div class="container"></div>');
$container.appendTo(container);
$.each(row, function (index, element) {
var $div = $('<div></div>');
$div.text(element.value);
if (element.colspan > 1)
$div.attr('data-ss-colspan', element.colspan);
$container.append($div);
});
});
}
});
If you have some sort of server side code you can add the order to a hidden field on the ss-drop-complete function and then post this back to the server on post back. You can then just re-output the values back when the page re-renders and you can use this information in any server side code you need.
I've done something similar when working with jquery mobile and ASP.NET to save back to a database the order.
If not, the local storage option could be a good way to go.

How to for loop in casperjs

I am trying to click a 'next' button N number of times and grab the page source each time. I understand that I can run an arbitrary function on the remote website, so instead of click() I just use the remote function nextPage() How do I run the following, an arbitrary number of times:
var casper = require('casper').create();
casper.start('http://www.example.com', function() {
this.echo(this.getHTML());
this.echo('-------------------------');
var numTimes = 4, count = 2;
casper.repeat(numTimes, function() {
this.thenEvaluate(function() {
nextPage(++count);
});
this.then(function() {
this.echo(this.getHTML());
this.echo('-------------------------');
});
});
});
'i' here is an index I tried to use in a javascript for loop.
So tl;dr: I want lick 'next', print pages source, click 'next', print page source, click 'next'... continue that N number of times.
First, you can pass a value to the remote page context (i.e. to thenEvaluate function like this:
this.thenEvaluate(function(remoteCount) {
nextPage(remoteCount);
}, ++count);
However, Casper#repeat might not be a good function to use here as the loop would NOT wait for each page load and then capture the content.
You may rather devise a event based chaining.
The work-flow of the code would be:
Have a global variable (or at-least a variable accessible to the functions mentioned below) to store the count and the limit.
listen to the load.finished event and grab the HTML here and then call the next page.
A simplified code can be:
var casper = require('casper').create();
var limit = 5, count = 1;
casper.on('load.finished', function (status) {
if (status !== 'success') {
this.echo ("Failed to load page.");
}
else {
this.echo(this.getHTML());
this.echo('-------------------------');
}
if(++count > limit) {
this.echo ("Finished!");
}
else {
this.evaluate(function(remoteCount) {
nextPage(remoteCount);
// [Edit the line below was added later]
console.log(remoteCount);
return remoteCount;
}, count);
}
});
casper.start('http://www.example.com').run();
NOTE: If you pages with high load of JS processes etc. you may also want to add a wait before calling the nextPage :
this.wait(
1000, // in ms
function () {
this.evaluate(function(remoteCount) {
nextPage(remoteCount);
}, count);
}
);
[EDIT ADDED] The following event listeners will help you debug.
// help is tracing page's console.log
casper.on('remote.message', function(msg) {
console.log('[Remote Page] ' + msg);
});
// Print out all the error messages from the web page
casper.on("page.error", function(msg, trace) {
casper.echo("[Remote Page Error] " + msg, "ERROR");
casper.echo("[Remote Error trace] " + JSON.stringify(trace, undefined, 4));
});
You could try using Casper#repeat
This should do, for the most part, what you want:
var numTimes = 10, count = 1;
casper.repeat(numTimes, function() {
this.thenEvaluate(function(count) {
nextPage(count);
}, ++count);
this.then(function() {
this.echo(this.getHTML());
this.echo('-------------------------');
});
});
var global_page_links = [];
casper.then(function(){
for(var i=1; i<=5; i++){
// you just add all your links to array, and use it in casper.each()
global_page_links.push(YOUR_LINK);
}
this.each(global_page_links, function(self, link) {
if (link){
self.thenOpen(link, function() {
console.log("OPENED: "+this.getCurrentUrl());
// do here what you need, evaluate() etc.
});
}
});
});
This is answer to question, how to use for() in casperjs to launch several links

$.getJSON request does not run but next line of code does

I have a $.getJSON request that does not run but the line of code right after the request does. If I remove all the code after the $.getJSON request the request will run. How do I get the request to run iterate over returned data then run code following the request.
var eventList = new Array();
$.getJSON('../index.php?/home/events', function(eventItems){
$.each(eventItems, function() {
var event = this;
var eventItem = new Array();
// format the date and append to span
eventItem[0] = formatMDYDate(formatTimeStamp(this.loc_datetime, false), 0);
// add shortdescription to div
eventItem[1] = this.shortdescription;
// check if longdescription exist
if (this.longdescription) {
// create new anchor element for "More Info" link on events
var link = $('<a></a>');
link.attr('href', '../index.php?/home/event_info');
link.addClass('popup');
link.html('More Info');
//link.bind('click', eventPopUp());
link.bind('click', function() {
var addressValue = event.id;
dialog = $('<div></div>').appendTo('body');
dialog.load('../index.php?/home/event_info',
{id: addressValue});
dialog.modal({
opacity: 80
});
return false;
});
eventItem[2] = link;
}
eventList.push(eventItem);
});
});
// removing the following lines of code will let the .getJSON request run
if (eventList.length > 0) {
write_Events(eventList);
}
I have no idea what is causing this issue, please help!
Asynchronous means that when you call it the JS runtime will not wait for it to finish before executing next line of code. Typically you need to use call backs in this case.
It's something like:
var a="start";
setTimeout(function(){
a="done";
dosomethingWithA(a);
},1000);
if(a=="done"){}//doesn't matter, a is not "done"
function dosomethingWithA(a){
// a is "done" here
}
In your case the code should look something like:
var eventList = new Array();
$.getJSON('../index.php?/home/events', function(eventItems){
$.each(eventItems, function() {
var event = this;
var eventItem = new Array();
// format the date and append to span
eventItem[0] = formatMDYDate(formatTimeStamp(this.loc_datetime, false), 0);
// add shortdescription to div
eventItem[1] = this.shortdescription;
// check if longdescription exist
if (this.longdescription) {
// create new anchor element for "More Info" link on events
var link = $('<a></a>');
link.attr('href', '../index.php?/home/event_info');
link.addClass('popup');
link.html('More Info');
//link.bind('click', eventPopUp());
link.bind('click', function() {
var addressValue = event.id;
dialog = $('<div></div>').appendTo('body');
dialog.load('../index.php?/home/event_info',
{id: addressValue});
dialog.modal({
opacity: 80
});
return false;
});
eventItem[2] = link;
}
eventList.push(eventItem);
});
processEventList();
});
function processEventList(){
// removing the following lines of code will let the .getJSON request run
if (eventList.length > 0) {
write_Events(eventList);
}
}
try
var eventList = new Array();
$.getJSON('../index.php?/home/events', function (eventItems) {
$.each(eventItems, function () {
//....
eventList.push(eventItem);
});
// removing the following lines of code will let the .getJSON request run
if (eventList.length > 0) {
write_Events(eventList);
}
});
Alternatively, you can use PubSub with jquery technique
var eventList = new Array();
$.getJSON('../index.php?/home/events', function (eventItems) {
$.each(eventItems, function () {
//....
eventList.push(eventItem);
});
//publisher
$(document).trigger('testEvent', eventList);
});
//subscriber
$(document).bind("testEvent", function (e, eventList) {
if (eventList.length > 0) {
write_Events(eventList);
}
});
For more detials http://www.codeproject.com/Articles/292151/PubSub-with-JQuery-Events
happy coding.. :)
$.getJSON is an asynchronous call. The callback will not execute until after the current function has executed completely. The code after the call will always run BEFORE the getJSON callback runs.
Its possible the write_Events function is throwing an error and stopping execution, which is why the callback is never running. Or it is actually running but you're not seeing evidence of it for whatever reason called by the extra code.
javascript code never wait for the response from the server and we need to stop the processing of javascript until we get the response from the server.
we can do this by using jquery.Deferred
You can also visit this tutorial.

How to detect if some text box is changed via external script?

I have some jQuery plugin that changes some elements, i need some event or jQuery plugin that trigger an event when some text input value changed.
I've downloaded jquery.textchange plugin, it is a good plugin but doesn't detect changes via external source.
#MSS -- Alright, this is a kludge but it works:
When I call boxWatcher() I set the value to 3,000 but you'd need to do it much more often, like maybe 100 or 300.
http://jsfiddle.net/N9zBA/8/
var theOldContent = $('#theID').val().trim();
var theNewContent = "";
function boxWatcher(milSecondsBetweenChecks) {
var theLoop = setInterval(function() {
theNewContent = $('#theID').val().trim();
if (theOldContent == theNewContent) {
return; //no change
}
clearInterval(theLoop);//stop looping
handleContentChange();
}, milSecondsBetweenChecks);
};
function handleContentChange() {
alert('content has changed');
//restart boxWatcher
theOldContent = theNewContent;//reset theOldContent
boxWatcher(3000);//3000 is about 3 seconds
}
function buttonClick() {
$('#theID').value = 'asd;lfikjasd;fkj';
}
$(document).ready(function() {
boxWatcher(3000);
})
try to set the old value into a global variable then fire onkeypress event on your text input and compare between old and new values of it. some thing like that
var oldvlaue = $('#myInput').val();
$('#myInput').keyup(function(){
if(oldvlaue!=$('#myInput').val().trim())
{
alert('text has been changed');
}
});
you test this example here
Edit
try to add an EventListner to your text input, I don't know more about it but you can check this Post it may help
Thanks to #Darin because of his/her solution I've marked as the answer, but i have made some small jQuery plugin to achieve the same work named 'txtChgMon'.
(function ($) {
$.fn.txtChgMon = function (func) {
var res = this.each(function () {
txts[0] = { t: this, f: func, oldT: $(this).val(), newT: '' };
});
if (!watchStarted) {
boxWatcher(200);
}
return res;
};
})(jQuery);
var txts = [];
var watchStarted = false;
function boxWatcher(milSecondsBetweenChecks) {
watchStarted = true;
var theLoop = setInterval(function () {
for (var i = 0; i < txts.length; i++) {
txts[i].newT = $(txts[i].t).val();
if (txts[i].newT == txts[i].oldT) {
return; //no change
}
clearInterval(theLoop); //stop looping
txts[i].f(txts[i], txts[i].oldT, txts[i].newT);
txts[i].oldT = $(txts[i].t).val();
boxWatcher(milSecondsBetweenChecks);
return;
}
}, milSecondsBetweenChecks);
}

setInterval with other jQuery events - Too many recursions

I'm trying to build a Javascript listener for a small page that uses AJAX to load content based on the anchor in the URL. Looking online, I found and modified a script that uses setInterval() to do this and so far it works fine. However, I have other jQuery elements in the $(document).ready() for special effects for the menus and content. If I use setInterval() no other jQuery effects work. I finagled a way to get it work by including the jQuery effects in the loop for setInterval() like so:
$(document).ready(function() {
var pageScripts = function() {
pageEffects();
pageURL();
}
window.setInterval(pageScripts, 500);
});
var currentAnchor = null;
function pageEffects() {
// Popup Menus
$(".bannerMenu").hover(function() {
$(this).find("ul.bannerSubmenu").slideDown(300).show;
}, function() {
$(this).find("ul.bannerSubmenu").slideUp(400);
});
$(".panel").hover(function() {
$(this).find(".panelContent").fadeIn(200);
}, function() {
$(this).find(".panelContent").fadeOut(300);
});
// REL Links Control
$("a[rel='_blank']").click(function() {
this.target = "_blank";
});
$("a[rel='share']").click(function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
}
function pageURL() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
$.get("loader.php", query, function(data) {
$("#load").fadeIn("fast");
$("#content").fadeOut(100).html(data).fadeIn(500);
$("#load").fadeOut("fast");
});
}
}
This works fine for a while but after a few minutes of the page being loaded, it drags to a near stop in IE and Firefox. I checked the FF Error Console and it comes back with an error "Too many Recursions." Chrome seems to not care and the page continues to run more or less normally despite the amount of time it's been open.
It would seem to me that the pageEffects() call is causing the issue with the recursion, however, any attempts to move it out of the loop breaks them and they cease to work as soon as setInterval makes it first loop.
Any help on this would be greatly appreciated!
I am guessing that the pageEffects need added to the pageURL content.
At the very least this should be more efficient and prevent duplicate handlers
$(document).ready(function() {
pageEffects($('body'));
(function(){
pageURL();
window.setTimeout(arguments.callee, 500);
})();
});
var currentAnchor = null;
function pageEffects(parent) {
// Popup Menus
parent.find(".bannerMenu").each(function() {
$(this).unbind('mouseenter mouseleave');
var proxy = {
subMenu: $(this).find("ul.bannerSubmenu"),
handlerIn: function() {
this.subMenu.slideDown(300).show();
},
handlerOut: function() {
this.subMenu.slideUp(400).hide();
}
};
$(this).hover(proxy.handlerIn, proxy.handlerOut);
});
parent.find(".panel").each(function() {
$(this).unbind('mouseenter mouseleave');
var proxy = {
content: panel.find(".panelContent"),
handlerIn: function() {
this.content.fadeIn(200).show();
},
handlerOut: function() {
this.content.slideUp(400).hide();
}
};
$(this).hover(proxy.handlerIn, proxy.handlerOut);
});
// REL Links Control
parent.find("a[rel='_blank']").each(function() {
$(this).target = "_blank";
});
parent.find("a[rel='share']").click(function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
}
function pageURL() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
var content = $("#content");
$.get("loader.php", query, function(data) {
$("#load").fadeIn("fast");
content.fadeOut(100).html(data).fadeIn(500);
$("#load").fadeOut("fast");
});
pageEffects(content);
}
}
Thanks for the suggestions. I tried a few of them and they still did not lead to the desirable effects. After some cautious testing, I found out what was happening. With jQuery (and presumably Javascript as a whole), whenever an AJAX callback is made, the elements brought in through the callback are not binded to what was originally binded in the document, they must be rebinded. You can either do this by recalling all the jQuery events on a successful callback or by using the .live() event in jQuery's library. I opted for .live() and it works like a charm now and no more recursive errors :D.
$(document).ready(function() {
// Popup Menus
$(".bannerMenu").live("hover", function(event) {
if (event.type == "mouseover") {
$(this).find("ul.bannerSubmenu").slideDown(300);
} else {
$(this).find("ul.bannerSubmenu").slideUp(400);
}
});
// Rollover Content
$(".panel").live("hover", function(event) {
if (event.type == "mouseover") {
$(this).find(".panelContent").fadeIn(200);
} else {
$(this).find(".panelContent").fadeOut(300);
}
});
// HREF Events
$("a[rel='_blank']").live("click", function(event) {
var target = $(this).attr("href");
window.open(target, "_blank");
event.preventDefault();
});
$("a[rel='share']").live("click", function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
setInterval("checkAnchor()", 500);
});
var currentAnchor = null;
function checkAnchor() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
$.get("loader.php", query, function(data) {
$("#load").fadeIn(200);
$("#content").fadeOut(200).html(data).fadeIn(200);
$("#load").fadeOut(200);
});
}
}
Anywho, the page works as intended even in IE (which I rarely check for compatibility). Hopefully, some other newb will learn from my mistakes :p.

Categories