Hey, Scripting Guy! How can I dynamically add controls to an HTA?
— TR
Hey, TR. Dum-de-dum-dum. Dum-de-dum-de – oh, wait : you were talking to us, weren’t you? Sorry; we saw the word “dynamically” and figured this question must have been addressed to someone else. When people hear the words Scripting Guys they think of all sorts of things, but “dynamic” usually isn’t one of them.
And no, TechNet won’t allow us to print the words people do associate with the Scripting Guys.
OK, now that we know that we’re supposed to answer the question we better get down to business. First of all, we should note that the real answer to your question is, “It depends.” After all, the exact method for dynamically adding controls to an HTA depends on what type of control you want to add and what you want those controls to do. (For example, do you want a script to run when the control is clicked?) Therefore, we’re going to show you a somewhat-generic method for adding dynamic controls to an HTA and for determining whether or not that control has been clicked. That probably won’t solve your actual problem, but, with any luck, it should be enough information to get you started.
We should also note that if you have no idea what we’re talking about, HTA is short for HTML Application. Among other things, HTAs utilize the Internet Explorer object model as a way to provide a graphical user interface for a script; that means you can create a script that looks like a real application, complete with radio buttons and drop-down lists and what-have-you. For more information, check out our HTA Developers Center.
And now, back to our regularly-scheduled program.
Our sample HTA is pretty simple. It consists of a window with a single button, labeled Add Button. Each time you click Add Button, a new button is added to the screen; if you click any of those new buttons, a subroutine will report back the ID of the button that was clicked. When you first start up the HTA it looks something like this:
No, it’s not very fancy at the moment. But don’t worry: we’re not done yet.
As you can see, the code for our HTA isn’t much fancier:
<script Language=”VBScript”>intButtonCount = 1
Sub AddButton strHTML = DataArea.InnerHTML strHTML = strHTML & “<input id=” & intButtonCount & ” type=” & Chr(34) & “button” & Chr(34) & _ ” value= ” & Chr(34) & “Button ” & intButtonCount & Chr(34) & ” onClick=” & Chr(34) & _ “NewButtonSubroutine” & Chr(34) & “>” DataArea.InnerHTML = strHTML intButtonCount = intButtonCount + 1 End Sub
Sub NewButtonSubroutine Set objButton = window.event.srcelement strID = objButton.id Msgbox “You clicked Button ID ” & strID End Sub
</script>
<body> <input id=addbutton type=”button” value=”Add Button” onClick=”AddButton”> <span id=DataArea></span> </body>
So how exactly does this all work? Let’s break the HTA down into subsections and see if we can answer that question. For starters, take a look at the <body> tag. As you can see, there isn’t much there; all we have is the HTML code for adding a button, along with this tag:
<span id=DataArea></span>
That’s not much, but it’s important. The <span> tag sets aside a named area of our HTA; as you’re about to see, once we have a named area we can then dynamically add items to that area. That’s step 1 in the process: in order to add new controls to an HTA you need a designated area within the HTA where controls can be added. Make sense? Good.
Oh: note that we’ve given this spot the ID DataArea. We’ll need to use that ID any time we refer to this portion of the HTA.
Next, let’s take a look at the AddButton subroutine; this is the subroutine that gets called each time we click Add Button. As you might expect, this is also the subroutine that dynamically adds controls each time the button is clicked (and thus each time the subroutine is called).
The first thing we do inside this subroutine is assign the value of DataArea’s InnerHTML property to a variable named strHTML:
strHTML = DataArea.InnerHTML
The InnerHTML property represents all the HTML coding contained within the DataArea span. For all intents and purposes, that means information about all the controls, text, images, etc. within that span is now stashed away in the variable strHTML.
That brings us to this nightmarish line of code:
strHTML = strHTML & “<input id=” & intButtonCount & ” type=” & Chr(34) & “button” & Chr(34) & _ ” value= ” & Chr(34) & “Button ” & intButtonCount & Chr(34) & ” onClick=” & Chr(34) & _ “NewButtonSubroutine” & Chr(34) & “>”
Yes, we know what it looks like. But let’s explain what’s going on here and see if that helps any. All we’re doing is assigning a new value to strHTML: this time it’s getting the existing value of strHTML (all the current controls, text, images, etc.) plus HTML code for adding a brand-new button. The portion of the code for adding a brand-new button looks like this:
“<input id=” & intButtonCount & ” type=” & Chr(34) & “button” & Chr(34) & _ ” value= ” & Chr(34) & “Button ” & intButtonCount & Chr(34) & ” onClick=” & Chr(34) & _ “NewButtonSubroutine” & Chr(34) & “>”
Believe it or not, that gobbledygook resolves to the code required to add a new button to the HTA. As you probably know, the HTA tag for a button looks like this:
<input id=1 type=”button” value=”Button 1″ onClick=”NewButtonSubroutine”>
Those elements – and only those elements – are present in our crazy line of code. However, we did have to make a few modifications:
• |
The HTA tag for a button includes a number of double quotes (e.g., type=”button”). In VBScript, all string values must be enclosed in double quotes, and putting double quotes within double quotes can be tricky. Therefore, we simply replaced the double quotes with their ASCII equivalent: Chr(34). See all the Chr(34) notations in our code? Those are just double quotes. If you see “type=” & Chr(34) & “button” you can simply read that as type=”button” (which is exactly how the script reads it). |
• |
If we want to be able to distinguish between buttons then each button needs to have a unique ID. To do that we defined a global variable named intButtonCount at the beginning of our <script> tag, and assigned intButtonCount the value 1. Each time we add a new button we then increment intButtonCount by 1. What does that mean? That means our first new button will have an ID of 1, our second new button will have an ID of 2, etc. That’s why the button ID is assigned the value of intButtonCount. Like so: id=” & intButtonCount. |
• |
We also want each button to have unique label. Therefore, we set the value (label) of each button to the word Button plus the button ID. That’s what happens here: ” value= ” & Chr(34) & “Button ” & intButtonCount & Chr(34). |
Got all that? If not, don’t fret. Instead, just slowly walk through the line of code piece-by-piece, substituting the current value of intButtonCount as needed, and sticking in double quote marks any time you see Chr(34). Sooner or later it should start making sense. If it doesn’t substitute in this line of code, which adds a button without an ID, a label, or an onClick event:
strHTML = strHTML & “<input type=” & Chr(34) & “button” & Chr(34) & “>”
That button won’t look like much and it won’t actually do anything, but once you understand how we created that very simple button you can start adding additional parameters such as value, id, and onClick.
After we’ve assigned a new value to strHTML we then set DataArea’s InnerHTML property to that new value:
DataArea.InnerHTML = strHTML
The net effect? We’ll have a new, dynamically-created button within our HTA. Click Add Button a few more times and you’ll have all sorts of new buttons on the HTA:
Etc.
Now, what about being able to distinguish between buttons 1, 2, and 3? Well, each button we add is configured to call the same subroutine (NewButtonSubroutine) any time someone clicks the button. That subroutine looks like this:
Sub NewButtonSubroutine Set objButton = window.event.srcelement strID = objButton.id Msgbox “You clicked Button ID ” & strID End Sub
Inside the subroutine we use the first line of code to create an object reference to the window.event.srcelement object. This object represents the item that fired the event triggering the subroutine. In other words, if we click button 2, then the window.event.srcelement is equal to button 2.
As soon as we have an object reference we can assign the button ID to a variable named strID; after that we can use the Msgbox function to echo back the ID of the button that was clicked:
Not very fancy, but you get the idea.
As we noted, this probably doesn’t fully answer your question, TR, but we hope it gets you headed down the right path. If you need more specific information, just let us know.
And remember: if you want to make sure we see your email, don’t use words like dynamic. Instead, use a subject line like Hey, You Lousy, Good-for-Nothing Bums. You can bet that email will get to us, even if it’s not specifically addressed to us!
0 comments