Phantomjs update values of var? - javascript

I have the below phantomjs program where the website contains a drop down list ddlLevel3
var page = require('webpage').create();
page.onConsoleMessage = function(str) {
console.log(str);
}
var z=0;
var z_l=0;
var op1='#ddlDivision'
var op2='#ddlLevel1'
var op3='#ddlLevel2'
var op4='#ddlLevel3'
function selectOption(selector, optionIndex) {
page.evaluate(function(selector, optionIndex){
var op4='#ddlLevel3'
var sel = document.querySelector(selector);
var sel4 = document.querySelector(op4);
sel.selectedIndex = optionIndex;
var event = document.createEvent("UIEvents"); // See update below
event.initUIEvent("change", true, false);
sel.dispatchEvent(event);
this.dispatchEvent(event);
z_l=sel4.length;
console.log("len: "sel4.length+" "+z_l);
}, selector, optionIndex);
}
page.open(...{
function loop4 () {
selectOption(op4,z);
window.setTimeout(function () {
go();
z++;
if (z < z_l) {
loop4();
}
}, 3000);
}
loop4();
});
I am trying to run loop4(). But the value of z_l is not changing from '0'.
In line console.log("len: "sel4.length+" "+z_l); Here values is proper.
But its not reflected back in loop4() in if (z < z_l), and remains 0 always.
What am I doing wrong?

I I wanted to get the value of z_l updated.I just need to use page.evaluate and assign it to z_l as below. Just made these changes in loop4().
function loop4 () {
var z_l = page.evaluate(function() {
var op4='#ddlLevel3'
return document.querySelector(op4)
});
selectOption(op4,z);
.
.
.
}

Related

EVAL dangerous How to replace it

I have the following code for a pop-up window (client request). It uses eval which I understand is dangerous. Is there a way to re-write the script below so it does not use (eval)?
/* exported popup_default , popup_help , popup_sitemap , popup_footerlinks */
var matchClass = ['popup_default', 'popup_sitemap', 'popup_footerlinks', 'popup_help'];
var newwindow = ''
var popup_default = 'width=800,height=640,toolbar=0,menubar=0,location=0,status=1,scrollbars=1,resizable=1,left=250,top=200';
var popup_help = 'width=700,height=650,toolbar=0,menubar=0,location=0,status=1,scrollbars=1,resizable=1,left=100,top=100';
var popup_sitemap = 'width=1000,height=600,toolbar=0,menubar=0,location=0,status=1,scrollbars=1,resizable=1,left=100,top=100';
var popup_footerlinks = 'width=800,height=500,toolbar=0,menubar=0,location=0,status=1,scrollbars=1,resizable=1,left=250,top=200';
function pop_ups() {
"use strict";
var x = 0;
var popClass;
while (x < matchClass.length) {
popClass = "'." + matchClass[x] + "'";
$(eval(popClass)).click(function() {
var popurl = $(this).attr('href');
var popupSpecs = $(this).attr('class');
var popupName = Math.floor(Math.random() * 10000001);
newwindow = window.open(popurl, popupName, eval(popupSpecs));
return false;
});
x++;
}
}
$(function() {
"use strict";
pop_ups();
});
You'll want to use
"use strict";
function makePopup(className, specs) {
$('.'+className).click(function(e) {
e.preventDefault();
var popupName = Math.floor(Math.random()*10000001);
window.open(this.href, popupName, specs);
});
}
var popups = {
popup_default: 'width=800,height=640,toolbar=0,menubar=0,location=0,status=1,scrollbars=1,resizable=1,left=250,top=200',
popup_help: 'width=700,height=650,toolbar=0,menubar=0,location=0,status=1,scrollbars=1,resizable=1,left=100,top=100',
popup_sitemap: 'width=1000,height=600,toolbar=0,menubar=0,location=0,status=1,scrollbars=1,resizable=1,left=100,top=100',
popup_footerlinks: 'width=800,height=500,toolbar=0,menubar=0,location=0,status=1,scrollbars=1,resizable=1,left=250,top=200'
};
$(function() {
for (var key in popups)
makePopup(key, popups[key]);
});
Instead of the first eval, just use string concatenation. Instead of the second eval, use an object to look up a property name.
Thanks #Bergi
I updated that last part of the script because it threw an error: "The body of a for in should be wrapped in an if statement"
$(function() {
"use strict";
for (var key in popups) {
if(popups.hasOwnProperty(key))
{
makePopup(key, popups[key]);
}
}
});
Thanks again for the help

Jquery: delay 2 seconds before sending json request

Below is my script. It's a autosuggestion search script. The problem is that it penetrates the server with a huge amount of requests (it sends a request after each inserted character).
I need to change the script so that it waits 2 seconds after user has finished typing (and has inserted at least 3 characters) and only then sends request to the php file.
(function($){
$.fn.fsearch = function(){
var $searchInput = $(this);
$searchInput.after('<div id="divResult"></div>');
$resultDiv = $('#divResult');
$searchInput.focus();
$searchInput.addClass('searchi');
$resultDiv.html("<ul></ul><div id='search-footer' class='searchf'></div>");
$searchInput.keyup(function(e) {
var q=$(this).val();
if(q.length>2&&q.length<30){
var current_index = $('.selected').index(),
$options = $resultDiv.find('.option'),
items_total = $options.length;
$resultDiv.fadeIn();
$resultDiv.find('#search-footer').html("<img src='img/loader.gif' alt='Searching...'/>");
$.getJSON("/search.php",{searchword: q},function(jsonResult) {
var str='';
for(var i=0; i<jsonResult.length;i++)
{
str += '<li id=' + jsonResult[i].uid + ' class="option"><img class="profile_image" src="photos/'+jsonResult[i].media+'" alt="'+jsonResult[i].username+'"/><span class="name">' + jsonResult[i].username + '</span><br/>'+jsonResult[i].country+'</li>';
}
$resultDiv.find('ul').empty().prepend(str);
$resultDiv.find('div#search-footer').text(jsonResult.length + " results found...");
$resultDiv.find('ul li').first().addClass('selected');
});
$resultDiv.find('ul li').live('mouseover',function(e){
current_index = $resultDiv.find('ul li').index(this);
$options = $resultDiv.find('.option');
change_selection($options,current_index);
});
function change_selection($options,current_index){
$options.removeClass('selected');
$options.eq(current_index).addClass('selected');
}
} else{
$resultDiv.hide();
}
});
jQuery(document).live("click", function(e) {
var $clicked = $(e.target);
if ($clicked.hasClass("searchi") || $clicked.hasClass("searchf")){
}
else{
$resultDiv.fadeOut();
}
});
$searchInput.click(function(){
var q=$(this).val();
if(q.length>2&&q.length<30) {
$resultDiv.fadeIn();
}
});
$resultDiv.find('li').live("click",function(e){
var id = $(this).attr('id');
var name = ($(this).find('.name').text());
$searchInput.val(name);
});
};
})(jQuery);
After reading this question I added the following solution to my script:
var timer;
var x;
$(".some-input").keyup(function () {
if (x) { x.abort() } // If there is an existing XHR, abort it.
clearTimeout(timer); // Clear the timer so we don't end up with dupes.
timer = setTimeout(function() { // assign timer a new timeout
x = $.getJSON(...); // run ajax request and store in x variable (so we can cancel)
}, 2000); // 2000ms delay, tweak for faster/slower
});
unfortunately, it does not work:
TypeError: e.nodeName is undefined jquery-1.11.0.min.js:4:9004

Change images randomly on click without repeating

I found this code on Stack Overflow: change images on click.
And it works for me. I want it to be random, but how can i prevent it from repeating the images. It should first repeat the images, when the user has clicked through all images.
I have made an JSfiddle with my code: http://jsfiddle.net/gr3f4hp1/
JQuery code:
var images = ["02.jpg","03.jpg","01.jpg"];
$(function() {
$('.change').click(function(e) {
var image = images[Math.floor(Math.random()*images.length)];
$('#bg').parent().fadeOut(200, function() {
$('#bg').attr('src', 'items/'+image);
$(this).fadeIn(200);
});
});
});
Keep track of the numbers that you have generated, and if its a repeat then get a new number.
You can Work Around This
var usedImages = {};
var usedImagesCount = 0;
function displayImage(){
var num = Math.floor(Math.random() * (imagesArray.length));
if (!usedImages[num]){
document.canvas.src = imagesArray[num];
usedImages[num] = true;
usedImagesCount++;
if (usedImagesCount === imagesArray.length){
usedImagesCount = 0;
usedImages = {};
}
} else {
displayImage();
}
}
you can try this code .
var images = ["02.jpg","03.jpg","01.jpg"];
var imagecon = [];
$(function() {
$('.change').click(function(e) {
if(images.length == 0) { // if no image left
images = imagecon; // put all used image back
imagecon = []; // empty the container
}
var index = Math.floor(Math.random()*images.length);
var image = images[index];
imagecon.push(image); // add used image
images.splice(index,1); // remove it to images
$('#bg').parent().fadeOut(200, function() {
$('#bg').attr('src', 'items/'+image);
$(this).fadeIn(200);
});
});
});
you could add a class to every image that appears like:
image.addClass("viewed")
and write an if statement that show the image only if it hasn't the class viewed:
if(!image.hasClass(viewed)){
(show the image methods);
image.addClass("viewed")
}
I'm not going to make all the code for you, just try this way, learn, fail, success, have fun! :D
Try this image change according to imgCnt variable.
var images = ["01.jpg","02.jpg","03.jpg","01.jpg"];
var imgCnt=1;
$(function() {
$('.change').click(function(e) {
// var image = images[Math.floor(Math.random()*images.length)];
if(imgCnt >= images.length){
imgCnt=0;
}
var image =images[imgCnt];
// alert(image);
$('#bg').parent().fadeOut(200, function() {
$('#bg').attr('src', 'items/'+image);
$(this).fadeIn(200);
imgCnt++;
});
});
});
Demo
There are lots of method here i just push the value of visited image in to Visited array
Campate two array show only differ element
var images = ["02.jpg","03.jpg","01.jpg"];
var visited = [];
$(function() {
$('.change').click(function(e) {
var image = images[Math.floor(Math.random()*images.length)];
visited.push(image);
$('#bg').parent().fadeOut(200, function() {
y = jQuery.grep(images, function(value) {
if(jQuery.inArray(value, visited) == -1){
$('#bg').attr('src', 'items/'+image);
$(this).fadeIn(200);
}
});
} });
});
});
I hopes its help

How to call JavaScript function repeatedly

I am trying to call the JavaScript function repeatedly after the execution.
function startSlide(){
var products = [
['images/product_images/footwear/footwear_1.jpeg'],
['images/product_images/mobile/mobile_1.jpeg'],
['images/product_images/camera/camera_1.jpeg'],
['images/product_images/fashion/fashion_1.jpeg'],
['images/product_images/laptop/laptop_1.jpeg'],
['images/product_images/furniture/furniture_1.jpeg']
];
for (var i = 0; i < products.length; i++) {
var image = products[i][0];
imgslider(image, i * 800);
}
};
function imgslider(image, timeout)
{
window.setTimeout(function() {
document.getElementById('imgslider').innerHTML = "";
var product = document.getElementById('imgslider');
var elem = document.createElement("img");
product.appendChild(elem);
elem.src = image;
},timeout);
startSlide();
}
The startSlide() function iterates the array and fetch the value from array and call the function imgslider(). the imgslider() function appends the image to the div.
at the end of the imgslider() i am trying to call the startSlide() so that it could continue the execution.... but its not working. how can i do this?
The problem is your code is creating an infinite recursion...
Maintianing your code structure you can add a flag to fix the problem
function startSlide() {
var products = [
['//placehold.it/64X64&text=1'],
['//placehold.it/64X64&text=2'],
['//placehold.it/64X64&text=3'],
['//placehold.it/64X64&text=4'],
['//placehold.it/64X64&text=5']
];
for (var i = 0; i < products.length; i++) {
var image = products[i][0];
imgslider(image, i * 800, i == products.length - 1);
}
};
function imgslider(image, timeout, last) {
window.setTimeout(function() {
document.getElementById('imgslider').innerHTML = "";
var product = document.getElementById('imgslider');
var elem = document.createElement("img");
product.appendChild(elem);
elem.src = image;
if (last) {
setTimeout(startSlide, 800);
}
}, timeout);
}
startSlide()
<div id="imgslider"></div>
If you want to loop, then you can use setInterval() instead
function startSlide() {
var products = [
['//placehold.it/64X64&text=1'],
['//placehold.it/64X64&text=2'],
['//placehold.it/64X64&text=3'],
['//placehold.it/64X64&text=4'],
['//placehold.it/64X64&text=5']
],
i = 0;
setInterval(function() {
imgslider(products[i][0]);
if (++i >= products.length) {
i = 0
}
}, 800);
};
function imgslider(image) {
document.getElementById('imgslider').innerHTML = "";
var product = document.getElementById('imgslider');
var elem = document.createElement("img");
product.appendChild(elem);
elem.src = image;
}
startSlide()
<div id="imgslider"></div>
That's because window.setTimeout only calls the function once, so you should use window.setInterval instead. Something like this:
window.setInterval(function () { /* code to update picture... */ }, 3000);
If it's still not working you can check the console log for errors.
That's F12 in IE or Ctrl+Shift+J in Chrome.

Using each() method to animate typing of code

I am trying to use JQuery's each() method to animate typing on multiple blocks of code, but I keep getting this error:
Uncaught TypeError: Cannot call method 'createDocumentFragment' of undefined
Check out some example code in this Fiddle...
And for your convenience, the JS is listed below:
$('.typeanimator').each(function(index) {
console.log(index);
var codeBlock = $(this).text();
var done;
var blockLength = codeBlock.length;
var charCounter = 0;
$(this).text('|');
(function typeAnimator() {
var typingSimulator = Math.round(Math.random() * (200));
done = setTimeout(function() {
console.log("Le print.");
charCounter++;
var typeSection = codeBlock.substring(0, charCounter);
$(this).text(typeSection + '|');
typeAnimator();
if (charCounter == blockLength) {
$(this).text($(this).text().slice(0, -1));
clearTimeout(done);
}
}, typingSimulator);
}());
});
The problem is in the use of $(this) inside the typeAnimator function. You are actually want to refer the this from the parent function but instead you are getting a totally different this. So, use a temporary variable to store the $(this)
$('.typeanimator').each(function(index) {
...
var self = $(this);
self.text('|');
(function typeAnimator() {
var typingSimulator = Math.round(Math.random() * (200));
done = setTimeout(function() {
...
self.text(typeSection + '|');
typeAnimator();
if (charCounter == blockLength) {
self.text(self.text().slice(0, -1));
clearTimeout(done);
}
}, typingSimulator);
}());
});
Updated fiddle
$('.typeanimator').each(function(index, current) {
console.log(index);
var codeBlock = $(current).text();
var done;
var blockLength = codeBlock.length;
var charCounter = 0;
$(current).text('|');
(function typeAnimator(context) {
var typingSimulator = Math.round(Math.random() * (200));
done = setTimeout(function() {
console.log("Le print.");
charCounter++;
var typeSection = codeBlock.substring(0, charCounter);
$(context).text(typeSection + '|');
typeAnimator(context);
if (charCounter == blockLength) {
$(context).text($(context).text().slice(0, -1));
clearTimeout(done);
}
}, typingSimulator);
}(current));
});
This should work, always remember that javascript is really picky about the context when using 'this'. As well .each() has nifty parameter of current item :) Gl, and good code.

Categories

Resources