Can anyone figure out what I am doing wrong?
When I try to submit data to an online MS Form the submission fails upon clicking the submit button because the data in the input text box disappears.
The code I am using:
Sub Hello()
Dim objIE As Object
Dim URL As String
Dim doc As HTMLDocument
Dim oServ As Object
Dim cProc As Variant
Dim oProc As Object
URL = "https://forms.office.com/Pages/ResponsePage.aspx?id=1tUOxOPgeU2DDHmR8zp8jnPOq1Zxq2ZMgF9BFdtxEI9UNTJUSlpaNVU3S0pYRDI0MzE3UkZZQzdZNi4u"
Set objIE = CreateObject("InternetExplorer.Application")
objIE.Visible = True
objIE.navigate URL
Do While objIE.Busy = True Or objIE.readyState <> 4: DoEvents: Loop
Set doc = objIE.document
Set oServ = GetObject("winmgmts:")
Set cProc = oServ.ExecQuery("Select * from Win32_Process")
Dim input_text As String
input_text = "Hello!"
doc.getElementsByTagName("input")(0).Value = input_text
doc.getElementsByTagName("input")(0).setAttribute("value") = input_text
'Let us wait 5 secconds to see if the text was entered into the textbox
Application.Wait (Now() + TimeValue("00:00:05"))
doc.getElementsByTagName("button")(2).Click
'Let us wait 10 secconds to see the results before terminating IE
Application.Wait (Now() + TimeValue("00:00:10"))
Set objIE = Nothing
For Each oProc In cProc
If oProc.Name = "iexplore.exe" Then
'MsgBox "KILL" ' used to display a message for testing pur
oProc.Terminate 'kill exe
End If
Next
End Sub
I wouldn't recommend using IE for automating VBA form submission.
Here's my experience: You spend a lot of time trying to solve this kind of 'what happened the click was supposed to work' errors. Or why did the page not load all the way errors? or how do I wait for the page to load and click what it needs.
TBS: having spent too much time trying to make this sort of thing work, and oftentimes getting a good result. I'd suggest using your DevTools (f12 in IE) while on the page. First click the button normally and see what happens. Next Click the button using JavaScript run in the console section. It'll be something very similar to your click syntax. Take note of what element is actually being clicked by using the inspector in dev tools and what script is running with the event.
IE does have ways to run the exact javascript on the page, you might need to replicate the form click event and javascript using this syntax:
Call IE.document.parentWindow.execScript("document.all.myElement.focus();buttonMovimenti();", "JavaScript")
I've had a lot better success using execScript to trigger OnClick(); events on the page / parentwindow. Just keep in mind iFrames can be a pain to figure out which document you're selecting so be sure to inspect the source to see if there's multiple html documents on the test page.
Alternatively you could attempt to use HTTP post / get methods to submit the form with VBA's MSXML2.XMLHTTP request object, and replicating the headers / form submission that you see in DevTools under Network tab when you click the button. This would take the timing of the page loads out of the equation, and make a more streamlined submission.
EDIT EXAMPLES:
Here's the sub I used to use for this purpose of executing scripts.
Test the script in the console of IE first. In your comment you're referencing the entire minimized JS library. What you want to do is find the function from the window that does the form submission.
Public Sub RunScriptZ(IeObjectDoc As Object, sJavaScript As String)
'run any java script on a page
Dim CurrentWindow As HTMLWindowProxy
Set CurrentWindow = IeObjectDoc.parentWindow
Call CurrentWindow.execScript(sJavaScript)
End Sub
Usually a form is submitted with a basic function like 'submitForm()'. So open DevTools with the page open, then go to Console, and type Document.submitForm(); in the console, and see what happens. Hopefully the form submits with this. Then you could something like:
Call RunScriptZ(objie.Document, "submitForm()")
If this doesn't work, sometimes a site needs you to click / hover to submit the form. You can try these variations alone or combined to see if it replicates on the web page.
Idea 1, Fire Event Method
Dim ieo As New SHDocVw.InternetExplorerMedium
Set ieoDoc = ieo.Document
ieoDoc.getElementById("buttonId").FireEvent ("Onclick")
Idea 2: Basic Exec Script
Dim ieo As New SHDocVw.InternetExplorerMedium
Set ieoDoc = ieo.Document
Dim CurrentWindow As HTMLWindowProxy
Set CurrentWindow = ieoDoc.parentWindow
Call CurrentWindow.execScript("submitForm()") ''or whatever the JS function
'name is that runs in console and triggers the event
Idea 3: test the button to see if it's clickable. sometimes web forms filled out with programming, dont register as filled in, especially if you're just assigning values. I know a lot of forms i dealt with used to require a click event on the input in order to register that a change had occurred, so check the submit button to make sure it's even clickable with this code:
Public Function TestLinkClick(linkelement As HTMLButtonElement, ForceClick
As Boolean) As Boolean
If ForceClick = True Then GoTo clickawaylabel
If IsNull(linkelement.OnClick) = False Then
clickawaylabel:
TestLinkClick = True
Debug.Print "the link is clickable"
Else 'the linkelement is not clickable
TestLinkClick = False
Debug.Print "the link is not clickable"
End If
End Function
Idea 4: Fill in a box
Public Sub FillInBox(TextValue As String, BoxName As String, IECVdoc As Object)
'fill in a box on a html page
Dim tries As Integer
tries = 0
On Error GoTo errorhandler
If tries >= 3 Then GoTo HappyEnd
startAgain:
With IECVdoc
.getElementById(BoxName).Value = TextValue
.getElementById(BoxName).FireEvent ("onchange")
End With
GoTo HappyEnd
errorhandler:
''Call a wait timer I'm using a wait sub: WaitForLoadSETx(IECVdoc, 2, 3)
tries = tries + 1
GoTo startAgain
HappyEnd:
End Sub
Idea 5: Wait for Load
Public Sub WaitForLoadSETx(ieo As Object, Maxtime As Integer, Maxtime2 As Integer)
' Wait for page to load before continuing
Dim sngTime As Single
'Const Maxtime As Integer = 5
'Const Maxtime2 As Integer = 10
sngTime = VBA.Timer ' a snapshot of the timer at the time the subroutine starts
' Wait until the webpage is doing something ... 'READYSTATE_COMPLETE <<< replaced 9/16/13 to click quicker with interactive
Do Until ieo.ReadyState <> READYSTATE_COMPLETE
DoEvents
If VBA.Timer > sngTime + Maxtime And VBA.Left(ieo.statusText, 4) = "Done" Then Exit Sub
If VBA.Timer > sngTime + Maxtime2 And ieo.ReadyState = 4 Or ieo.ReadyState = "complete" Then Exit Sub 'added this to make a real max time 1-12-15 'aded OR complete 1/14/15
' If VBA.Left(IEo.StatusText, 4) = "" Then GoTo outloop
Debug.Print "ONE LOOP Page Loading [" & VBA.Timer & "]/[" & sngTime + Maxtime & "]" & " [" & ieo.ReadyState & "]" & " [" & ieo.statusText & "]" '<<<< added 1/02/14
Loop
'outloop:
' ... and then wait for it to finish 'READYSTATE_INTERACTIVE <<< replaced 9/18/13 to click quicker with interactive
Do Until ieo.ReadyState = READYSTATE_COMPLETE
DoEvents
On Error GoTo 0
' If VBA.Timer > sngTime + Maxtime And VBA.Left(ieo.statusText, 4) = "Done" Then Exit Sub 'removed 1/14/15 because or error 438 not found on .statusText
If VBA.Timer > sngTime + Maxtime2 And ieo.ReadyState = 4 Or ieo.ReadyState = "complete" Then Exit Sub 'added this to make a real max time 1-12-15 'aded OR complete 1/14/15
Debug.Print "TWO LOOP Page Loading [" & VBA.Timer & "]/[" & sngTime + Maxtime & "]" & " [" & ieo.ReadyState & "]" '& " [" & 'ieo.statusText & "]" '<<<< added 1/02/14
Loop
0:
End Sub
Best of luck!