How do I traverse a collection in classic ASP? - asp-classic

I want to be able to do:
For Each thing In things
End For
CLASSIC ASP - NOT .NET!

Something like this?
dim cars(2),x
cars(0)="Volvo"
cars(1)="Saab"
cars(2)="BMW"
For Each x in cars
response.write(x & "<br />")
Next
See www.w3schools.com.
If you want to associate keys and values use a dictionary object instead:
Dim objDictionary
Set objDictionary = CreateObject("Scripting.Dictionary")
objDictionary.Add "Name", "Scott"
objDictionary.Add "Age", "20"
if objDictionary.Exists("Name") then
' Do something
else
' Do something else
end if

Whatever your [things] are need to be written outside of VBScript.
In VB6, you can write a Custom Collection class, then you'll need to compile to an ActiveX DLL and register it on your webserver to access it.

The closest you are going to get is using a Dictionary (as mentioned by Pacifika)
Dim objDictionary
Set objDictionary = CreateObject("Scripting.Dictionary")
objDictionary.CompareMode = vbTextCompare 'makes the keys case insensitive'
objDictionary.Add "Name", "Scott"
objDictionary.Add "Age", "20"
But I loop through my dictionaries like a collection
For Each Entry In objDictionary
Response.write objDictionary(Entry) & "<br />"
Next
You can loop through the entire dictionary this way writing out the values which would look like this:
Scott
20
You can also do this
For Each Entry In objDictionary
Response.write Entry & ": " & objDictionary(Entry) & "<br />"
Next
Which would produce
Name: Scott
Age: 20

One approach I've used before is to use a property of the collection that returns an array, which can be iterated over.
Class MyCollection
Public Property Get Items
Items = ReturnItemsAsAnArray()
End Property
...
End Class
Iterate like:
Set things = New MyCollection
For Each thing in things.Items
...
Next

As Brett said, its better to use a vb component to create collections. Dictionary objects are not very commonly used in ASP unless for specific need based applications.

Be VERY carefully on using VB Script Dictionary Object!
Just discover this "autovivication" thing, native on this object: http://en.wikipedia.org/wiki/Autovivification
So, when you need to compare values, NEVER use a boolen comparison like:
If objDic.Item("varName") <> "" Then...
This will automatically add the key "varName" to the dictionary (if it doesn't exist, with an empty value) , in order to carry on evaluating the boolean expression.
If needed, use instead If objDic.Exists("varName").
Just spend a few days knocking walls, with this Microsoft "feature"...
vbscript-dictionary-object-creating-a-key-which-never-existed-but-present-in-another-object

Related

Looping through different dropdown lists

I have multiple controls on a page that are all similar and are all numbered. For instance, I have multiple month controls like this:
Replacement1MonthDropDownList
Replacement2MonthDropDownList
Replacement3MonthDropDownList
Etc.
But when I have common code that works on all of the controls, I need a big Select Case statement like this:
Select Case Count
Case 1
Call Me.FillReplacements(rf.Replacements(0), Me.Replacement1MonthDropDownList, Me.Replacement1AmountTextBox, Me.ReplacementSaveButton)
Case 2
Call Me.FillReplacements(rf.Replacements(0), Me.Replacement1MonthDropDownList, Me.Replacement1AmountTextBox, Me.ReplacementSaveButton)
Call Me.FillReplacements(rf.Replacements(1), Me.Replacement2MonthDropDownList, Me.Replacement2AmountTextBox, Me.SplitButton1)
Is it possible to loop through the controls and get them by name--justreplacing the numbers in the name with the current Count in my loop?
Sorry, I'm very new to Visual Basic! :S
Yes, you can. The Page class (Me, in this case) has a FindControl method which allows you to find a control by name. So, for instance, you could do something like this:
Dim monthControl As Control = Me.FindControl("Replacement" & Count.ToString() & "MonthDropDownList")
Dim splitControl As Control = Me.FindControl("SplitButton" & Count.ToString())
If you need to cast them as a more specific type, you could use DirectCast. For instance:
Dim monthControl As DropDownList = DirectCast(Me.FindControl("Replacement" & Count.ToString() & "MonthDropDownList"), DropDownList)
Alternatively, and perhaps preferably, you could make an array of controls so you could access them by index. For instance, if you had an array like this defined:
Private monthControls() As DropDownList = {Replacement1MonthDropDownList, Replacement2MonthDropDownList, Replacement3MonthDropDownList}
Then you could access it by index like this:
Dim currentMonthControl As DropDownList = monthControls(Count)

Use string as variable name ASP

Im doing a page in .asp and im having this problem ... I have some variable constants
MENU_01="FICHEROS"
MENU_02="OPTIONS"
MENU_03="USERS"
etc ... what I need to do its a cicle where I can print each variable value by refering it by string ...
Dim i
For i=1 to CANTMENUS
Response.Write "<li>"& MENU_0 & i; & "</li>"
Next
Something like that (obviously that do not work) I know the variable name start in MENU_0 and I want dinamicly add the next value to the variable name (the "i" value)
Its this posible to do ??
thanks for all.
Can be done with Response.Write "<li>"& Eval("MENU_0" & i) & "</li>" but using eval is not recommended because of it's not a reliable method. I'd suggest the use of dictionary object.
Set MENU = Server.CreateObject("Scripting.Dictionary")
MENU.Add "01", "FICHEROS"
MENU.Add "02", "OPTIONS"
MENU.Add "03", "USERS"
For Each Item In MENU.Items
Response.Write "<li>" & Item & "</li>"
Next
Another option is using arrays.
In fact I found a way to do this without a set or array! By using eval() func
eval("MENU_"&MENUNUMBER)
MENUNUMBER its the iteration variable and the variables with the values I want are MENU_01 MENU_02 MENU_03 etc ... and with eval("MENU_01") I get the value I need!
Thanks for all.

Cast a string to a name of a web label

HI, using vs2008 and building a web app. On a asp page called blackjack.aspx, I have four labels with id of lbBJTStatusP1 lbBJTStatusP2 lbBJTStatusP3 lbBJTStatusP4.
I want to address those labels in a single sub by casting the casting two strings into the control name, so that string lbBJTStatusP & "1" would refer to lbBJTStatusP1.This is done on the code behind page.
So far I have tried this but with no success. boxct refers to either "1" "2" "3" or "4".
DirectCast(blackjack.Controls.Find("lbBJTStatusP" & boxct, True)(0), Label).BackColor = stoodcolor
Can it be done and if so how. Thanks for all and any help.
You can't "cast" a string to a specific instance of a control.
What you can do is use FindControl: that accepts a string, searches (one level deep, not more) for a control with that name and returns it. The method returns a Control, so you might need to cast it to Label.
I have labels named lblqu01ex - lblqu10ex. I set the text value through coding as follows.
for i = 1 to 10
ex = "lbl" & IIf(i = 10, "qu10", "qu0" & i) & "ex"
DirectCast(FindControl(ex), Label).Text = 2*100/i
next
Its work.

Accessing VB6 Collection Item from VBScript embedded in HTML

i'm learning by practice. I was given an OCX file which according to who gave it to me was created using VB6 and I have the task of creating a user interface for it to test all the functionality that is described in a poorly written documentation file. On top of that I am not well-versed in VBScript but I've managed to dodge a few bullets while learning.
I have a method which returns a Collection and when I try to access it from VBScript I am only able to query the Count but when I try to do job.Item(i) or job(i) I get an error stating it doesn't have that property or method.
Can someone point me in the right direction to be able to traverse the contents of this collection?
I had to do it from JavaScript but since some things weren't that easy I decided that perhaps VBScript would help me bridge the gaps where JavaScript didn't cut it. I can access all properties from the ActiveXObject from JavaScript, but the methods which return other VB objects are a little more obscure to me. I've tried aJob.Item(iCount), aJob.Items(iCount) and aJob(iCount).
My code is:
For iCount = 1 To aJobs.Count
MsgBox("Num " & iCount)
MsgBox(aJobs.Item(iCount))
Next
Thanks.
People often create specialized and/or strongly typed collection classes in VB6. They don't always do it correctly though, and they sometimes create "partial" collection implementations that have no Item() method (or fail to mark it as the default member of the class). They might even have a similar method or property but name it something entirely different.
It is rarer to return a raw Collection object, but it can be done and if it is you shouldn't have the problems you have indicated from VBScript.
I just created a DLL project named "HallLib" with three classes: Hallway, DoorKnobs, and DoorKnob. The DoorKnobs class is a collection of DoorKnob objects. The Hallway class has a DoorKnobs object that it initializes with a random set of DoorKnob objects with randomly set properties. Hallway.DoorKnobs() returns the DoorKnobs collection object as its result.
It works fine in this script:
Option Explicit
Dim Hallway, DoorKnobs, DoorKnob
Set Hallway = CreateObject("HallLib.Hallway")
Set DoorKnobs = Hallway.DoorKnobs()
MsgBox "DoorKnobs.Count = " & CStr(DoorKnobs.Count)
For Each DoorKnob In DoorKnobs
MsgBox "DoorKnob.Material = " & CStr(DoorKnob.Material) & vbNewLine _
& "DoorKnob.Color = " & CStr(DoorKnob.Color)
Next
Update:
This script produces identical results:
Option Explicit
Dim Hallway, DoorKnobs, KnobIndex
Set Hallway = CreateObject("HallLib.Hallway")
Set DoorKnobs = Hallway.DoorKnobs()
MsgBox "DoorKnobs.Count = " & CStr(DoorKnobs.Count)
For KnobIndex = 1 To DoorKnobs.Count
With DoorKnobs.Item(KnobIndex)
MsgBox "DoorKnob.Material = " & CStr(.Material) & vbNewLine _
& "DoorKnob.Color = " & CStr(.Color)
End With
Next
As does:
Option Explicit
Dim Hallway, DoorKnobs, KnobIndex
Set Hallway = CreateObject("HallLib.Hallway")
Set DoorKnobs = Hallway.DoorKnobs()
MsgBox "DoorKnobs.Count = " & CStr(DoorKnobs.Count)
For KnobIndex = 1 To DoorKnobs.Count
With DoorKnobs(KnobIndex)
MsgBox "DoorKnob.Material = " & CStr(.Material) & vbNewLine _
& "DoorKnob.Color = " & CStr(.Color)
End With
Next
So I suspect you'll need to use some type library browser like OLEView to look at your OCX to see what classes and members it actually exposes.

How do you call a method from a variable in ASP Classic?

For example, how can I run me.test below?
myvar = 'test'
me.myvar
ASP looks for the method "myvar" and doesn't find it. In PHP I could simply say $me->$myvar but ASP's syntax doesn't distinguish between variables and methods. Suggestions?
Closely related to this, is there a method_exists function in ASP Classic?
Thanks in advance!
EDIT: I'm writing a validation class and would like to call a list of methods via a pipe delimited string.
So for example, to validate a name field, I'd call:
validate("required|min_length(3)|max_length(100)|alphanumeric")
I like the idea of having a single line that shows all the ways a given field is being validated. And each pipe delimited section of the string is the name of a method.
If you have suggestions for a better setup, I'm all ears!
You can achieve this in VBScript by using the GetRef function:-
Function Test(val)
Test = val & " has been tested"
End Function
Dim myvar : myvar = "Test"
Dim x : Set x = GetRef(myvar)
Response.Write x("Thing")
Will send "Thing has been tested" to the client.
So here is your validate requirement using GetRef:-
validate("Hello World", "min_length(3)|max_length(10)|alphanumeric")
Function required(val)
required = val <> Empty
End Function
Function min_length(val, params)
min_length = Len(val) >= CInt(params(0))
End Function
Function max_length(val, params)
max_length = Len(val) <= CInt(params(0))
End Function
Function alphanumeric(val)
Dim rgx : Set rgx = New RegExp
rgx.Pattern = "^[A-Za-z0-9]+$"
alphanumeric = rgx.Test(val)
End Function
Function validate(val, criterion)
Dim arrCriterion : arrCriterion = Split(criterion, "|")
Dim criteria
validate = True
For Each criteria in arrCriterion
Dim paramListPos : paramListPos = InStr(criteria, "(")
If paramListPos = 0 Then
validate = GetRef(criteria)(val)
Else
Dim paramList
paramList = Split(Mid(criteria, paramListPos + 1, Len(criteria) - paramListPos - 1), ",")
criteria = Left(criteria, paramListPos - 1)
validate = GetRef(criteria)(val, paramList)
End If
If Not validate Then Exit For
Next
End Function
Having provided this I have to say though that if you are familiar with PHP then JScript would be a better choice on the server. In Javascript you can call a method like this:-
function test(val) { return val + " has been tested"; )
var myvar = "test"
Response.Write(this[myvar]("Thing"))
If you are talking about VBScript, it doesn't have that kind of functionality. (at least not to my knowledge) I might attempt it like this :
Select myvar
case "test":
test
case "anotherSub":
anotherSub
else
defaultSub
end select
It's been a while since I wrote VBScript (thank god), so I'm not sure how good my syntax is.
EDIT-Another strategy
Personally, I would do the above, for security reasons. But if you absolutely do not like it, then you may want to try using different languages on your page. I have in the past used both Javascript AND VBScript on my Classic ASP pages (both server side), and was able to call functions declared in the other language from my current language. This came in especially handy when I wanted to do something with Regular Expressions, but was in VBScript.
You can try something like
<script language="vbscript" runat="server">
MyJavascriptEval myvar
</script>
<script language="javascript" runat="server">
function MyJavascriptEval( myExpression)
{
eval(myExpression);
}
/* OR
function MyJavascriptEval( myExpression)
{
var f = new Function(myExpression);
f();
}
*/
</script>
I didn't test this in a classic ASP page, but I think it's close enough that it will work with minor tweaks.
Use the "Execute" statement in ASP/VBScript.
Execute "Response.Write ""hello world"""
PHP's ability to dynamically call or create functions are hacks that lead to poor programming practices. You need to explain what you're trying to accomplish (not how) and learn the correct way to code.
Just because you can do something, doesn't make it right or a good idea.
ASP does not support late binding in this manner. What are you trying to do, in a larger sense? Explain that, and someone can show you how to accomplish it in asp.
Additionally, you might consider "objectifying" the validation functionality. Making classes is possible (though not widely used) in VB Script.
<%
Class User
' declare private class variable
Private m_userName
' declare the property
Public Property Get UserName
UserName = m_userName
End Property
Public Property Let UserName (strUserName)
m_userName = strUserName
End Property
' declare and define the method
Sub DisplayUserName
Response.Write UserName
End Sub
End Class
%>

Resources