js.executeScript doesn't work when using getElementsByClassName in selenium - javascript

I have a method:
public void delayToCapture(String methodGetBy, String key){
/* List of methodGetBy:
* 1. getElementById
* 2. getElementsByTagName
* 3. getElementsByClassName
* 4. querySelectorAll
*/
System.out.println("Excuteing javaScript...");
if(methodGetBy.equals("getElementById")){
js.executeScript("setTimeout(function(){ document." +methodGetBy+ "('" +key+ "').setAttribute('style', 'display: none');},500);");
}
else if(methodGetBy.equals("getElementsByClassName")){
js.executeScript("setTimeout(function(){"
+ "var elems = document.getElementsByClassName('"+ key +"');"
+ "for(var i = 0; i < elems.length; i++){"
+ "elems[i].style.display = 'none';}"
+ "},"
+ "500);");
}
}
And I call that method in another class:
delayToCapture("getElementsByClassName", "positionmenu");
When running the code, console always show me this message:
java.lang.NullPointerException
However, if I run this code at below on console of Brower directly -> It's work:
setTimeout(function(){
var elems = document.getElementsByClassName('positionmenu');
for(var i = 0; i < elems.length; i++){
elems[i].style.display = 'none';
}
},500);
So, could you tell me what is the reason here?

Try using this :
else if(methodGetBy.equals("getElementsByClassName")){
List<WebElement> element = driver.findElements(By.className(key)); // getting element using class name
js.executeScript("setTimeout(function(){"
+ "var elems = arguments[0];"
+ "for(var i = 0; i < elems.length; i++){"
+ "elems[i].style.display = 'none';}"
+ "},"
+ "500);", element);
}
Hope that helps you.

Related

How to get attribute ID to parameter of function js

I need put 5 images on page like thumbnail, and after click show the lightbox. I need put ID of element what I create to function like parameter. But i cant get ID. I was looking for this problem here and with google but nothings work :( It is project to school and I can use only html, css and javascript, I can not use jquery. Thanks. Here is my code:
function onloadpg() {
for (var i = 0; i<5; i++) {
x[i] = document.createElement("IMG");
x[i].setAttribute("src", "images/" + (i+1) + ".jpg");
x[i].setAttribute("width", "250");
x[i].setAttribute("height", "200");
x[i].setAttribute("alt", fotky.title);
x[i].setAttribute("title", fotky.title);
x[i].setAttribute("id", i+1);
x.setAttribute("onclick", zobraz(x.getAttribute('id')), nacitaj(x.getAttribute('id')));
}
Problem :
You could see in the browser console the message :
Uncaught TypeError: x.setAttribute is not a function
Solution :
You need to use x[i] instead of x to target the current element by index in :
x.setAttribute("onclick", zobraz(x.getAttribute('id')), nacitaj(x.getAttribute('id')));
^________________________________^______________________________^
Should be :
x[i].setAttribute("onclick", "zobraz("+x[i].getAttribute('id')+")", "nacitaj("+x[i].getAttribute('id')+")");
^^^^_________________________^_______^^^^^^___________________^^^^___________^^^^^^___________________^^^^^
Note also that you've to add quotes " and concate variables.
NOTE : You should define the variable x as array :
var x = [];
Hope this helps.
function onloadpg() {
var x = [];
for (var i = 0; i < 5; i++) {
x[i] = document.createElement("IMG");
x[i].setAttribute("src", "images/" + (i + 1) + ".jpg");
x[i].setAttribute("width", "250");
x[i].setAttribute("height", "200");
x[i].setAttribute("alt", "fotky.title");
x[i].setAttribute("title", "fotky.title");
x[i].setAttribute("id", i + 1);
x[i].setAttribute("onclick", "zobraz("+x[i].getAttribute('id')+")", "nacitaj("+x[i].getAttribute('id')+")");
document.body.innerHTML += x[i].outerHTML+"<br>";
}
}
function zobraz(id) {
alert('zobraz : '+id);
}
function nacitaj(id) {
alert("nacitaj : "+id);
}
onloadpg();
function onloadpg(element_id) {
var elem = document.getElementById(element_id);
for (var i = 0; i<5; i++) {
x[i] = document.createElement("IMG");
x[i].setAttribute("src", "images/" + (i+1) + ".jpg");
x[i].setAttribute("width", "250");
x[i].setAttribute("height", "200");
x[i].setAttribute("alt", fotky.title);
x[i].setAttribute("title", fotky.title);
x[i].setAttribute("id", i+1);
x.setAttribute("onclick", zobraz(x.getAttribute('id')),nacitaj(x.getAttribute('id')));
}
onloadpg("element_id");

Get CSS class definition from chrome developer tools console

I would like to programatically retrieve a set of CSS class definitions from chrome developer tools. In effect similar to what is displayed in styles tab in the right hand side. The input needs to be a class name and the output should be all the styles defined in it.
I'm aware of getComputedStyle DOM method, but this doesn't separate into separate classes which I need.
This approach worked for me (stackoverflow.com/a/27527462/1023562):
/**
* Gets styles by a classname
*
* #notice The className must be 1:1 the same as in the CSS
* #param string className_
*/
function getStyle(className_) {
var styleSheets = window.document.styleSheets;
var styleSheetsLength = styleSheets.length;
for(var i = 0; i < styleSheetsLength; i++){
var classes = styleSheets[i].rules || styleSheets[i].cssRules;
var classesLength = classes.length;
for (var x = 0; x < classesLength; x++) {
if (classes[x].selectorText == className_) {
var ret;
if(classes[x].cssText){
ret = classes[x].cssText;
} else {
ret = classes[x].style.cssText;
}
if(ret.indexOf(classes[x].selectorText) == -1){
ret = classes[x].selectorText + "{" + ret + "}";
}
return ret;
}
}
}
}
It lets you invoke the javascript code in Chrome console like this:
console.log(getStyle('#heder_logo a'));
and get results like this:
> #heder_logo a { width: 200px; height: 114px; display: block; }.
I did have issues with some CSS files which were not on the same domain (they were pulled from CDN), but there are variety of proposals in that thread, so some should work for you.
Have adapted Ivan's answer in order to get a more complete result. This method will also return styles where the class is part for the selector
//Get all styles where the provided class is involved
//Input parameters should be css selector such as .myClass or #m
//returned as an array of tuples {selectorText:"", styleDefinition:""}
function getStyleWithCSSSelector(cssSelector) {
var styleSheets = window.document.styleSheets;
var styleSheetsLength = styleSheets.length;
var arStylesWithCSSSelector = [];
//in order to not find class which has the current name as prefix
var arValidCharsAfterCssSelector = [" ", ".", ",", "#",">","+",":","["];
//loop through all the stylessheets in the bor
for(var i = 0; i < styleSheetsLength; i++){
var classes = styleSheets[i].rules || styleSheets[i].cssRules;
var classesLength = classes.length;
for (var x = 0; x < classesLength; x++) {
//check for any reference to the class in the selector string
if(typeof classes[x].selectorText != "undefined"){
var matchClass = false;
if(classes[x].selectorText === cssSelector){//exact match
matchClass=true;
}else {//check for it as part of the selector string
//TODO: Optimize with regexp
for (var j=0;j<arValidCharsAfterCssSelector.length; j++){
var cssSelectorWithNextChar = cssSelector+ arValidCharsAfterCssSelector[j];
if(classes[x].selectorText.indexOf(cssSelectorWithNextChar)!=-1){
matchClass=true;
//break out of for-loop
break;
}
}
}
if(matchClass === true){
//console.log("Found "+ cssSelectorWithNextChar + " in css class definition " + classes[x].selectorText);
var styleDefinition;
if(classes[x].cssText){
styleDefinition = classes[x].cssText;
} else {
styleDefinition = classes[x].style.cssText;
}
if(styleDefinition.indexOf(classes[x].selectorText) == -1){
styleDefinition = classes[x].selectorText + "{" + styleDefinition + "}";
}
arStylesWithCSSSelector.push({"selectorText":classes[x].selectorText, "styleDefinition":styleDefinition});
}
}
}
}
if(arStylesWithCSSSelector.length==0) {
return null;
}else {
return arStylesWithCSSSelector;
}
}
In addition, I've made a function which collects the css style definitions to the sub-tree of a root node your provide (through a jquery selector).
function getAllCSSClassDefinitionsForSubtree(selectorOfRootElement){
//stack in which elements are pushed and poped from
var arStackElements = [];
//dictionary for checking already added css class definitions
var existingClassDefinitions = {}
//use jquery for selecting root element
var rootElement = $(selectorOfRootElement)[0];
//string with the complete CSS output
var cssString = "";
console.log("Fetching all classes used in sub tree of " +selectorOfRootElement);
arStackElements.push(rootElement);
var currentElement;
while(currentElement = arStackElements.pop()){
currentElement = $(currentElement);
console.log("Processing element " + currentElement.attr("id"));
//Look at class attribute of element
var classesString = currentElement.attr("class");
if(typeof classesString != 'undefined'){
var arClasses = classesString.split(" ");
//for each class in the current element
for(var i=0; i< arClasses.length; i++){
//fetch the CSS Styles for a single class. Need to append the . char to indicate its a class
var arStylesWithCSSSelector = getStyleWithCSSSelector("."+arClasses[i]);
console.log("Processing class "+ arClasses[i]);
if(arStylesWithCSSSelector != null){
//console.log("Found "+ arStylesWithCSSSelector.length + " CSS style definitions for class " +arClasses[i]);
//append all found styles to the cssString
for(var j=0; j< arStylesWithCSSSelector.length; j++){
var tupleStyleWithCSSSelector = arStylesWithCSSSelector[j];
//check if it has already been added
if(typeof existingClassDefinitions[tupleStyleWithCSSSelector.selectorText] === "undefined"){
//console.log("Adding " + tupleStyleWithCSSSelector.styleDefinition);
cssString+= tupleStyleWithCSSSelector.styleDefinition;
existingClassDefinitions[tupleStyleWithCSSSelector.selectorText] = true;
}else {
//console.log("Already added " + tupleStyleWithCSSSelector.styleDefinition);
}
}
}
}
}
//push all child elments to stack
if(currentElement.children().length>0){
arStackElements= arStackElements.concat(currentElement.children().toArray());
}
}
console.log("Found " + Object.keys(existingClassDefinitions).length + " CSS class definitions");
return cssString;
}
Note that if a class is defined several times with the same selector, the above function will only pick up the first.
Python script to search css file for a word once found read what is inbetween the curly braces. Quick and dirty way**

getElementsByClassName not letting me change fontsize

I am trying to make a JavaScript script that will change the "Resizable" Class elements on my page, however I don't think that I am using the getElementsByClassName correctly.
Here is my code:
function resizeText(multiplier) {
var elements = document.getElementsByClassName('Resizable');
for(var i=0; i<elements.length; i++) {
elements[i].style.fontSize = parseFloat(elements[i].style.fontSize) + (multiplier+ * 0.2)
}
}
I have a button using onclick="resizeText(1)" and another with (-1), neither are working and I am unsure why. Am I correct in using getElementsByClassName to make an Array and then try and change the style of each object?
May be you're missing "px" at the end:
function resizeText(multiplier) {
var elements = document.getElementsByClassName('Resizable');
for(var i = 0; i < elements.length; i++) {
elements[i].style.fontSize = parseFloat(elements[i].style.fontSize) + (multiplier + * 0.2) + "px";
}
}
have you tried
elements[i].style.fontSize = (parseFloat(elements[i].style.fontSize) + (multiplier+ * 0.2)) + "px";
or the element's font-size has initial value?
function resizeText(multiplier) {
var elements = document.getElementsByClassName('Resizable');
for(var i=0; i<elements.length; i++) {
elements[i].style.fontSize = parseFloat(elements[i].style.fontSize) + (multiplier * 0.2) + 'px';
}
}

id for each element showing undefined or 0 not being assigning different id's

I'm trying to assign a id to each link in my list like this,
for (var j = start; j < stop; j++) {
link = linkBase + json[j].relatedItemId;
$('#citations').append('<li><a href="' + link + '" id="num" + j>' +
json[j].title + '</a></li>');
alert($('a').attr('id'));
}
it keeps giving me undefined or 0? Should I use $.each outside of the for loop instead?
I was trying to use the for loop for two purposes but maybe that's not such a great idea?
*EDIT***
If I put my for loop inside of a function like,
// Loop function for each section
var loopSection = function(start, stop) {
// Http setup for all links
var linkBase = "http://www.sciencebase.gov/catalog/item/";
// Link for citation information
var link = "";
for (var j = start; j < stop; j++) {
link = linkBase + json[j].relatedItemId;
var $anchor = $("<a>", {
href: link,
id: "id" + j,
text: json[j].title
})
// .parent() will get the <li> that was just created and append to the first citation
element
$anchor.appendTo("<li>").parent().appendTo("#citations");
}
}
I'm not able to access the id from outside of the function
$('#citations').on('click', function (e) {
e.preventDefault();
var print = ($(this).attr('id'));
alert(print);
});
This form is much cleaner:
for (var j = start; j < stop; j++) {
link = linkBase + json[j].relatedItemId;
$("<a>", {
href: link,
id:'num' + j,
text: json[j].title
}).appendTo("<li>")
.parent() // get the <li> we just made
.appendTo("#citations");
}
If you want a reference to the anchor tag you created, do this:
for (var j = start; j < stop; j++) {
link = linkBase + json[j].relatedItemId;
var $anchor = $("<a>", {
href: link,
id:'num' + j,
text: json[j].title
});
$anchor.appendTo("<li>").parent().appendTo("#citations");
}
You have a syntax error in your code (id="num" + j..)
However,You should do this by the code (avoiding syntax error and giving a better performance)
for (var j = start; j < stop; j++)
{
var link = linkBase + json[j].relatedItemId;
$('#citations').append($(document.createElement('li'))
.append($(document.createElement('a'))
.attr('href', link)
.attr('id', 'num' + j)
.html(json[j].title)));
}
Agree with the answer from Schmiddty but, for the sake of completeness
for (var j = 0; j < 10; j++) {
var link = "someLink.htm";
$('#citations').append('<li>'+ 'click here' + '</li>');
alert($('#citations a:last').attr('id'));
}
I've only changed your variable to make it work on its own on this fiddle as a demo

getElementsByClassName IE resolution issue

I am having issues figuring out how to resolve the getElementsByClassName issue in IE. How would I best implement the robert nyman (can't post the link to it since my rep is only 1) resolution into my code? Or would a jquery resolution be better? my code is
function showDesc(name) {
var e = document.getElementById(name);
//Get a list of elements that have a class name of service selected
var list = document.getElementsByClassName("description show");
//Loop through those items
for (var i = 0; i < list.length; ++i) {
//Reset all class names to description
list[i].className = "description";
}
if (e.className == "description"){
//Set the css class for the clicked element
e.className += " show";
}
else{
if (e.className == "description show"){
return;
}
}}
and I am using it on this page dev.msmnet.com/services/practice-management to show/hide the description for each service (works in Chrome and FF). Any tips would be greatly appreciated.
I was curious to see what a jQuery version of your function would look like, so I came up with this:
function showDesc(name) {
var e = $("#" + name);
$(".description.show").removeClass("show");
if(e.attr("class") == "description") {
e.addClass("show");
} else if(e.hasClass("description") && e.hasClass("show")) {
return;
}
}
This should support multiple classes.
function getElementsByClassName(findClass, parent) {
parent = parent || document;
var elements = parent.getElementsByTagName('*');
var matching = [];
for(var i = 0, elementsLength = elements.length; i < elementsLength; i++){
if ((' ' + elements[i].className + ' ').indexOf(findClass) > -1) {
matching.push(elements[i]);
}
}
return matching;
}
You can pass in a parent too, to make its searching the DOM a bit faster.
If you want getElementsByClassName('a c') to match HTML <div class="a b c" /> then try changing it like so...
var elementClasses = elements[i].className.split(/\s+/),
matchClasses = findClass.split(/\s+/), // Do this out of the loop :)
found = 0;
for (var j = 0, elementClassesLength = elementClasses.length; j < elementClassesLength; j++) {
if (matchClasses.indexOf(elementClasses[j]) > -1) {
found++;
}
}
if (found == matchClasses.length) {
// Push onto matching array
}
If you want this function to only be available if it doesn't already exist, wrap its definition with
if (typeof document.getElementsByClassName != 'function') { }
Even easier jQuery solution:
$('.service').click( function() {
var id = "#" + $(this).attr('id') + 'rt';
$('.description').not(id).hide();
$( id ).show();
}
Why bother with a show class if you are using jQuery?
Heres one I put together, reliable and possibly the fastest. Should work in any situation.
function $class(className) {
var children = document.getElementsByTagName('*') || document.all;
var i = children.length, e = [];
while (i--) {
var classNames = children[i].className.split(' ');
var j = classNames.length;
while (j--) {
if (classNames[j] == className) {
e.push(children[i]);
break;
}
}
}
return e;
}
I used to implement HTMLElement.getElementByClassName(), but at least Firefox and Chrome, only find the half of the elements when those elements are a lot, instead I use something like (actually it is a larger function):
getElmByClass(clm, parent){
// clm: Array of classes
if(typeof clm == "string"){ clm = [clm] }
var i, m = [], bcl, re, rm;
if (document.evaluate) { // Non MSIE browsers
v = "";
for(i=0; i < clm.length; i++){
v += "[contains(concat(' ', #"+clc+", ' '), ' " + base[i] + " ')]";
}
c = document.evaluate("./"+"/"+"*" + v, parent, null, 5, null);
while ((node = c.iterateNext())) {
m.push(node);
}
}else{ // MSIE which doesn't understand XPATH
v = elm.getElementsByTagName('*');
bcl = "";
for(i=0; i < clm.length; i++){
bcl += (i)? "|":"";
bcl += "\\b"+clm[i]+"\\b";
}
re = new RegExp(bcl, "gi");
for(i = 0; i < v.length; i++){
if(v.className){
rm = v[i].className.match(bcl);
if(rm && rm.length){ // sometimes .match returns an empty array so you cannot use just 'if(rm)'
m.push(v[i])
}
}
}
}
return m;
}
I think there would be a faster way to iterate without XPATH, because RegExp are slow (perhaps a function with .indexOf, it shuld be tested), but it is working well
You can replace getElementsByClassName() with the following:
function getbyclass(n){
var elements = document.getElementsByTagName("*");
var result = [];
for(z=0;z<elements.length;z++){
if(elements[z].getAttribute("class") == n){
result.push(elements[z]);
}
}
return result;
}
Then you can use it like this:
getbyclass("description") // Instead of document.getElementsByClassName("description")

Categories