If I had multiple objects of a class present, but only some are visible, what would be the best way to find the first visible one. I currently try:
browser.waitForElementVisible('.myClass', timeOut)
which sees all of the elements, but will only act on the first found. OR
browser.waitForElementVisible('(//div[#class="myClass"])[1]')
which specifies an index, but that may or may not be visible, since new data is loaded every time the page refreshes.
I need to loop through all present and just click on the first instance of one that is visible. I know I can achieve this through custom commands, but I'm new to js and nightwatch, so I'm not sure how to go about it.
I think I would probably use .elementIdDisplayed() to accomplish this.
The snippet below should help you
get a list of the elements
check if one is displayed
If displayed, click on the element
Usually I would use a forEach loop but since you can't break out of that without doing some hacky stuff just use a regular old for loop like this:
browser.elements('css selector', '.myClass', function(elements) {
for(let i = 0; i < elements.value.length; i++) {
browser.elementIdDisplayed(elements.value[i].ELEMENT, function(isDisplayed) {
if(isDisplayed.value) {
browser.elementIdClick(element.value[i].ELEMENT);
break; //this will break out of the loop when you find the first displayed element
}
});
}
});
Related
I have multiple elements on a page with the same class name, but each element has a unique id name.
Example:
<div class="video-image" id="get-googled">
<div class="video-image" id="email-marketing">
I want to display the id value, but right now I am only able to have GTM return and display the first element on the page. I read this post: "Getting value of ID from class" and it didn't help and even explains doing it the simple way will only display the first elements value.
Do I need custom Javascript to create this properly?
If you want to get a specific div and you know where it is on the page you might be able to use a DOM variable with an nth of type query selector. But this seems cumbersome, and since it seems you want a list in any case I think you are better of with a custom javascript variable:
function() {
return document.querySelectorAll(".video-image");
}
which return a collection of DOM elements (you might want to check if there are actually elements with that class first).
The initial answer is the right start - this completes the loop:
<script>
var inputs = document.querySelectorAll(".video-image");
for (var i = 0; i < inputs.length; i++) {
alert(inputs[i].id);
}
</script>
Here is a JSFiddle to try it out - [https://jsfiddle.net/JMurphy22/kduybmsp/2/][1]
Consider the following code:
jQuery(function($)
{
$(document).ready(function()
{
$(".td-block-row").each(function()
{
var item = $(this);
$(".td-block-span4:nth-child(3)").prependTo(item.next());
});
});
});
I am trying to iterate through each .td-block-row div, and pick out the third .td-block-span4 element from it, and then move it to the next .td-block-row
The code I currently have (above) will move every Nth .td-block-span4 rather than just the one within the current div in the each loop. Essentially I am trying to do something like:
$(item ".td-block-span4:nth-child(3)").prependTo(item.next());
This may just be a case of finding out the correct syntax to make use of the item var, or perhaps I am taking a completely the wrong approach.
Any advise here would be appreciated as I have little experience with JS
The problem is you need to query td-block-span4:nth-child(3) relative to the current element(in the each handler). So
$(".td-block-span4:nth-child(3)", this).prependTo(item.next());
//or
$item.find(".td-block-span4:nth-child(3)").prependTo(item.next());
I have a page generated by Yii CListView which contains a div andmultiple child divs.I need to access a specific the child div and add one more div into that.
Although I managed to solve it using one approach but dont think its the right one. Following is the overview of my solution (the code below does not contain all necessary variables declarations and other stuff, I have pasted the core code not the complete.):
Accessed the parent div by Id (Since the Id was available as I can
code this into Yii)
Obtained all the elements in this div using :
var div_childern = document.getElementById('StudentGridViewId').getElementsByTagName('*');
Iterated through and when reached to the desired div, added my new div. Please note that the div in which I want to add new div has the class name as "items". Code as below:
for (var i = 0; i < div_childern.length; i++) {
if (div_childern[i].getAttribute('class')=='items'){
document.getElementById('StudentGridViewId').getElementsByTagName('*')[i].appendChild(newdiv);
i=div_childern.length+1;
}
}
The only problem in this solution is, I am accessing the whole document twice, the call to getElementsByTagName. First to obtain the list of all items and then again to add my new div. Is there a better way to this ?
and also, could anyone point me to set the Id of the "items" div that Yii generates?
Thanks
Faisal
You might be able to get a much more elegant solution if you use JQuery.
But, if you want to use the traditional javascript, here is what you could do
for (var i = 0; i < div_childern.length; i++) {
if (div_childern[i].getAttribute('class')=='items'){
div_childern[i].appendChild(newdiv);
i=div_childern.length+1;
}
}
http://jsfiddle.net/NzbRQ/2/
I allow the user to add multiple rows of fields, but I do not want to include a delete link on the very first row of fields, so they can't delete all the fields.
Also, how do I limit it to only 3 rows of fields?
Try this fiddle: Fiddle
For the first part of hiding the delete on the first row, I called the following on page load:
$(".removeoutcome").hide();
Then to make sure they can't add more than 3 or delete the last one, I've added length checks in your click methods, see:
$('.addoutcome').live('click', function() {
if ($(".outcomegroup").length < 3) {
$('#template').clone().removeAttr('id').insertAfter($(this).closest('.outcomegroup')).find('.minus').show();
renumber();
}
});
$('.removeoutcome').live('click', function() {
if ($(".outcomegroup").length > 1) {
$(this).closest('.outcomegroup').remove();
renumber()
}
});
Also, on a side note, live is deprecated now, so if you're using jQuery 1.7, change these methods to on or if you're pre-1.7, use delegate.
You can just hide the del for first element and limit it to add only 3 more set using the following code
var count = 3;
$('.minus').first().hide();
$('.addoutcome').live('click', function() {
count--;
if(count < 0 )return;
$('#template').clone().removeAttr('id').insertAfter($(this).closest('.outcomegroup')).find('.minus').show();
});
here is the working fiddle http://jsfiddle.net/joycse06/uW9NQ/
Updated: http://jsfiddle.net/NzbRQ/5/
First off, ditch .live. I added the section to give a more specific selector than body, but there's probably something better that you can use in your original DOM.
Just don't remove the last row with some simple logic. Your logic for showing the future "del" link was actually already there! You don't even really need the last-row-removal logic at all since just not displaying "del" is enough, but I was just being thorough.
I don't know why anyone haven't paid close attention to this line:
.find('.minus').show();
where he definitely was un-hiding the del element. In short, the only thing you need to do is add the proper CSS rule:
.minus { display: none; }
and that's it, the first element won't show a del link and the others will.
The limit to three elements simply.
$("[parent element]").on('click', '.addoutcome', function() {
if($('.addoutcome').length > 2) return;
...
});
A better selector [parent selector] is needed and depends totally in your layout. Basically, it is the element that wraps all these elements, the parent element of all of them.
I want to hide all the elements on the page that end in _dropMenu via javascript...so this is what i have
window.onload = function() {
hideNav();
};
function hideNav(){
myArray = element("_dropMenu");// this is what need changing
for (i=0;i<=5;i++)
{
i.style.visibility = 'hidden';
}
}
This is obviously wrong but how do I first get all the elements on the page that end with _dropMenu then loop through them and set them to hidden... I would prefer javascript since I only have prototype on the page but if I need to add jquery I will...
jQuery has a selector for finding elements that have an attribute that ends with a given string:
$('[id$="_dropMenu]')
This will be faster if you can narrow it by an element type (e.g. if all the elements you care about are divs, or some such) but will work as is.
Behind the scenes, jquery is just looping through a given set of elements, and checking whether element["id"].substring(element["id"].length-"_dropMenu".length)==="_dropMenu".
Just pointing out the Prototype is very similar to jQuery in this case:
$$('[id$="_dropMenu"]').invoke('hide');
Kudos Jishnu & JacobM for getting the selector first.