Loop until value is found - vba

I'm new to VBA Selenium, I would like to loop until a value is found. This code is not working because it just captures a text, not repeating until it finds the value. Could someone help me?
In my research I didn't find how to put a loop inside this code
If Status <> "" Then
capture = 100
new:
Status = drive.FindElementByXPath("/html/body/div[1]/div/div/div[4]/div/div[2]/div/div[2]/div[2]/div[ & capture & 1]/div/div/div[1]/div[1]/div[2]/div/div/span").Attribute("ariaLabel")
Else
capture = capture - 1
GoTo new
End If

Related

The control could not be found by id. SAP GUI bug?

I am trying to automate SAP data extraction using scripting. The problem I am facing is a recorded script in SAP isn't working when I'm running it, when I use findById("id") method it comes out that cannot be found, however the tabs are there.
The idea is to move between the tabs (using session.findById("id").Select) to extract info in that panels. Use a list of Purchase Orders (PO's), make a loop and extract the information, it's simple.
However, these tabs aren't found randomly. Sometimes it works, sometimes it is not found. All PO's (if I do it manually) have tabs with the data, but in the script it doesn't work.
For example:
The red box is the tabs that I am trying to select
Output of the recorded script (just moving between tabs):
If Not IsObject(application) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(connection) Then
Set connection = application.Children(0)
End If
If Not IsObject(session) Then
Set session = connection.Children(0)
End If
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject application, "on"
End If
session.findById("wnd[0]").resizeWorkingPane 183,24,false
session.findById("wnd[0]/usr/subSUB0:SAPLMEGUI:0015/subSUB3:SAPLMEVIEWS:1100/subSUB2:SAPLMEVIEWS:1200/subSUB1:SAPLMEGUI:1301/subSUB2:SAPLMEGUI:1303/tabsITEM_DETAIL/tabpTABIDT13").select
' Extract info
session.findById("wnd[0]/usr/subSUB0:SAPLMEGUI:0019/subSUB3:SAPLMEVIEWS:1100/subSUB2:SAPLMEVIEWS:1200/subSUB1:SAPLMEGUI:1301/subSUB2:SAPLMEGUI:1303/tabsITEM_DETAIL/tabpTABIDT15").select
' Extract info
session.findById("wnd[0]/usr/subSUB0:SAPLMEGUI:0015/subSUB3:SAPLMEVIEWS:1100/subSUB2:SAPLMEVIEWS:1200/subSUB1:SAPLMEGUI:1301/subSUB2:SAPLMEGUI:1303/tabsITEM_DETAIL/tabpTABIDT18").select
' Extract info
Error:
The control could not be found by id.
I'm using:
My theory, the tab is hidden and doesn't find it, that I would have to use the arrows to move, however when I use the arrows at the time of making the script recording, it simply doesn't add them to the code.
Sorry for my English, and thanks in advance for your time.
I can only offer a workaround on this phenomenon.
for example:
...
for i = 1 to 99
on error resume next
session.findById("wnd[0]/usr/subSUB0:SAPLMEGUI:00" & right("0" & cstr(i),2) & "/subSUB3:SAPLMEVIEWS:1100/subSUB2:SAPLMEVIEWS:1200/subSUB1:SAPLMEGUI:1301/subSUB2:SAPLMEGUI:1303/tabsITEM_DETAIL/tabpTABIDT13").select
if err.number = 0 then exit for
on error goto 0
next
on error goto 0
' Extract info
for i = 1 to 99
on error resume next
session.findById("wnd[0]/usr/subSUB0:SAPLMEGUI:00" & right("0" & cstr(i),2) & "/subSUB3:SAPLMEVIEWS:1100/subSUB2:SAPLMEVIEWS:1200/subSUB1:SAPLMEGUI:1301/subSUB2:SAPLMEGUI:1303/tabsITEM_DETAIL/tabpTABIDT15").select
if err.number = 0 then exit for
on error goto 0
next
on error goto 0
' Extract info
for i = 1 to 99
on error resume next
session.findById("wnd[0]/usr/subSUB0:SAPLMEGUI:00" & right("0" & cstr(i),2) & "/subSUB3:SAPLMEVIEWS:1100/subSUB2:SAPLMEVIEWS:1200/subSUB1:SAPLMEGUI:1301/subSUB2:SAPLMEGUI:1303/tabsITEM_DETAIL/tabpTABIDT18").select
if err.number = 0 then exit for
on error goto 0
next
on error goto 0
' Extract info
Regards,
ScriptMan
Ah yes, my favorite SAP screen: ME23N. Who knows what the SAPLMEGUI:00XX will be! But, if you find the element by it's name you'll never run into this problem. Additionally, this solves the problem of the tab you want not being there; because, depending on the line item of the PO, who knows what tabs will be available.
Here's how I get over this every time, without fail.
In your sub procedure use the function below. If the tab is there it will select it and return true and you can continue extracting your data. You need the tab text and the name of the tab strip.
You can find the name of the tab strip easily. Look at what has been recorded. It has the "tabs" prefix.
session.findById("wnd[0]/usr/subSUB0:SAPLMEGUI:0015/subSUB3:SAPLMEVIEWS:1100/subSUB2:SAPLMEVIEWS:1200/subSUB1:SAPLMEGUI:1301/subSUB2:SAPLMEGUI:1303/tabsITEM_DETAIL/tabpTABIDT13")
Public Sub Main()
If IsTabThere("ITEM_DETAIL", "Account Assignment") = True Then
' Extract info
End If
If IsTabThere("ITEM_DETAIL", "Purchase Order History") = True Then
' Extract info
End If
End Sub
Public Function IsTabThere(ByVal tabStripName As String, ByVal tabText As String) As Boolean
Dim userArea As Object
Dim tabStrip As Object
Dim tabToSelect As Object
Set userArea = session.FindById("wnd[0]/usr")
Set tabStrip = userArea.FindByName(tabStripName, "GuiTabStrip").Children
For Each tabToSelect In tabStrip
If tabToSelect.Text = tabText Then
tabToSelect.Select
IsTabThere = True
' Will exit here if the tab was selected and return true
Exit Function
End If
Next
IsTabThere = False
End Function
Hope this makes your day. Good luck!
If your interested in making your script more dynamic checkout my answer on this post. I explain how to get started using the SAP GUI Scripting API.
how-to-run-sap-gui-script-from-excel-macro

Automate a Listbox value in VBA

Hello I'm trying to automate a value into a website that has two list boxes in it.
For the first List box this code works, However It doesn't work for the second list box. I can't just copy and paste this code below it for the second one even if I change the variable "a". Any help is appreciated!
For a = 1 To cats.Options.Length
If cats.Options(a).Text = "Option One" Then
cats.selectedindex = a
Exit For
End If
Next a
If you're working with multiple lists then you should come up with a re-useable block of code which you can call for any list+value.
Something like:
Function SetByTextValue(lst as object, v as string) As Boolean
Dim a as long
For a = 0 To lst.Options.Length - 1
If lst.Options(a).Text = v Then
lst.selectedindex = a
SetByTextValue = True
Exit Function
End If
Next a
End Function
Then in your main code you can do something like:
If Not SetByTextValue(cats, "Option One") Then
'not found
Else
'...proceed with next list
End If

VBA Excel Return value based on list

The VBA code below was supplied to us, and should make it possible to return streetaddresses based on the postcode and housenumbers we have in excel.
But I can't seem to get it to work at all. Mind I am not a VBA expert :(
I have the key and know it's needed. I have a column with postcodes, and a column with streetnumbers. I need to output a streetname for each of those lines.
Any idea how to set this up?
Sub gkkx()
Dim xDoc As Object
Set xDoc = CreateObject("Microsoft.XMLDOM")
xDoc.async = False
If xDoc.Load("https://api.pro6pp.nl/v1/autocomplete?auth_key=KEYGOESHERE&format=xml&pretty=True&nl_sixpp=" & Postcode & "&streetnumber=" & Streetnumber) Then
If xDoc.DocumentElement.Text = "Not found" Then
Plaats = ""
Adres = ""
Else
If xDoc.DocumentElement.ChildNodes.Length = 0 Then
Dim xDoc2 As Object
Set xDoc2 = CreateObject("Microsoft.XMLDOM")
xDoc2.async = False
xDoc2.Load ("https://api.pro6pp.nl/v1/autocomplete?auth_key=KEYGOESHERE&format=xml&pretty=True&nl_sixpp=" & Left(Postcode, 4))
Plaats = xDoc2.DocumentElement.SelectSingleNode("result/city").Text
Adres = ""
Set xDoc2 = Nothing
Else
Plaats = xDoc.DocumentElement.SelectSingleNode("results/result/city").Text
Adres = xDoc.DocumentElement.SelectSingleNode("results/result/street").Text
End If
'If xDoc.documentElement.childNodes.length > 1 Then
' Tekst41 = MsgBox("Meerdere straten op deze Postcode", vbInformation, "Meerdere Straten")
'End If
End If
Else
' The document failed to load.
Plaats = ""
Adres = ""
End If
Set xDoc = Nothing
End Sub
I'm just glancing through your code and not doing any testing or really analyzing what it is supposed to do. There are some code lines commented-out at the bottom section:
'If xDoc.documentElement.childNodes.length > 1 Then
' Tekst41 = MsgBox("Meerdere straten op deze Postcode", vbInformation, "Meerdere Straten")
'End If
You may want to ask the code author if they intended this section of code to be left in as a comment - commenting-out code means the lines of code are ignored by the compiler. Comments are created by prefixing any text with the apostrophe character. Many times, when someone is writing code, they will comment out parts of the code so they can test individual sections of the code. It could be that the author was doing this and forgot to un-comment (by deleting the apostrophes) this section of code.
Also, I would point out that this code appears to be working with Microsoft.XMLDOM. To get a start on understanding what this code is doing, you may want to have a look HERE.
It's probably not a total answer but I hope it helps. It is a bit difficult, based on the brevity and vagueness of your question, to really have a picture of what you are trying to ask.

VBA 2042 Type mismatch - #N/A - Array

I would have a problem in creating an array, which contains a number of data, which then will be merged into one file. During reading the info from the files, then having them put into the another merged file, the loop in which it is situated it find a 2042 error. I found in Add Watch that it wants to give back #N/A as the function in the original file does not returns anything. How can I avoid my macro stopping? I have found ways to skip this record, but I cannot insert it into my current loop because of insufficient experience in handling these. It stops at here "If aOutput(1, outputCol) = aDataFromPivotFiltered(1, filteredCol) Then" See below a small bit of the macro.
For outputCol = 1 To UBound(aOutput, 2)
For filteredCol = 1 To UBound(aDataFromPivotFiltered, 2)
If aOutput(1, outputCol) = aDataFromPivotFiltered(1, filteredCol) Then
For filteredRow = 2 To UBound(aDataFromPivotFiltered, 1)
aOutput(filteredRow, outputCol) = aDataFromPivotFiltered(filteredRow, filteredCol)
Next filteredRow
Exit For
End If
Next filteredCol
Next outputCol
I have found the below, which would be ok, but it is applied another macro.
Sub Test()
Dim varIn As Variant
[a1].FormulaR1C1 = "=NA()"
If IsError([a1].Value2) Then
varIn = "skip record"
Else
varIn = [a1].Value2
End If
End Sub
Is there anyone who could help me with this? It keeps causing headaches not matter how many article I am reading in this topic. Cannot figure out.
Test for errors first, like below:
If Not IsError(aDataFromPivotFiltered(1, filteredCol) And Not IsError(aOutput(1, outputCol)) Then
If aOutput(1, outputCol) = aDataFromPivotFiltered(1, filteredCol) Then
For filteredRow = 2 To UBound(aDataFromPivotFiltered, 1)
aOutput(filteredRow, outputCol) = aDataFromPivotFiltered(filteredRow, filteredCol)
Next filteredRow
Exit For
End If
End If
This way, any formula errors that are passed into the array will be skipped.

Using a macro generated variable within Evaluate function

I've created a macro variable active_search, which I'm trying to include in an evaluate function. However, the evaluate function is not outputting the correct value. Does anyone have suggestions on how to do this?
Code:
' this accurately provides the cell reference for the formula below
active_search = Cells(i, search_col).Address
active_match = Cells(i, match_col).Address
MsgBox active_search ' = &B$3 (or row i)
MsgBox active_match ' = $A$3
' formulas for the criteria below
' check_search = [IFERROR(MATCH(B3,list_keywords,0),0)] << Note: this works correctly
check_search = [IFERROR(MATCH(active_search,list_keywords,0),0)]
check_match = [IFERROR(SEARCH("exact",active_match,0)]
MsgBox check_search ' currently = 0 but should be 2250
MsgBox check_match
Thank you!
Let us expound what #simoco commented.
[] which is a shortcut for Evaluate function doesn't work on Variables.
To make it work, you have to explicitly use it as what simoco does in his comment.
To get the correct values use these instead (one already provided by simoco)
check_search = Evaluate("IFERROR(MATCH(" & active_search & "list_keywords,0),0)")
'~~> provided that list_keywords is named Range
check_match = Evaluate("IFERROR(SEARCH(""exact""," & active_match & ",0),0)")
Syntax: Evaluate(name) wherein the name argument is in a form of string.