I am trying to access child element of an ng-repeat element but I am having troubles doing that.
I have searched around about the problem and the solutions that I have found did not work for me. One of those solutions was to do something like this:
var parent = element(by.repeater(''));
var child = parent.element(by.....);
When I try the child line I cant see the element function on the parent element..
http://prikachi.com/images/11/8338011u.png
If you see the screenshot above you will see the structure of the code of the page that I am trying to test.
I need to access the alt attribute of the image of the avatar and get its value (thats the Username of the User).
One thing that came to my mind is to use .getInnerHTML() on the ng-repeat row which will return a string with all that code. From there I can find the alt attribute and its value with string manipulation but this seems too brute and I am sure that there has to be a better way.
Simply I want to be able to get row 4 from the repeater and get the Username of the user at row 4, that's all I wanna do actually.
Try this,
var parent = element(by.repeater('f in feed'));
var child = parent.all(by.xpath('//img[#alt="Pundeep"]')).first()
(or)
var parent = element(by.repeater('f in feed'));
var child = parent.all(by.xpath('//img[#alt="Pundeep"]')).get(0)
You can get it directly using element.all() and get() locator in protractor. Here's how -
var child = element.all(by.repeater('parent_locator')).get(3); //gets 4th element in repeater. Its a 0 based index.
child.getAttribute('alt').then(function(user){
var username = user; //username contains the alt text
});
Hope this helps.
In Protractor element documentation it gives an example like this to find child elements, which is same as chaining element find:
// Chain 2 element calls.
let child = element(by.css('.parent')).
$('.child');
expect(child.getText()).toBe('Child text\n555-123-4567');
// Chain 3 element calls.
let triple = element(by.css('.parent')).
$('.child').
element(by.binding('person.phone'));
expect(triple.getText()).toBe('555-123-4567');
// Or using the shortcut $() notation instead of element(by.css()):
// Chain 2 element calls.
let child = $('.parent').$('.child');
expect(child.getText()).toBe('Child text\n555-123-4567');
// Chain 3 element calls.
let triple = $('.parent').$('.child').
element(by.binding('person.phone'));
expect(triple.getText()).toBe('555-123-4567');
https://www.protractortest.org/#/api?view=ElementFinder.prototype.$
this example could help :
return element(by.css('select.custom-select:nth-child(1) option[value="12"]'));
you can use nth-child() selector to access to a child element.
In my example i used a plugin with 2 select with same classes and i wanted to click on a defined option in the select 1, and a second in the select 2.
Related
I am looking for way to select element inside of already located element in variable. For example I have selected a container:
let productAttachedFilesModal = document.getElementById('modal_more_information');
I know, that inside are array of a elements, which I want to select as well. Which method should I use? in jQuery there are method find(). So I need the analog for JS.
Or I need to use DOM method again? Like this:
let listOfLinks= document.getElementById('modal_more_information > a');
You should use productAttachedFilesModal.children to get its children, which is the elements inside. It will get you an array of HTML elements.
There are several ways:
let anchors = productAttachedFilesModal.getElementsByTagName("a");
let anchors = document.querySelectorAll("#modal_more_information > a")
let anchors = productAttachedFilesModal.querySelectorAll("a");
You can just query that stored DOM reference:
let productAttachedFilesModal = document.getElementById('modal_more_information');
// Query the stored DOM element for all descendent anchors
let childAnchors = productAttachedFilesModal.querySelectorAll("a");
I am trying to scrape the following Javascript frontend website to practise my Javascript scraping skills:
https://www.oplaadpalen.nl/laadpaal/112618
I am trying to find two different elements by their xPath. The first one is the title, which it does find. The second one is the actual text itself, which it somehow fails to find. It's strange since I just copied the xPath's from Chrome browser.
from selenium import webdriver
link = 'https://www.oplaadpalen.nl/laadpaal/112618'
driver = webdriver.PhantomJS()
driver.get(link)
#It could find the right element
xpath_attribute_title = '//*[#id="main-sidebar-container"]/div/div[1]/div[2]/div/div[' + str(3) + ']/label'
next_page_elem_title = driver.find_element_by_xpath(xpath_attribute_title)
print(next_page_elem_title.text)
#It fails to find the right element
xpath_attribute_value = '//*[#id="main-sidebar-container"]/div/div[1]/div[2]/div/div[' + str(3) + ']/text()'
next_page_elem_value = driver.find_element_by_xpath(xpath_attribute_value)
print(next_page_elem_value.text)
I have tried a couple of things: change "text()" into "text", "(text)", but none of them seem to work.
I have two questions:
Why doesn't it find the correct element?
What can we do to make it find the correct element?
Selenium's find_element_by_xpath() method returns the first element node matching the given XPath query, if any. However, XPath's text() function returns a text node—not the element node that contains it.
To extract the text using Selenium's finder methods, you'll need to find the containing element, then extract the text from the returned object.
Keeping your own logic intact you can extract the labels and the associate value as follows :
for x in range(3, 8):
label = driver.find_element_by_xpath("//div[#class='labels']//following::div[%s]/label" %x).get_attribute("innerHTML")
value = driver.find_element_by_xpath("//div[#class='labels']//following::div[%s]" %x).get_attribute("innerHTML").split(">")[2]
print("Label is %s and value is %s" % (label, value))
Console Output :
Label is Paalcode: and value is NewMotion 04001157
Label is Adres: and value is Deventerstraat 130
Label is pc/plaats: and value is 7321cd Apeldoorn
I would suggest a slightly different approach. I would grab the entire text and then split one time on :. That will get you the title and the value. The code below will get Paalcode through openingstijden labels.
for x in range(2, 8):
s = driver.find_element_by_css_selector("div.leftblock > div.labels > div")[x].text
t = s.split(":", 1)
print(t[0]) # title
print(t[1]) # value
You don't want to split more than once because Status contains more semicolons.
Going with #JeffC's approach, if you want to first select all those elements using xpath instead of css selector, you may use this code:
xpath_title_value = "//div[#class='labels']//div[label[contains(text(),':')] and not(div) and not(contains(#class,'toolbox'))]"
title_and_value_elements = driver.find_elements_by_xpath(xpath_title_value)
Notice the plural elements in the find_elements_by_xpath method. The xpath above selects div elements that are descendants of a div element that had a class attribute of "labels". The nested label of each selected div must contain a colon. Furthermore, the div itself may not have a class of "toolbox" (Something that certain other divs on the page have), nor must it contain any additional nested divs.
Following which, you can extract the text within the individual div elements (which also contain the text from the nested label elements) and then split them using ":\n" which separates the title and value in the raw text string.
for element in title_and_value_elements:
element = element.text
title,value = element.split(":\n")
print(title)
print(value,"\n")
Since you want to practice JS skills you can do this also in JS, actually all the divs contain more data, you can see if you do paste this in the browser console:
labels = document.querySelectorAll(".labels");
divs = labels[0].querySelectorAll("div");
for (div of divs) console.log(div.firstChild, div.textContent);
you can push to an array and check only divs and that have label and return the resulted array in a python variable:
labels_value_pair.driver.execute_script('''
scrap = [];
labels = document.querySelectorAll(".labels");
divs = labels[0].querySelectorAll("div");
for (div of divs) if (div.firstChild.tagName==="LABEL") scrap.push(div.firstChild.textContent, div.textContent);
return scrap;
''')
I have some XML that looks like so:
<closure1>
<topClosure>
<ellipsoidalHead>
<standardComponentData>
<variousElements>
<idNumber>234567</idNumber>
<nominalThickness units="in">0.3750</nominalThickness>
</standardComponentData>
</ellipsoidalHead>
</topClosure>
</closure1>
<shell>
<standardComponentData>
<various_elements>
<nominalThickness units="in">0.6250</nominalThickness>
<idNumber>123456</idNumber>
</standardComponentData>
</shell>
<nozzle>
<standardComponentData>
<various_elements>
<attachedToidNumber>123456</attachedToidNumber>
</standardComponentData>
<nozzle>
In my JS code, I already have the <nozzle> element bomNode as a jQuery set, i.e.
var bomNode = $("nozzle");
So, for each nozzle element, I need to
Get the value of <attachedToidNumber> in the <nozzle> element.
Find the element that contains the <idNumber> that matches
<attachedToidNumber> (<shell> in this case).
Get the value in the <nominalThickess>
element.
As you can see, the depth of the desired <idNumber> element can vary. This is also a very small subset of the whole XML structure, so it can be very large.
I've tried something like this:
var attachedToElement = bomNode.parents().find('idNumber').text() === attachedToId;
but I get false returned. What's the easiest way to get the desired idNumber value? I'm sure it's something simple, but I'm just missing it.
Thanks.
UPDATE: I realized that bomNode is at the top level, I don't need to go up. a level. Doing something like this
var attachedToElement = bomNode.parents().siblings().find('idNumber')
gives me a list of children elements that have an <idNumber> element. So, I need to find the one that has the desired value. My thought is to use .each(). However, that value is defined outside of the .each() function, so I don't have anything to match against. Once I have the list of matches, what's the easiest way to get the set that has the <idNumber> value I want?
You were right - you missed a simple thing:
shell is not a parent of nozzle. They are siblings. Try this:
var attachedToElement = bomNode.siblings().find('idNumber').text() === attachedToId;
But this would return true (if true) - not the actual value.
I'm in a situation where I can't use jquery to select an element inside the DOM and trying to figure out how to use Javascript to do it.
The jquery path is $('.link-linkedin a').attr('href');
I'm trying to get to the href and open it in a new tab.
I found this - http://javascript.info/tutorial/searching-elements-dom and tried doing
var elem = document.getElementsByClassName('link-linkedin')
var list = elem.getElementsByTagName('a')
But I'm getting the error:
Uncaught TypeError: elem.getElementsByTagName is not a function(…)
Is there a better way to do this?
// where `linkIndex` , `aIndex` are index of each respective element
// to be selected from collections returned by `.getElementsByClassName` ,
// `.getElementsByTagName`
var linkIndex = 0, aIndex = 1;
var elem = document.getElementsByClassName('link-linkedin')[linkIndex];
var list = elem.getElementsByTagName('a')[aIndex];
var href = list.href;
You don't need javascript for that. Just add target="_blank" to your anchor element.
Something like this:
whatever
This will open the link on a new tab when you click it.
I am going to go ahead and put this as an answer. First, it is unclear what you are trying to do, but some things will help your code.
Put semi-colons at the end of each instruction.
Do not call a variable "list" - list of what - use better naming, and avoid words that could be used as a reserved word.
If you are trying to reference an element in the DOM, give it an ID, and then use document.getElementById to get at it.
Customers
And to reference it in your javascript:
var ListOfCustomers = document.getElementById("LinkToCustomers");
window.open(ListOfCustomers.getAttribute("href"));
This question already has answers here:
How to select last child element in jQuery?
(6 answers)
Closed 9 years ago.
I am taking a fairly simple piece of code and wrapping into a function, the code builds a slide out menu from the items inside a div. I'm now trying to get the last child from a div:
experimentOne('#experimentOne');
function experimentOne(masterContainer) {
var experimentOneMenuButton = $('masterContainer :last-child');
... etc
However, this returns [] in the log. When I check the width, instead of the 100px it should be, it's 1420 which I'm guessing is the window width.
If I just get the last child of the ID by coding it in everything is fine, but I want the function to be as reusable as possible.
Thanks.
Try this if your masterContainer is an element:
var experimentOneMenuButton = $(':last-child', masterContainer);
Or this if it is a string for the element id
var experimentOneMenuButton = $('#'+masterContainer+' :last-child');
masterContainer is a variable containing the value of the parent container, so when you build the selector you need use it with string concatenation.
var experimentOneMenuButton = $(masterContainer + ' :last-child');
or you can use a context based lookup
var experimentOneMenuButton = $(':last-child', masterContainer);
I would recommend the second solution which make use of context bases lookup since it is neater.
Demo: Fiddle
element with id is selected with "#"
you need to target immediat children with ">", [space] target all descendants of element
$('#masterContainer>:last-child');
Well masterContainer inside the string will do nothing. I think it should be:
$(masterContainer).find(':last-child');
Also note that experimentOne('#experimentOne'); will send a string not a jQuery object. That would require experimentOne($('#experimentOne'));, which would leave:
experimentOne($('#experimentOne'));
function experimentOne(masterContainer) {
var experimentOneMenuButton = masterContainer.find(':last-child');
// Note the lack of jQuery wrapper around masterContainer in this version
Depends on whether you want to force a jQuery object in the parameter or in the function itself!
Your concatenation is wrong. Try that way:
$(masterContainer + ' :last-child')