I'm using Excel VBA to automate a web page. The "Select" boxes and "Input" boxes were created by a jQuery platform called "Select2."
When the user clicks on a "Select box" (which appears as an input box) a dropdown box pops up asking the user to type in two characters. I've discovered that you can add a valid data item into this box with this command by inserting the select box ID.
myDoc.parentWindow.execScript "$('#s2id_broomCloset').val('Swiffer - Model 2010').trigger('change')"
Most of the input boxes are like any other where you can change them with
myDoc.GetElementByID("broomCloset").value = "Swiffer"
However, there is one input box built with Select2 which involves a validation drop down list asking the user to type the first two characters and it lists employees whose last names start with those two characters. Then the user is supposed to select the employee from the list.
This input box is tied to an "
I was able to use the advice of
I have tried everything I can think of to enter a valid response into this input box. Here are a couple of failed attempts:
myDoc.GetElementByID("s2id_beanCounter").Children(0).Clicik
myDoc.parentWindow.execScript "$('#s2id_beanCounter').trigger('onclick')"
It would be a tremendous help if you could lead me to an answer as how can I put a valid input into this box or at least how to click the box to make the drop down list appear.
Edited 06-20-2017
Using advice from @dee I was able to get the last name into the searchable input elelment and it drops down all of the people with that last name. As you can see from the html code below the first name in the drop down box is highlighted.
When I hover the mouse over any of the names, the name under the mouse becomes the highlighted name. And of course a left click of the mouse enters that name into the input box.
How can I automate the process of highlighting the name we need form the UL list and click it to put into the input box as a valid value?
The one caveat about this search is that it only searches the last name.
<div class="select2-drop select2-display-none bigdrop select2-with-searchbox select2-drop-active" id="select2-drop" style="left: 1049.13px; top: 227.83px; width: 238px; display: block;">
<div class="select2-search">
<input class="select2-input" spellcheck="false" type="text" autocomplete="off" autocapitalize="off" autocorrect="off">
</div>
<ul class="select2-results">
<li class="select2-results-dept-0 select2-result select2-result-selectable select2-highlighted">
<div class="select2-result-label">
<div>JOSEPH MENGELA (ARGENTINA)</div></div>
</li>
<li class="select2-results-dept-0 select2-result select2-result-selectable">
<div class="select2-result-label">
<div>TOMMY MENGELA (ITALY)</div>
</div>
</li>
<li class="select2-results-dept-0 select2-result select2-result-selectable">
<div class="select2-result-label">
<div>SUSAN H MENGELA (POLAND)</div>
</div>
</li>
</ul>
</div>
Here is the code I used to get the dropdown box to show all the names of people in our system with that last name.
Set myElement = myDoc.getElementById("s2id_IDofInputBoxHere").Children(0)
SendMouseDownEvent myDoc, myElement
Set myElement = myDoc.getElementById("select2-drop").Children(0).Children(0)
myDoc.getElementById("select2-drop").Children(0).Children(0).Value = "mengela"
' Send input event to trigger searching of text 'BR"
Dim kev
Set kev = myDoc.createEvent("KeyboardEvent")
kev.initEvent "input", True, False
myElement.dispatchEvent kev
For Version 4.0.3 of select 2
Solution 1
In select2.js
there is function:
this.$selection.on('mousedown', function (evt) {
// Only respond to left clicks
if (evt.which !== 1) {
return;
}
self.trigger('toggle', {
originalEvent: evt
});
});
This function handles the mousedown
event of the selection
so first I have tried to send mousedown
to the selection
so we get the selection
open and then to put the text into search box. Finally it is necessary to send input event to trigger searching.
Sub Select2Demo()
Dim ie As SHDocVw.InternetExplorer
Dim doc As MSHTML.HTMLDocument
Dim url As String
url = "file:///C:/Temp/StackOverflow/html/Select2VbaDemo.html"
Set ie = New SHDocVw.InternetExplorer
ie.Visible = True
ie.navigate url
While ie.Busy Or ie.readyState <> READYSTATE_COMPLETE
DoEvents
Wend
Set doc = ie.document
' Open drop down
Dim sp As HTMLSpanElement
Set sp = doc.querySelector("span[class^=select2-selection]")
SendMouseDownEvent doc, sp
' Put value into search box
Dim inp
Set inp = doc.querySelector("input[class=select2-search__field]")
inp.Value = "BR"
' Send input event to trigger searching of text 'BR"
Dim kev
Set kev = doc.createEvent("KeyboardEvent")
kev.initEvent "input", True, False
inp.dispatchEvent kev
'ie.Quit
End Sub
Private Sub SendMouseDownEvent(doc As MSHTML.HTMLDocument, target As IEventTarget)
Dim mev As Object
Dim eventType As String
Dim canBubble As Boolean
Dim cancelable As Boolean
Dim viewArg As IHTMLWindow2
Dim detailArg As Long
Dim screenXArg As Long
Dim screenYArg As Long
Dim clientXArg As Long
Dim clientYArg As Long
Dim ctrlKeyArg As Boolean
Dim altKeyArg As Boolean
Dim shiftKeyArg As Boolean
Dim metaKeyArg As Boolean
Dim buttonArg As Object ' Unsupported Variant-Type
Dim relatedTargetArg As IEventTarget
Set mev = doc.createEvent("MouseEvent")
eventType = "mousedown"
canBubble = True
cancelable = False
Set viewArg = doc.parentWindow
Set relatedTargetArg = target
mev.initMouseEvent eventType, canBubble, cancelable, viewArg, _
detailArg, screenXArg, screenYArg, clientXArg, clientYArg, _
ctrlKeyArg, altKeyArg, shiftKeyArg, metaKeyArg, buttonArg, _
relatedTargetArg
target.dispatchEvent mev
End Sub
Solution 2
Other idea would be to put focus
to the selection
and simply send {ENTER}
which is the same as when the user opens the selection
.
We need the selection
to be opened because then the input
will be added to the DOM (otherwise it is not there). The following code worked for me.
Notice the SetFocusIE
which ensures that the IE-Window
is active one and so the SendKeys
will target the right window. HTH.
Option Explicit
' Add reference to Microsoft Internet Controls (SHDocVw)
' Add reference to Microsoft HTML Object Library
Private Declare Function SetFocusIE Lib "user32" Alias "SetFocus" _
(ByVal hwnd As Long) As Long
Sub Select2Demo2()
Dim ie As SHDocVw.InternetExplorer
Dim doc As MSHTML.HTMLDocument
Dim url As String
url = "file:///C:/Temp/StackOverflow/html/Select2VbaDemo.html"
Set ie = New SHDocVw.InternetExplorer
ie.Visible = True
ie.navigate url
While ie.Busy Or ie.readyState <> READYSTATE_COMPLETE
DoEvents
Wend
Set doc = ie.document
Dim sp As HTMLSpanElement
Set sp = doc.querySelector("span[class^=select2-selection]")
sp.Click ' Selection gets focus
SetFocusIE ie.hwnd ' IE gets active window
SendKeys "~", True ' Sends ENTER: Selection opens
' put value to search box then
Dim inp
Set inp = doc.querySelector("input[class=select2-search__field]")
inp.Value = "BR"
ie.Quit
End Sub
Sample page used
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!-- saved from url=(0016)http://localhost -->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet" />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.js"></script>
<title>Untitled 1</title>
</head>
<body>
<script type="text/javascript">
$(document).ready(function() {
$("#s2id_beanCounter").select2();
});
</script>
<div class="s2-example" >
<label class="control-label" for="s2id_beanCounter">
Enter Employee Name
<select class="js-example-basic-single js-states form-control" id="s2id_beanCounter" style="width:100%">
<option value="JD">John Doe</option>
<option value="BL">Bruce Lee</option>
</select>
</label>
</div>
</body>
</html>
Result im IE
EDIT: For Version 3.4.1 of select2
In version 3.4.1 it looks different. There is this function resposible for selecting the highlighted element:
this.dropdown.on("mouseup", resultsSelector, this.bind(function (e) {
if ($(e.target).closest(".select2-result-selectable").length > 0) {
this.highlightUnderEvent(e);
this.selectHighlighted(e);
}
}));
So the following code can be used to highlight and select one of the filtered elements. HTH
Option Explicit
' Add reference to Microsoft Internet Controls (SHDocVw)
' Add reference to Microsoft HTML Object Library
Sub Select2DemoVersion341()
Dim ie As SHDocVw.InternetExplorer
Dim doc As MSHTML.HTMLDocument
Dim url As String
url = "file:///C:/Temp/StackOverflow/html/select2demo/Select2VbaDemo.html"
Set ie = New SHDocVw.InternetExplorer
ie.Visible = True
ie.navigate url
While ie.Busy Or ie.readyState <> READYSTATE_COMPLETE
DoEvents
Wend
Set doc = ie.document
' Get reference to target serach input box before select2 starts to mess up with the DOM when the select opens
Dim inp As HTMLInputElement
Set inp = doc.querySelector("div[class^=select2-container] input[class=select2-input]")
' Open drop down
Dim select2Choice As HTMLAnchorElement
Set select2Choice = doc.querySelector("a[class^=select2-choice]")
SendMouseEvent doc, select2Choice, "mousedown"
' Put value into search box
inp.Value = "mengela"
' Send input event to trigger searching of text 'mengela"
Dim kev
Set kev = doc.createEvent("KeyboardEvent")
kev.initEvent "input", True, False
inp.dispatchEvent kev
' Get the search results
Dim selectResultUl As HTMLUListElement
Set selectResultUl = doc.querySelector("ul[class=select2-results]")
If selectResultUl.Children.Length = 1 Then
' Verify 'No results found' posibility
If selectResultUl.Children(0).className = "select2-no-results" Then
MsgBox "No results"
ie.Quit
Exit Sub
End If
End If
' Deselect currently selected item by removing select2-highlighted class
Dim selectedResultsLis As IHTMLElementCollection
Dim selectResultsLi As HTMLLIElement
Set selectedResultsLis = selectResultUl.getElementsByTagName("li")
For Each selectResultsLi In selectedResultsLis
If selectResultsLi.className Like "*select2-highlighted*" Then
selectResultsLi.className = VBA.Strings.Replace(selectResultsLi.className, "select2-highlighted", "")
Exit For
End If
Next selectResultsLi
' Select another li-element, e.g. last one by adding select2-highlighted class
Dim newSelectionLi As HTMLLIElement
Set newSelectionLi = selectedResultsLis(selectedResultsLis.Length - 1)
newSelectionLi.className = newSelectionLi.className & " select2-highlighted"
' Send mouseup to result label to select the highligted element
Dim resultLabel As HTMLDivElement
Set resultLabel = newSelectionLi.getElementsByClassName("select2-result-label")(0)
SendMouseEvent doc, resultLabel, "mouseup"
'ie.Quit
End Sub
Private Sub SendMouseEvent(doc As MSHTML.HTMLDocument, target As IEventTarget, eventTypeVal)
Dim mev As Object
Dim eventType As String
Dim canBubble As Boolean
Dim cancelable As Boolean
Dim viewArg As IHTMLWindow2
Dim detailArg As Long
Dim screenXArg As Long
Dim screenYArg As Long
Dim clientXArg As Long
Dim clientYArg As Long
Dim ctrlKeyArg As Boolean
Dim altKeyArg As Boolean
Dim shiftKeyArg As Boolean
Dim metaKeyArg As Boolean
Dim buttonArg As Object ' Unsupported Variant-Type
Dim relatedTargetArg As IEventTarget
Set mev = doc.createEvent("MouseEvent")
eventType = eventTypeVal
canBubble = True
cancelable = False
Set viewArg = doc.parentWindow
Set relatedTargetArg = target
mev.initMouseEvent eventType, canBubble, cancelable, viewArg, _
detailArg, screenXArg, screenYArg, clientXArg, clientYArg, _
ctrlKeyArg, altKeyArg, shiftKeyArg, metaKeyArg, buttonArg, _
relatedTargetArg
target.dispatchEvent mev
End Sub
Demo page with select2.js/css of version 3.4.1 can be downloaded from my dropbox as zip file.