Question: I have a DHTML form that is dynamically generated based on a user's selection from a list box. It generates a table line for product information which includes text fields and an input (order quantity) text box for each item. The number of items varies widely based on the user's selection. How can I (or better yet, can I) access the .value property of these generated input fields in Visual Basic?
The exact answer to your conundrum (other than, yes, it is certainly possible to do this) depends upon how you integrate Internet Explorer within Visual Basic. For the sake of discussion, I'm assuming that you have created a WebBrowser object within a Visual Basic form, and called this component WebBrowser1. One thing that's really useful to do when manipulating HTML documents from within VB is to create a variable of type HTMLDocument. However, in order to do this, you need to load in the HTML type library (MSHTML.DLL), which contains the type declarations for all of the objects used within an HTML page. Open References from the Project menu, and select Microsoft HTML Object Library (note that the exact wording may be different on your systemthe important thing is that you choose the MSHTML library).
Once you have created the reference, you declare the variable. If you want to catch document events from within your VB Application, you may also want to include With Events in your declaration.
Public WithEvents Doc as HTMLDocument
Note that you are not actually creating a new instance of the Document hereyou just need an intelligent container for the object that already exists. The document itself can be any HTML page. For example, I've created a small HTML file that puts together a form (in this case, a Holy Grail BridgeKeeper's form) used to gain basic information for all would-be grail seekers:
Monty Python's E-Commerce Form
To start the download of the document, you need to call the navigate method on the WebBrowser control:
However, this particular document will only exist once the Web page itself has been loaded into the browser pane, making it inadvisable to assign it during initialization. Instead, you will probably want to catch the document when the download is complete, which can be captured in the DocumentComplete event, as follows:
Private Sub WebBrowser1_DocumentComplete(ByVal pDisp As Object, URL As Variant)
Set Doc = WebBrowser1.Document
Once the document has been initialized, then accessing or modifying the contents of a form within that document is the same as for accessing the form within DHTML. To illustrate, you can explicitly set the color to "blue" in the code from VB:
or retrieve that same information in a similar fashion:
dim myColor as string
You can also reference other properties of a given field input element. For example, if you wish to disable a given field, you can do so by setting the disabled property to true:
The only two input fields that can trip you up are checkboxes and radio buttons. In order to put a checkmark into a checkbox, you need to set the "checked" property to true (or false to remove the check), for example, Doc.bridgeKeeperData.isKnight.checked=true. Note that values act a little strangely with checkboxesit will return whatever is placed into the .value field, not the state of the checkmark.
Radio buttons work in a similar fashion (internally they act exactly in the same way as checkboxes). To make a radio button "on", set the checked attribute to true. The one difference between checkboxes and radio buttons is that if you define two or more radio buttons with the same name and id, then turning one radio button on in that group will turn all others off. However, this means that in order to determine the currently selected radio button, you need to query all of the radio buttons until you find it.
One characteristic of the Internet Explorer Scripting engine comes when two or more elements are given the same name. These items become a collection implicitlytrying to reference the objects using just their names will result in errors. What you need to do instead is refer to each element via an index. For example, the "transformed" group above is written as:
Which of these statements is true for you?
I was a duck.
I was a newt.
In order to reference the first element, you would use Doc.bridgeKeeperData.transformed(0), while the second would be Doc.bridgeKeeperData.transformed(1). To get a count of the number of items in this group, you'd need the length method (Doc.bridgeKeeperData.transformed.length). The one advantage to a collection is that you can enumerate through it directly:
dim transformedItem as Variant
for each transformedItem in Doc.bridgeKeeperData.transformed
if transformedItem.checked then