How to loop through options in a drop down list? - excel

I am trying to loop through the options or items of a drop down menu, but I don't know the number of items as it will be changeable every time.
Here's the html part of the sList3
<select name="ctl00$ContentPlaceHolder1$Dschool" onchange="javascript:setTimeout('__doPostBack(\'ctl00$ContentPlaceHolder1$Dschool\',\'\')', 0)" id="ContentPlaceHolder1_Dschool" style="font-size:12pt;font-weight:bold;width:500px;">
<option selected="selected" value="0"> Select From Menu </option>
<option value="311223">first option</option>
<option value="311625">some option</option>
</select>
Here's my code that I have started
For i = 1 To 4
Set sList1 = .FindElementById("ContentPlaceHolder1_Dedara").AsSelect
sList1.SelectByIndex i
.Wait 2000
Set sList2 = .FindElementById("ContentPlaceHolder1_Drel").AsSelect
sList2.SelectByIndex 1
.Wait 2000
Set sList3 = .FindElementById("ContentPlaceHolder1_Dschool").AsSelect
'How can I loop through the options (unknown in length)
Next i
I would like to loop each option and debug.print the value of the option.
SOLUTION
With the help of JeffC this is the final solution
For j = 1 To sList3.Options.Count
Debug.Print sList3.Options(j).Text
Next j

I think you can use for each loop
WebElement selectElement = driver.findElement(By.xpath("//select[#id='ContentPlaceHolder1_Dschool']"));
Select select = new Select(selectElement);
List<WebElement> options = select.getOptions();
for (WebElement we : options)
{
System.out.println("Element="+we.getText());
}

You can use CSS selector to get collection of the options under the parent id
Dim elements As Object, element As Object
Set elements = driver.FindElementsByCss("#ContentPlaceHolder1_Dschool option")
Then loop
For Each element In elements:
Debug.Print element.text
Next
CSS:
If the id is dynamic switch css to
[id^=ContentPlaceHolder1] option

Related

VBA Automation - Prefilling Combodate Box

I am trying to prefill data from Excel to a local intranet website via VBA.
I've been able to prefill most data to the site, but I am struggling with this combodate box:
Please see HTML code:
<div class="form-group row " id="starttime_field">
<label class="col-form-label col-md-3" for="starttime">Start time</label>
<div class="col-md-9">
<input type="text" id="starttime" name="starttime" class="form-control" size="30" style="display: none;"><span class="combodate">
<select class="hour " style="width: auto;"><option value="0">00</option><option value="1">01</option><option value="2">02</option><option value="3">03</option><option value="4">04</option><option value="5">05</option><option value="6">06</option><option value="7">07</option><option value="8">08</option><option value="9">09</option><option value="10">10</option><option value="11">11</option><option value="12">12</option><option value="13">13</option><option value="14">14</option><option value="15">15</option><option value="16">16</option><option value="17">17</option><option value="18">18</option><option value="19">19</option><option value="20">20</option><option value="21">21</option><option value="22">22</option><option value="23">23</option></select> :
<select class="minute " style="width: auto;"><option value="0">00</option><option value="1">01</option><option value="2">02</option><option value="3">03</option><option value="4">04</option><option value="5">05</option><option value="6">06</option><option value="7">07</option><option value="8">08</option><option value="9">09</option><option value="10">10</option><option value="11">11</option><option value="12">12</option><option value="13">13</option><option value="14">14</option><option value="15">15</option><option value="16">16</option><option value="17">17</option><option value="18">18</option><option value="19">19</option><option value="20">20</option><option value="21">21</option><option value="22">22</option><option value="23">23</option><option value="24">24</option><option value="25">25</option><option value="26">26</option><option value="27">27</option><option value="28">28</option><option value="29">29</option><option value="30">30</option><option value="31">31</option><option value="32">32</option><option value="33">33</option><option value="34">34</option><option value="35">35</option><option value="36">36</option><option value="37">37</option><option value="38">38</option><option value="39">39</option><option value="40">40</option><option value="41">41</option><option value="42">42</option><option value="43">43</option><option value="44">44</option><option value="45">45</option><option value="46">46</option><option value="47">47</option><option value="48">48</option><option value="49">49</option><option value="50">50</option><option value="51">51</option><option value="52">52</option><option value="53">53</option><option value="54">54</option><option value="55">55</option><option value="56">56</option><option value="57">57</option><option value="58">58</option><option value="59">59</option></select></span><span class="combodate"><select class="hour " style="width: auto;"><option value="0">00</option><option value="1">01</option><option value="2">02</option><option value="3">03</option><option value="4">04</option><option value="5">05</option><option value="6">06</option><option value="7">07</option><option value="8">08</option><option value="9">09</option><option value="10">10</option><option value="11">11</option><option value="12">12</option><option value="13">13</option><option value="14">14</option><option value="15">15</option><option value="16">16</option><option value="17">17</option><option value="18">18</option><option value="19">19</option><option value="20">20</option><option value="21">21</option><option value="22">22</option><option value="23">23</option></select> : <select class="minute " style="width: auto;"><option value="0">00</option><option value="1">01</option><option value="2">02</option><option value="3">03</option><option value="4">04</option><option value="5">05</option><option value="6">06</option><option value="7">07</option><option value="8">08</option><option value="9">09</option><option value="10">10</option><option value="11">11</option><option value="12">12</option><option value="13">13</option><option value="14">14</option><option value="15">15</option><option value="16">16</option><option value="17">17</option><option value="18">18</option><option value="19">19</option><option value="20">20</option><option value="21">21</option><option value="22">22</option><option value="23">23</option><option value="24">24</option><option value="25">25</option><option value="26">26</option><option value="27">27</option><option value="28">28</option><option value="29">29</option><option value="30">30</option><option value="31">31</option><option value="32">32</option><option value="33">33</option><option value="34">34</option><option value="35">35</option><option value="36">36</option><option value="37">37</option><option value="38">38</option><option value="39">39</option><option value="40">40</option><option value="41">41</option><option value="42">42</option><option value="43">43</option><option value="44">44</option><option value="45">45</option><option value="46">46</option><option value="47">47</option><option value="48">48</option><option value="49">49</option><option value="50">50</option><option value="51">51</option><option value="52">52</option><option value="53">53</option><option value="54">54</option><option value="55">55</option><option value="56">56</option><option value="57">57</option><option value="58">58</option><option value="59">59</option></select></span>
This is what this section of the form looks like (highlighted in red):
ComboBox Form
Here is a snippet of the code I am using:
Sub Legends()
Dim IE As InternetExplorerMedium
Dim Environment As String
Dim webContent As String
Dim NOME_EMPRESA, CNPJ, CPF, COD_ACESSO As String
Dim Lookup_Range As Range
Dim SH
Dim confirmationBox As Integer
confirmationBox = MsgBox("Confirm Legendary Promotion changes to " & Worksheets("Legends").Range("E2") & "?", vbYesNoCancel, "Woolly Legends")
'Confirmation box data if yes is clicked
Select Case confirmationBox
Case vbYes
Dim eachIE
'Choosing the environment
If ThisWorkbook.Sheets("Legends").Range("E2").Value = ThisWorkbook.Sheets("Parameters").Range("A2") Then
AD = ThisWorkbook.Sheets("Parameters").Range("C2").Value
Environment = AD
End If
If ThisWorkbook.Sheets("Legends").Range("E2").Value = ThisWorkbook.Sheets("Parameters").Range("A3") Then
AC= ThisWorkbook.Sheets("Parameters").Range("C3").Value
Environment = AC
End If
If ThisWorkbook.Sheets("Legends").Range("E2").Value = ThisWorkbook.Sheets("Parameters").Range("A4") Then
AB = ThisWorkbook.Sheets("Parameters").Range("C4").Value
Environment = AB
End If
If ThisWorkbook.Sheets("Legends").Range("E2").Value = ThisWorkbook.Sheets("Parameters").Range("A5") Then
Testing = ThisWorkbook.Sheets("Parameters").Range("C5").Value
Environment = Testing
End If
Set IE = New SHDocVw.InternetExplorer
IE.navigate Environment
ShowWindow IE.hwnd, SW_MAXIMIZE
Do
Set SH = New Shell32.Shell
For Each eachIE In SH.Windows
If InStr(1, eachIE.LocationURL, Environment) Then
Set IE = eachIE
'ie.Visible = False 'This is here because in some environments, the new process defaults to Visible.
Exit Do
End If
Next eachIE
Loop
Set eachIE = Nothing
Set SH = Nothing
'Setting doc to allow for form manipulation via Excel
Set doc = IE.document
'Setting the Promotion Names for the Text Promotion
IE.document.all("promo_name").Value = ThisWorkbook.Sheets("Legends").Range("b3")
IE.document.all("race_name").Value = ThisWorkbook.Sheets("Legends").Range("b19")
'Setting start date and end date
IE.document.all("startdate").Value = Format$(ThisWorkbook.Sheets("Legends").Range("b7").Value, "yyyy-mm-dd")
IE.document.all("enddate").Value = Format$(ThisWorkbook.Sheets("Legends").Range("b8").Value, "yyyy-mm-dd")
'Setting the Runner Names
IE.document.all("runner_names_0").Value = ThisWorkbook.Sheets("Legends").Range("b20")
IE.document.all("runner_names_1").Value = ThisWorkbook.Sheets("Legends").Range("b21")
IE.document.all("runner_names_2").Value = ThisWorkbook.Sheets("Legends").Range("b22")
IE.document.all("runner_names_3").Value = ThisWorkbook.Sheets("Legends").Range("b23")
IE.document.all("runner_names_4").Value = ThisWorkbook.Sheets("Legends").Range("b24")
IE.document.all("runner_names_5").Value = ThisWorkbook.Sheets("Legends").Range("b25")
'Setting the dropdown box for the jurisdictions
If ThisWorkbook.Sheets("Legends").Range("B4").Value = "AAA" Or ThisWorkbook.Sheets("Legends").Range("B5").Value = "AAB" Or ThisWorkbook.Sheets("Legends").Range("B6").Value = "AAC" Then
IE.document.all("jurisdiction[]").Options(0).Selected = True
End If
If ThisWorkbook.Sheets("Legends").Range("B4").Value = "BBB" Or ThisWorkbook.Sheets("Legends").Range("B5").Value = "BBA" Or ThisWorkbook.Sheets("Legends").Range("B6").Value = "BBC" Then
IE.document.all("jurisdiction[]").Options(1).Selected = True
End If
If ThisWorkbook.Sheets("Legends").Range("B4").Value = "CCA" Or ThisWorkbook.Sheets("Legends").Range("B5").Value = "CCB" Or ThisWorkbook.Sheets("Legends").Range("B6").Value = "CCC" Then
IE.document.all("jurisdiction[]").Options(2).Selected = True
End If
End Select
End Sub
I am unsure how to pre-populate data from the spreadsheet into the hour and minute comboboxes, as the layout of this is a bit different from the other fields in the html.
Any help or guidance would be greatly appreciated.
Thanks!
The hour and minute boxes are select elements which means with InternetExplorer automation you have two main methods for selecting individual items (and a couple of alternates for tricky situations):
You can use selectedIndex on the select itself then specify index of option of interest in the list under that select. I think starts at 1 but you would need to check.
Use .Selected = True on the option element itself.
As you have options that have the same values you need to isolate the dropdowns by the parent select if using second method. This can be done by adding parent className in front.
Method 1:
hour
ie.document.querySelector(".hour").SelectedIndex = 1
minute
ie.document.querySelector(".minute").SelectedIndex = 1
Method 2:
hour
ie.document.querySelector(".hour [value='0']").Selected = True 'hour 00
minute
ie.document.querySelector(".minute [value='0']").Selected = True 'minute 00
Alternates are predominately the above/variants thereof written in javascript and executed by method of
ie.document.parentWindow.execScript. This can be helpful when elements are not interactable for some reason but generally frowned
upon by QA automation specialists in particular.
Reading:
CSS Selectors
EDIT:
To differentiate starttime from endtime based on html provided e.g.
ie.document.querySelector(".combodate + .combodate .hour [value='0']").Selected =True 'end hour
ie.document.querySelector(".combodate + .combodate .minute [value='0']").Selected =True 'end minute
Using variable
Dim var As Long
var = 0
ie.document.querySelector(".combodate .hour [value='" & cstr(var) & "']").Selected =True 'start hour
Although your HTML doesn't reflect this I would have expected something more like:
ie.document.querySelector("#starttime_field .combodate .hour [value='" & cstr(var) & "']").Selected =True
ie.document.querySelector("#endtime_field .combodate .hour [value='" & cstr(var) & "']").Selected =True

Need help selecting multiple items in combobox in IE, using VBA

I am having an issue with one part of my automation job, and that is selecting ALL the options in a combobox, on a webpage, using VBA and IE.
This code selects ONE item in the combo box
Set frm = HTMLDoc.getElementsByName("UFG.USER_TYPES")(0)
frm.Value = "AUT"
However, when I try to select multiple items, it just selects the last one, not all of them.
Here is the code from the web page
<p id="DispFormCollapsible.Rc10"class="formrow" >
<span id="DispFormCollapsible.Rc10.C1" class="querytextleft">
<label for="UFG.USER_TYPES" id="LabelForContro123"class = "simpletext" >
Accessible Types:<span class="redstar">*</span></label></span>
<span id="DispFormCollapsible.Rc10.C2" class="querytextright">
<span class="labelColumn_combo">
<span class="labelColumn_combi_brdr">
<select name= "UFG.USER_TYPES" multiple= "true" class = "dropdownexpandalbe"
id="UFG.USER_TYPES" title = "Accessible Financial Transaction Types">
<option value="AUT" title="ACTIVE USER TYPE1" >TYPE1</option>
<option value="SET" title="Selective User Type" >TYPE2</option>
<option value="TST" title="Test User Type" >TEST3</option>
</select></span></span>
<input type ="hidden" name= "UFG.USER_TYPES" value="NULL" >
</span></p>
Here is my VBA line to select an item
Set frm = HTMLDoc.getElementsByName("UFG.USER_TYPES")(0)
frm.Value = "AUT"
What I need it to do, is select all the "option values" in the combobox. I think it needs to be an array maybe, or some other way. I've tried searching, but I'm getting nowhere. Any help appreciated. Thx
Tried the following, but get an error 91 Block not set. I've also tried using the Values "AUT" in the children, and when doing that I don't get an error, but it doesn not select anything.
With HTMLDoc.getElementsByName("Select")(0)
.Children(1).Selected = True
.Children(2).Selected = True
.Children(3).Selected = True
End With
Also tried the following, this doesn't give an error, but only selects the first option in the list.
With HTMLDoc.getElementsByName("UFG.USER_TYPES")(0)
.Children(AUT).Selected = True
.Children(SET).Selected = True
.Children(TST).Selected = True
End With
This is strange, when I use this code, it selects the first two in the list, but not the third.
With HTMLDoc.getElementsByName("UFG.USER_TYPES")(0)
.Children(all).Selected = True
End With
With HTMLDoc.getElementsByName("UFG.USER_TYPES")(0)
.Children(0).Selected = True
.Children(1).Selected = True
.Children(2).Selected = True
End With
The above code fixed it... whoopie!

Cannot get the text of nth span element using vba

I have the following html part
<div class="description">
<span>Brand:</span>
Nikon<br/>
<span>Product Code:</span> 130342 <br/>
<span>Barcode</span> 18208948581 <br/>
<span>Availability:</span>Available</div>
I am trying to get the last span and the word Available using the following
Set availability = ie.Document.getElementsByClassName(".description").getElementsByTagName("span")(2)
wks.Cells(i, "D").Value = availability.innerText
But it shows all span texts
What I am doing wrong here?
Use last-child css pseudo class in descendant combination with parent element class selector.
.description span:last-child
The :last-child CSS pseudo-class represents the last element among a
group of sibling elements.
Applying:
single match
Set availability = ie.document.querySelector(".description span:last-child")
Cells(1,1) = availability.innerText
all matches
Set availability = ie.document.querySelectorAll(".description span:last-child")
Cells(1,1) = availability.item(0).innerText
Otherwise, you can return the span collection from that parent class and index into it
Set availability = ie.document.querySelectorAll(".description span")
Cells(1,1) = availability.item(2).innerText '<==choose your index here
Or even chain:
Set availability = ie.document.querySelector(".description span + span + span") '<==expand as required. This uses [adjacent sibling combinator][4].
Sadly, pseudo classes nth-of-type / nth-child are not supported in VBA implementation though you can in many other languages e.g. python.
—-
If after just the Available you should be able to use .description as your selector to return all the text in the div. Then use Split on the .innerText using Chr$(32) to split by and extract the UBound (I.e. the last element of the generated array)
Set availability = ie.document.querySelector(".description")
Dim arr() As String
arr = split( availability.innerText, ":")
Cells(1,1) = arr(UBound(arr))
As Zac pointed out in the comments, you shouldn't use a period . with the getElementsByClassName method.
ie.Document.getElementsByClassName is returning a DispHTMLElementCollection of elements. You need to specify which element you want to reference
Set availability = ie.Document.getElementsByClassName(".description")(0).getElementsByTagName("span")(2)
A better way to write the write the code would be to reference the Microsoft HTML Object Library and create a variable to test each element returned. Unfortunately, there is a bug in the DispHTMLElementCollection implementation, so you will need to use Object instead of DispHTMLElementCollection.
Dim doc As HTMLDocument
Dim availability As Object
Set doc = ie.Document
Set availability = doc.getElementsByClassName("description")
Dim div As HTMLDivElement
Dim span As HTMLSpanElement
Dim spans As Object
For Each div In availability
Set spans = div.getElementsByTagName("span")
For Each span In spans
Debug.Print span.innerText
Next
Next
Output

Web scraping worked fine in IE 9 but breaks in IE 11

I had a procedure that scraped information from a website in IE9 however after updating to IE11 the procedure breaks when trying to enter a piece of data into
an input box on the webpage. The code recognizes the field and it is listed as on object when I debug but when I try to enter a value into the box using CUSIP.value it does not enter anything on the webpage. I think it has something to do with the source being updated after the browser was updated. I could have sworn that the identifier for "txtCusipNo" in the HTML was listed as an ID instead of a Name. Any help is appreciated. Thanks.
HTML from website
<td class="tbl1">
<INPUT TYPE="TEXT" NAME="txtCusipNo" VALUE="" CLASS="input" SIZE="11" MAXLENGTH="9">
<img src="/RDPANN/pbs/images/lookup.gif" border="0" alt="Open Security Finder" align="absmiddle"> <IMG NAME="txtCusipIMG"SRC="/RDPANN/pbs/images/req.gif" ALIGN="ABSMIDDLE">
</td>
VBA code
Private Sub EnterCUSIP()
Retry:
Set CUSIP = Doc.getElementById("txtCusipNo")
Err.Clear
valA = ActiveSheet.Cells(row, 1)
On Error Resume Next
CUSIP.Value = ActiveSheet.Cells(row, 1) 'insert CUSIP
If Err.Number = 91 Then GoTo Retry
Set CurrentWindow = IE.document.parentWindow
Call CurrentWindow.execScript("javascript:processForm(document.forms.frmSearchEntry)") 'Search (hit enter)
If Err.Number = -2147352319 Then Exit Sub
On Error GoTo 0
Do While (IE.Busy Or IE.READYSTATE <> READYSTATE.READYSTATE_COMPLETE):DoEvents: Loop
End Sub
If you suspect that the HTML source has been changed and may make unannounced changes in the future, I would recommend switching to the ie.Document.All.Item property.
Doc.all.Item("txtCusipNo").Value = 123
The .Item identifier can be either an ID or a Name, there is no distinction between the two. However, I would be concerned that the identifying factor (e.g. txtCusipNo) may not be unique on that page. Yes, it is supposed to be but a growing number of HTML developers are using code like divs(0).getElementById("txtCusipNo") and divs(1).getElementById("txtCusipNo").

Using excel vba to change the value of a dropdown menu on a website

I am writing an Excel macro to fill out a form on a website. I have written the code that populate the text boxes easily enough, and found code to chose radio boxes, but I am having problems with choosing info from dropdown menus.
Example 'Gender':
The combo box has three options:
Select / Male / Female
I've tried a few variations on this:
doc.getElementsByName("xs_r_gender").Item(0).Value="Male"
...but with no luck.
This is the web source code:
<td> <select name="xs_r_gender" id="xs_r_gender">
<option value="" selected>Select</option>
<option value="male">Male</option>
<option value="female">Female</option> </select></td>
Thanks.
doc.getElementById("xs_r_gender").selectedindex=1
seems to do the trick. (Where 1 represents male)
Though it means I will need to do alot of lookups to determine what the value is for the items in my dropdown. (Easy enough for Sex, where there are only two options, but I have some comboboxes with up to 50 options). If anyone knows of a faster solution, that'd be great. In the meantime, Ill start doing up some tables!!!
thanks.
Try below code assuming doc = ie.document
doc.getElementById("xs_r_gender").value = "Male"
Use this in your code to call the function below.
xOffset = SetSelect(IE.Document.all.Item("shipToStateValue"), "Texas")
doc.getElementById("shipToStateValue").selectedindex = xOffset
Then use this for your function
Function SetSelect(xComboName, xComboValue) As Integer
'Finds an option in a combobox and selects it.
Dim x As Integer
For x = 0 To xComboName.options.Length - 1
If xComboName.options(x).Text = xComboValue Then
xComboName.selectedindex = x
Exit For
End If
Next x
SetSelect = x
End Function
Thanks Stack, works for me! My solution to operate an IE HTML combobox drop down turned out to be two parts.
Part 1 was to click the pull down, here's code:
Dim eUOM1 As MSHTML.HTMLHtmlElement
Set eUOM1 = ie.document.getElementsByTagName("input")(27).NextSibling
eUOM1.Focus
eUOM1.Click
Part 2 was to choose and click the value, like this (*actual element name changed):
Dim eUOM2 As MSHTML.HTMLHtmlElement
Set eUOM2 = ie.document.getElementsByName("[*PutNameHere]")(0)
eUOM2.Value = "EA"
eUOM2.Click
Here are references:refs
You can try the querySelector method of document to apply a CSS selector of option tag with attribute value = 'male':
doc.querySelector("option[value='male']").Click
or
doc.querySelector("option[value='male']").Selected = True
Function SetSelect(s, val) As Boolean
'Selects an item (val) from a combobox (s)
'Usage:
'If Not SetSelect(IE.Document.all.Item("tspan"), "Custom") Then
'something went wrong
'Else
'continue...
'End If
Dim x As Integer
Dim r As Boolean
r = False
For x = 0 To s.Options.Length - 1
If s.Options(x).Text = val Then
s.selectedIndex = x
r = True
Exit For
End If
Next x
SetSelect = r
End Function
Try this code :
doc.getElementById("xs_r_gender").value = "Male"
doc.getElementById("xs_r_gender").FireEvent("onchange")
You can do something like this:
doc.getElementsByName("xs_r_gender").Item(1).Selected=True
or
doc.getElementById("xs_r_gender").selectedindex = 1
Where 1 is the male option (in both cases).
If the dropbox needs to fire some event in order to aknowledge your choice, it is likely that it will be the "onchange" event. You can fire it like so:
doc.getElementById("xs_r_gender").FireEvent("onchange")
If you ever want to be able to select an option based on the option's text you can use the function given by Lansman (here) .
Based on the same answer, if you want to call the option by it's value property (instead of the text, you can just change the line If xComboName.Options(x).Text = xComboValue Then to If xComboName.Options(x).value = xComboValue Then).
This should cover all bases.
Copy from Here till last line:
Sub Filldata()
Set objShell = CreateObject("Shell.Application")
IE_count = objShell.Windows.Count
For X = 0 To (IE_count - 1)
On Error Resume Next ' sometimes more web pages are counted than are open
my_url = objShell.Windows(X).document.Location
my_title = objShell.Windows(X).document.Title
If my_title Like "***Write your page name***" Then
Set IE = objShell.Windows(X)
Exit For
Else
End If
Next
With IE.document.forms("***write your form name***")
' Assuming you r picking values from MS Excel Sheet1 cell A2
i=sheet1.range("A2").value
.all("xs_r_gender").Item(i).Selected = True
End with
End sub

Resources