I'm trying to write a reusable bit of code for attaching scroll-to click events to various DOM nodes by using data attributes. Here's what I have so far:
HTML
<li class="scroll-to-anchor" data-dest='top'></li>
<div id='top'></div>
JS
if ($('.scroll-to-anchor').length) {
$('.scroll-to-anchor').each(function () {
var instance = $(this);
if ($(this).attr('data-dest')) {
var destination = $(this).data('dest');
if ($('#' + destination).length) {
instance.click(function () {
alert('click');
// Scroll to destination
})
} else {
throw 'Not a valid scroll-to anchor'
}
} else {
throw 'No data attribute present'
}
});
}
As you can see, the function is supposed to:
Check if any .scroll-to-anchor nodes exist
If they do, run them through an each
Check if .scroll-to-anchor has a data-dest attribute
If it does, check that the attribute corresponds to a DOM node
If it does, attach the click event
Everything is working fine, but the click event isn't attaching. I have a feeling this is scope related, but I can't figure it out...
throw may breaks your loop.
You may want to use console.error() instead.
$(".scroll-to-anchor").each(function() {
var instance = $(this),
destination = instance.data('dest'),
element = $("#" + destination);
if (destination) {
if (element) {
instance.on("click", function() {
console.info("Anchor clicked");
$('html, body').animate({
scrollTop: element.offset().top
}, 500);
});
} else {
console.error("Destination not found");
}
} else {
console.error("No destination specified");
}
});
check this JsFiddle
HTML
<a id="top"></a>
<div class="scroll-to-anchor" data-dest="top">sdlkjfs</div>
JS
$('.scroll-to-anchor').each(function () {
var instance = $(this);
if (instance.data('dest')) {
var destination = instance.data('dest');
if ($('#' + destination).length) {
instance.click(function () {
alert('click');
// Scroll to destination
})
} else {
throw 'Not a valid scroll-to anchor'
}
} else {
throw 'No data attribute present'
}
});
Related
I have used the below for loop to click on the icon in 5th index of td, if the 2nd index of td contains text (which is passed as external parameter) as expected.
I'm getting the row elements as tenantRowElements and written the following code.
The outcome is reached i.e, the expected button is clicked but still am facing the below error and it is not moving into next method.
stale element reference: element is not attached to the page document
error.
this.clickEditOfTenant=function(userobj) {
console.log("Edit of tenant is clicked");
basePage.waitForElement(this.tenantRowElements, 5000);
this.tenantRowElements.then(function (tenants) {
console.log("element length : " + tenants.length);
for (var i = 0; i < tenants.length; i++) {
tenants[i].$$('td').then(function (tds) {
tds[1].getText().then(function (text) {
return text;
}).then(function (name) {
console.log("tenant name : " + name + "; given name :" + userobj.tname);
if (name === userobj.tname) {
tds[5].click();
}
});
});
}
}).then(function () {
if(basePage.isVisible(updateTenant.tenantNameTxtBox))
{console.log("Edit button is clicked");}
});
};
i have edited as below, and now its working
this.clickEditOfTenant = function(userobj) {
console.log("call clickEditOfTenant()");
basePage.waitForElement(this.tenantRowElements, 10000);
//browser.sleep(15000);
this.tenantRowElements.filter(function (tr) {
return tr.all(by.css('td')).get(1).getText().then(function (name) {
return name === userobj.tname;
});
}).then(function (eles) {
eles[0].$$('td').then(function (btn) {
//console.log(text);
btn[5].click();
}).then(function () {
browser.sleep(5000);
if (basePage.isVisible(updateTenant.tenantNameTxtBox)) {
console.log("Edit button is clicked");
}
});
});
};
I suspect basePage.waitForElement(this.tenantRowElements, 5000); is not sufficient to wait the page complete load. So you met the issue at the first iteration of loop,
Add browser.sleep(15000) after basePage.waitForElement(this.tenantRowElements, 5000); for debug purpose.
And you can use filter() to make your code briefness:
this.clickEditOfTenant = function(userobj) {
console.log("call clickEditOfTenant()");
// basePage.waitForElement(this.tenantRowElements, 5000);
browser.sleep(15000)
this.tenantRowElements.filter(function(tr) {
return tr.all(by.css('td')).get(1).getText().then(function(name) {
return name === userobj.tname;
});
})
.then(function(eles) {
if(eles.length > 0) {
eles[0].click();
}
})
.then(function () {
if(basePage.isVisible(updateTenant.tenantNameTxtBox)) {
console.log("Edit button is clicked");
}
});
};
I'm trying to check if an element is display block, and if it is then i want to execute some code. Below is my code, its a large function but where I'm trying to check if a div is display block is at the bottom, and if it is display block then i want to execute the blur method.
As you can see near the bottom, I started writing if ($suggestionsWrapper === and my intention was to write if suggestions wrapper is display none, then do this. I just can't figure out how to execute this, what I've written doesn't work. Also I am new to all of this so sorry if this is really messy or doesn't make sense, still very much learning.
//Header Search Handler
function headerSearchHandler(){
var $searchInput = $(".header-search input[type=text]"),
$searchSubmit = $(".header-search input[type=submit]"),
$mobSearchBtn = $(".mobile-search-btn"),
$myAccountText = $(".menu-utility-user .account-text"),
$miniCart = $("#header #mini-cart"),
$searchForm = $(".header-search form"),
$headerPromo = $(".header-promo-area");
$suggestionsWrapper = $('#suggestions-wrapper');
//
$mobSearchBtn.on("click touchend", function(e) {
$(this).hide();
//$myAccountText.hide();
$searchInput.show();
$searchInput.addClass('grey-line');
$searchSubmit.show();
$miniCart.addClass("search-open");
$searchForm.addClass("search-open");
setTimeout(function() {
$searchInput.addClass("active").focus();
}, 100);
e.stopPropogation();
});
$searchInput.on("click touchend", function(e) {
$searchInput.addClass('grey-line');
e.stopPropogation();
}).blur(function(e) {
var $this = $(this);
if($this.hasClass("active")){
$this.removeClass("active");
$searchSubmit.hide();
$mobSearchBtn.show();
$miniCart.removeClass("search-open");
$searchForm.removeClass("search-open");
}
});
$searchInput.focus(function(e){
$(this).css('width', '145px');
})
if ($suggestionsWrapper.css('display') == 'none') {
$searchInput.blur(function(e){
$(this).removeClass('grey-line');
$(this).css('width', '145px');
}
})
}//End Header Search Handler
You can create a helper method to check if display is block or not :
function checkDisplay(element) {
return $(element).css('display') == 'block';
}
Then you can check it like :
if(checkDisplay("#myElement")){
console.log("Display is Block")
}
else {
console.log("Display is NOT Block")
}
here is an example : https://jsfiddle.net/fafgqv7v/
You can do something like this I think:
if ($suggestionsWrapper.css('display') == 'block')
{
// true
} else {
// false
}
Based off of your code I think you have the }) wrong, it should be:
if ($suggestionsWrapper.css('display') == 'none') {
$searchInput.blur(function(e){
$(this).removeClass('grey-line');
$(this).css('width', '145px');
})
}
I hope this helps!
I am currently working with PhantomJS and CasperJS to scrape for links in a website. The site uses javascript to dynamically load results. The below snippet however is not getting me all the results the page contains. What I need is to scroll down to the bottom of the page, see if the spinner shows up (meaning there’s more content still to come), wait until the new content had loaded and then keep scrolling until no more new content was shown. Then store the links with class name .title in an array. Link to the webpage for scraping.
var casper = require('casper').create();
var urls = [];
function tryAndScroll(casper) {
casper.waitFor(function() {
this.page.scrollPosition = { top: this.page.scrollPosition["top"] + 4000, left: 0 };
return true;
}, function() {
var info = this.getElementInfo('.badge-post-grid-load-more');
if (info["visible"] == true) {
this.waitWhileVisible('.badge-post-grid-load-more', function () {
this.emit('results.loaded');
}, function () {
this.echo('next results not loaded');
}, 5000);
}
}, function() {
this.echo("Scrolling failed. Sorry.").exit();
}, 500);
}
casper.on('results.loaded', function () {
tryAndScroll(this);
});
casper.start('http://example.com/', function() {
this.waitUntilVisible('.title', function() {
tryAndScroll(this);
});
});
casper.then(function() {
casper.each(this.getElementsInfo('.title'), function(casper, element, j) {
var url = element["attributes"]["href"];
urls.push(url);
});
});
casper.run(function() {
this.echo(urls.length + ' links found:');
this.echo(urls.join('\n')).exit();
});
I've looked at the page. Your misconception is probably that you think the .badge-post-grid-load-more element vanishes as soon as the next elements are loaded. This is not the case. It doesn't change at all. You have to find another way to test whether new elements were put into the DOM.
You could for example retrieve the current number of elements and use waitFor to detect when the number changes.
function getNumberOfItems(casper) {
return casper.getElementsInfo(".listview .badge-grid-item").length;
}
function tryAndScroll(casper) {
casper.page.scrollPosition = { top: casper.page.scrollPosition["top"] + 4000, left: 0 };
var info = casper.getElementInfo('.badge-post-grid-load-more');
if (info.visible) {
var curItems = getNumberOfItems(casper);
casper.waitFor(function check(){
return curItems != getNumberOfItems(casper);
}, function then(){
tryAndScroll(this);
}, function onTimeout(){
this.echo("Timout reached");
}, 20000);
} else {
casper.echo("no more items");
}
}
I've also streamlined tryAndScroll a little. There were completely unnecessary functions: the first casper.waitFor wasn't waiting at all and because of that the onTimeout callback could never be invoked.
I have 5 link and mini preview photo and url 3 links its good link opsss and upsss is wrong when i click good link i'm going to new page when i click error link attr href change to adresError and then we have popup This only works for the first time second time click all links have a popup and should have only opsss and upsss
http://jsfiddle.net/3ptktp47/1/
Here is my code :
var nameError = [
"opsss",
"upsss",
];
$(function() {
$('#prev').hide();
$(function() {
var title_link = 'kliknij aby podejżeć';
$(".preview-link a")
.attr({title: title_link})
//.tooltip()
.click(function(){
$('.preview-link a img').css('opacity',1);
var sciezka = $(this).attr("href");
var tytul = $(this).attr("title");
var adres = $(this).text();
//alert(adres);
$(".duzy").attr({ src: sciezka, alt: tytul, style:'cursor:pointer;', href:'http://www.'+ adres,'target':'_blank'});
$('.link').html(adres).attr({href:'http://www.'+ adres,'target':'_blank'});
$('#prev').show();
function errorDomain() {
$('.link, .duzy').removeAttr('href');
$('.link, .duzy').click(function(event){
$('#popup, .popup-bg').show('slow');
$('.server_url').html(adresError).attr({href:'http://'+ adresError,'target':'_blank'});
});
};
if(adres == 'opsss.com'){
var adresError = 'x4ql.nazwa.pl/'+ nameError[0];
errorDomain();
}else if(adres == 'upsss.com' ){
var adresError = 'x4ql.nazwa.pl/'+ nameError[1];
errorDomain();
}else{
//$('#popup, .popup-bg').fadeOut();
};
$('.cancel, .popup-bg').click(function(event){
$('#popup, .popup-bg').fadeOut();
});
return false;
});
$('.close').click(function(){
$('#prev').hide();
});
$('.link').mouseover(function(){
$(this).css({style: 'color:#000;'});
});
});
});
EDITED:
Ok, I was able to handle your problem.
Your .click() event in the errorDomain() method was firing every time you clicked this square. I managed it to toggle a class on a.duzy element with toggleClass('error') in your if-statement where you check the address.
Inside your click() event, a if-statement is checking if the .duzy element has class named error with hasClass('error') , this has following result -
TRUE- your popup will be displayed
FALSE - nothing happens
I hope my answer is clear enough, but please check out the edited fiddle.
EDITED SOURCE:
Your errorDomain() Method
function errorDomain() {
$('.link, .duzy').removeAttr('href');
$('.duzy, .link').click(function (event) {
if ($(this).hasClass("error")) {
$('#popup, .popup-bg').show('slow');
$('.server_url').html(adresError).attr({
href: 'http://' + adresError,
'target': '_blank'
});
}
});
}
The if-statements
if (adres == 'opsss.com') {
var adresError = 'x4ql.nazwa.pl/' + nameError[0];
$('a.duzy').toggleClass("error");
errorDomain();
} else if (adres == 'upsss.com') {
var adresError = 'x4ql.nazwa.pl/' + nameError[1];
$('a.duzy').toggleClass("error");
errorDomain();
} else {
$('a.duzy').removeClass("error");
}
Edited fiddle
I need to write some code which is supposed to wait until a predefined div is no longer visible in order to process the next line. I plan on using jQuery( ":visible" ) for this, and was thinking I could have some type of while loop. Does anyone have a good suggestion on how to accomplish this task?
$( document ).ready(function() {
$(".scroller-right" ).mouseup(function( event ) {
alert('right');
pollVisibility();
});
});
function pollVisibility() {
if ($(".mstrWaitBox").attr("visibility")!== 'undefined') || $(".mstrWaitBox").attr("visibility") !== false) {
alert('inside else');
microstrategy.getViewerBone().commands.exec('refresh');
} else {
setTimeout(pollVisibility, 100);
}
}
$( document ).ready(function() {
$(".scroller-right" ).mouseup(function( event ) {
alert('right');
pollVisibility();
});
});
function pollVisibility() {
if (!$(".mstrWaitBox").is(":visible")) {
alert('inside if');
microstrategy.getViewerBone().commands.exec('refresh');
} else {
setTimeout(pollVisibility, 100);
}
}
div when not visible:
<div class="mstrWaitBox" id="divWaitBox" scriptclass="mstrDialogImpl" dg="1" ty="edt">
</div>
div when visible:
<div class="mstrWaitBox" id="divWaitBox" scriptclass="mstrDialogImpl" dg="1" ty="edt" visibility="visible">
</div>
You can use the setTimeout function to poll the display status of the div. This implementation checks to see if the div is invisible every 1/2 second, once the div is no longer visible, execute some code. In my example we show another div, but you could easily call a function or do whatever.
http://jsfiddle.net/vHmq6/1/
Script
$(function() {
setTimeout(function() {
$("#hideThis").hide();
}, 3000);
pollVisibility();
function pollVisibility() {
if (!$("#hideThis").is(":visible")) {
// call a function here, or do whatever now that the div is not visible
$("#thenShowThis").show();
} else {
setTimeout(pollVisibility, 500);
}
}
}
Html
<div id='hideThis' style="display:block">
The other thing happens when this is no longer visible in about 3s</div>
<div id='thenShowThis' style="display:none">Hi There</div>
If your code is running in a modern browser you could always use the MutationObserver object and fallback on polling with setInterval or setTimeout when it's not supported.
There seems to be a polyfill as well, however I have never tried it and it's the first time I have a look at the project.
FIDDLE
var div = document.getElementById('test'),
divDisplay = div.style.display,
observer = new MutationObserver(function () {
var currentDisplay = div.style.display;
if (divDisplay !== currentDisplay) {
console.log('new display is ' + (divDisplay = currentDisplay));
}
});
//observe changes
observer.observe(div, { attributes: true });
div.style.display = 'none';
setTimeout(function () {
div.style.display = 'block';
}, 500);
However an even better alternative in my opinion would be to add an interceptor to third-party function that's hiding the div, if possible.
E.g
var hideImportantElement = function () {
//hide logic
};
//intercept
hideImportantElement = (function (fn) {
return function () {
fn.apply(this, arguments);
console.log('element was hidden');
};
})(hideImportantElement);
I used this approach to wait for an element to disappear so I can execute the other functions after that.
Let's say doTheRestOfTheStuff(parameters) function should only be called after the element with ID the_Element_ID disappears, we can use,
var existCondition = setInterval(function() {
if ($('#the_Element_ID').length <= 0) {
console.log("Exists!");
clearInterval(existCondition);
doTheRestOfTheStuff(parameters);
}
}, 100); // check every 100ms