VBA IE click button that requires argument? - vba

I'm using Excel and programming in VBA.
I've located a button that I want to click. However, it seems this button requires an argument.
Using the Console in Chrome, I typed this:
document.getElementById("button1").click
That line resolved function click() { [native code] }
so instead I tried this:
document.getElementById("button1").click ('100', '2016-03-02')
And it worked. So, how do I run the same thing from VBA?
I have tried the following:
Sub ClickTheButton()
Dim IE As SHDocVw.InternetExplorer
Dim Doc As MSHTML.HTMLDocument
Set IE = New SHDocVw.InternetExplorer
With IE
.Visible = True
.Navigate "(webpage here)"
Do Until Not .Busy And .ReadyState = 4
DoEvents
Loop
Set Doc = .Document
Doc.GetElementByID("button1").Click ' nothing happens when running this
Doc.GetElementByID("button1").Click "('100', '2016-03-02')" ' not working (can't even attempt to run this)
Doc.GetElementByID("button1").Click ("'100', '2016-03-02'") ' not working (can't even attempt to run this)
End With
End Sub
I can't run the procedure, because of the code after .Click returning Wrong number of arguments or invalid property assignments.
Any ideas?

Answer found here.
The click button ran a function. Instead of clicking the button I could instead just run the function like this:
Dim CurrentWindow As HTMLWindowProxy
Set CurrentWindow = IE.Document.parentWindow
Call CurrentWindow.execScript("xajax_DoCalReservation('100', '2016-03-02')")

Related

Windows Form run website without address bar

I've seen a lot of examples using JavaScript to run a popup window to remove address bar. My issue is I want to run a full website [that I've created in ASP.net] without the address bar visible from a Windows Form application.
I've tried:
Dim objIE As Object 'InternetExplorer 'or as object - if you want to keep it lite and don't add the reference
objIE = CreateObject("InternetExplorer.Application")
With objIE
.Visible = True
objIE.AddressBar = False
objIE.MenuBar = False
objIE.ToolBar = False
.Navigate2(Address)
End With
objIE.Navigate = Address
but I get an error at CreateObject of Cannot create ActiveX component.
So my current working code to run the website is:
Dim process As New System.Diagnostics.Process()
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden
Dim sInfo As New ProcessStartInfo(Address)
Process.Start(sInfo)
However, the address bar is visible.
Any suggestions?
That code should work fine, as I just tested it myself. I would say start a fresh VB file (console application/windows form, whichever you'd like) and try to run just these:
Dim objIE as Object
objIE = CreateObject("InternetExplorer.Application")
With objIE
.Visible = True
End With
If it does not run from there, then your best bet is to try to "Reset" your internet explorer, which can be done through the Settings/Options. I've done this in the past and it allowed to work. The fact that you cannot create the object is the concerning part, as that's being written correctly and when I run that on my PC it works.
Give those two a shot (try a fresh file, and reset internet explorer). And let me know if that works.

Clicking a button in IE using VBA

I am using Excel VBA to try click a button on a site, here's the code from the site using inspect element:
<button class="_ah57t _84y62 _frcv2 _rmr7s">ClickHere</button>
And here's what i'm doing in VBA:
Sub testcode()
Dim ie As InternetExplorer
Dim html As HTMLDocument
Set ie = New InternetExplorer
ie.Visible = True
ie.Navigate "somesite.com"
Do While ie.READYSTATE <> READYSTATE_COMPLETE
DoEvents
Loop
Dim e
Set e = ie.Document.getElementsByClassName("_ah57t _84y62 _frcv2 _rmr7s")
e.Click
End Sub
Using the debug I found that the code seems to be storing something called "[object]" in the variable e and and then gives a Runtime error '438' when it gets to e.click. I have even tried using .Focus first, but get the same error. Any ideas?
The getElementsByClassName() function returns a collection not a single element. You need to specify an index on the returned collection in order to return a single element. If there is only one element within the class you can simply use:
ie.Document.getElementsByClassName("_ah57t _84y62 _frcv2 _rmr7s")(0).Click
The (0) specifies the index of the element within the collection returned from the class.
Its easy to tell whether a function returns a collection or single element:
getElementBy... - Returns a single element.
getElementsBy... - Returns a collection of elements.

VBA-Excel: Filling forms in an IE Window

I'm hoping someone can help. I'm trying to speed up the process of filling a webform that must be completed dozens or hundreds of times with information stored in excel.
To do this, I need one button to open an IE window and navigate to a certain website's login page (I've figured this bit out). The user can then log in and navigate to the form that needs to be filled. Then, I'd like the user to be able to return to the excel page, click another button, which will automatically fill several drop downs and text boxes.
Within Excel, I already have some code to allow the user to search for the particular set of information that needs to go to the form, so all they should have to do is click the button to transfer it over. The first bit of the code is just this:
Public IE As Object
Public Sub OpenIE()
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
IE.Navigate "loginpage url"
End Sub
Where I'm having trouble, however, is having a different function access the same IE window once the user has logged in and navigated to the form. Right now I've got this:
Sub FillMacro()
Dim sh As Object, oWin As Object
Set sh = CreateObject("Shell.Application")
For Each oWin In sh.Windows
If TypeName(oWin.document) = "HTMLDocument" Then
Set IE = oWin
Exit For
End If
Next
IE.Visible = True
Application.Wait (Now + TimeValue("00:00:01"))
IE.document.getElementById("idec").Value = "John"
Application.Wait (Now + TimeValue("00:00:01"))
IE.document.getElementById("idee").Value = "Smith"
End Sub
Most of that I've gotten from other posts on this forum, and while I'm a bit of a novice at this, the problem seems to be that for some reason VBA can't find the text boxes with the id of LastName or FirstName. What's more, the IE.Visible = True doesn't bring the IE window back to the foreground, so I'm trying to find the proper line to do that. When I try to run the code, I get an "Object Required" error at:
IE.document.getElementById("idec").Value = "John"
I've tried searching this site and will continue to look, but any help in the meantime would be greatly appreciated!
On the Internet Explorer page, here is the line for the first text box I'm trying to fill:
<input name="componentListPanel:componentListView:1:component:patientLastNameContainer:patientLastName" class="input300" id="idec" type="text" maxlength="60" value="">
Why not automate logging process as well? Login could be stored in Excel and its value read by macro from cell.
As Tim Williams suggests, if there is Iframe on website, use (for me it works only with contentwindow included):
IE.document.getElementById("iFrameIdHere").contentwindow.document.getEleme‌ntById("idec").Value = "John"
Instead of Application.Wait use:
Do Until IE.ReadyState = 4 And IE.Busy = False
DoEvents
Loop
It will save you a lot of time when page loads fast and prevent errors when loading exceeds wait time. Use it ONLY after page reloads (meaning after navigating or anything what causes page reloads, especially .click on HTML elements.
Use early binding, it's a bit faster than creating objects. It can increase performance by a few percent based on page loading speed, the faster pages load, the bigger increase.
Set IE = New InternetExplorer
Finally, you can toggle loading pictures, depending on whether you need to download images from website.
Public Sub ShowPictures(ByVal EnabledStatus As Boolean)
Public ScrapingCancelled as Boolean
Dim obj_Shell
Dim v_Result As Variant
Set obj_Shell = CreateObject("WScript.Shell")
'Reads the registry key that determines whether 'Show pictures' Internet Explorer advanced setting is enabled
v_Result = obj_Shell.RegRead("HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\Display Inline Images")
Select Case v_Result
Case "yes" 'Pictures are displayed
If EnabledStatus = False Then _
obj_Shell.RegWrite "HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\Display Inline Images", "no", "REG_SZ"
Case "no" 'Pictures are not displayed
If EnabledStatus = True Then _
obj_Shell.RegWrite "HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\Display Inline Images", "yes", "REG_SZ"
Case Else
ScrapingCancelled = True
End Select
End Sub
No images loaded:
ShowPictures (0)
Images loaded:
ShowPictures (1)
A good practice is to set value to 1 in the end of macro.

Working with Internet Explorer Object

My goal is to create a VB application that reads and writes information to various webpages loaded in Internet explorer.
I have created a program that works exactly as I intend in VBA. I am now trying to re-implement the same programming in VB.
I have a function that looks for and returns an Internet Explorer Object where the input matches the LocationName.
Assuming the target page is loaded, I can work with it. Methods such as getElementByID() work perfectly. If the browser window is closed and reopened, and the code is run again, the results are very inconsistent. The getIE function seems to work, but when trying to use methods like document.getElementByID() a NullReferenceException is thrown.
Does anyone know if there is anything I am missing that I need to include to get the document property to update?
EDIT: I have looked over the NullReferenceException article. It hasn't helped me unfortunately. In case I was unclear in my wording, I would like to reiterate that the same bit of code yields a different result when executed the 2nd time under the same conditions (same webpage open in Internet Explorer).
On the second execution IE.locationName is retrievable but IE.Document.title is not. The problem is definitely with the Document property as far as I can tell. I am truly stumped.
Many thanks
Public Function getIE(targetTitle As String) As SHDocVw.InternetExplorer
' Create the shell application and Collection of open windows
Dim shellObj As Object = CreateObject("Shell.Application")
Dim shellWindows As SHDocVw.ShellWindows = shellObj.Windows()
getIE = Nothing
' Scan through the Collection
For I = (shellObj.Windows.Count - 1) To 0 Step -1
' If found, assign this to the function output and exit early
If InStr(shellWindows(I).LocationName, targetTitle) Then
getIE = shellWindows(I)
Debug.Print("Found: " & shellWindows(I).LocationName)
Exit For
End If
Next I
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim IE As SHDocVw.InternetExplorer
IE = getIE("my site title")
If IE Is Nothing Then
Debug.Print("Site not open")
Exit Sub
End If
' The code always gets this far, and despite the page being found, starts throwing exceptions from here on if the window has been closed and reopened whilst my application has stayed running.
' Sample form data insertion code
IE.Document.getElementById("textbox1").value = "my value"
' Click the submit button
IE.Document.getElementById("submit").click()
' Wait for page to load
While IE.Busy
End While
IE.Document.getElementById("textbox2").value = "my 2nd value"
' done
IE = Nothing
End sub

how to refer back to created browser instance

I create a browser like so, and manually navigate to the web page I need to be. I intend to automatically pull certain elements once I get to the page I need to be on via a seperate macro
Sub Test()
Set CAS = New SHDocVw.InternetExplorer ' create a browser
CAS.Visible = True ' make it visible
CAS.navigate "http://intraneturl"
Do Until CAS.readyState = 4
DoEvents
Loop
This works fine, then I do
Public Sub Gather
Set HTMLDoc2 = CAS.document.frames("top").document
Call Timer1
With HTMLDoc2
.getElementById("tab4").FirstChild.Click
End With
Call Timer2
Dim fir, las, add1, add2, cit, stat, zi As String
Dim First As Variant
Dim Last As Variant
Dim addr1 As Variant
Dim addr2 As Variant
Dim city As Variant
Dim Thisstate As Variant
Dim Zip As Variant
Call Timer2
Set HTMLDoc = CAS.document.frames("MainFrame").document
Call Timer2
With HTMLDoc
First = .getElementsByName("IndFirst")
Last = .getElementsByName("IndLast")
addr1 = .getElementsByName("txtAdd_Line1")
addr2 = .getElementsByName("txtAdd_Line2")
city = .getElementsByName("txtAdd_City")
Thisstate = .getElementsByName("cmb_Add_State")
Zip = .getElementsByName("txtAdd_Zip")
End With
fir = First.Value
las = Last.Value
add1 = addr1.Value
add2 = addr2.Value
cit = city.Value
stat = Thisstate.Value
zi = Zip.Value
'navigate back to start page
With HTMLDoc2
.getElementById("tab3").FirstChild.Click
End With
End Sub
This works the first time, but after the first time, I get "Object variable or with block variable not set" when trying to run the gather() sub again, on a different web page that contains similar information. Any Ideas as to what im doing wrong?
"The error "object variable or with block variable not set" occurs on: Set HTMLDoc2 = CAS.document.frames("top").document the second time i try running Gather()."
This is probably one of three things:
CAS is no longer an object
To check this, set a breakpoint on the line, press ctr+G in the VBA Editor and type ?CAS Is Nothing in the Immediate Window; the result should be False; if it is True CAS is no longer an object
Like Daniel Dusek suggested, make sure CAS.document.frames("top") is an actual element on the page.
To check this, open the webpage you are trying to script, press F12 in Internet Explorer, click on the arrow in the toolbar and click on the "top" frame element in the webpage, switch back to the Developer Tool and look at the line highlighted. Make sure the frame element is named "top".
The HTML hasn't fully loaded when you try to reference the frame element. Set a longer delay or a loop.
i.e. (untested):
Do Until HtmlDoc2 Is Nothing = false
Set HTMLDoc2 = CAS.document.frames("top").document
Loop
Maybe the more important question is why manually navigate to another page? Can't you automate that part of your process too?