VBScript Data Validation – Numeric 1 Results in Infinite Loop

infinite-loopvalidationvbscript

DISCLAIMER: I'm still an uber-n00b with programming concepts and know just enough VBS to hurt myself, so I'm likely to slur/slaughter some of the terms/concepts/ideas that are entailed with this program I'm trying to write. You, the vastly superior programmer who has every right to flame me, have been warned.

I've been trying to write a VBScript to validate data, specifically Dates. Since my users are kind of poor with keyboards, I figured I'd make it easy by separating the entry of each part of the date (Month & Day only, I've got the Year set statically).

Previously, I was having problems with validating the numbers with only 1 "Do…Loop", as I was trying to verify if it was Numeric Input and checking at the same time if it was within the specified range (1 – 12, for the 12 months of the year).

This is what the previous code roughly looked like:

Do
    ' If...Then Statements Here
Loop Until (dtFirstMonth > 0) _
    And (dtFirstMonth < 13) _
    And IsNumeric(dtFirstMonth) _
    And (dtFirstMonth <> "") _
    And (dtFirstMonth <> vbNull)

This often resulted in "Data Type Mismatch" errors, so I had to split the Validation Critera to two separate "Do…Loop" statements, as you can see in the current code I have below:

Sub srTest()
    Do
        dtFirstMonth = InputBox("Please Enter a Numeric Month for the Starting Range", _
            "Starting Range Month")

        If (dtFirstMonth = vbNull) _
            Or (dtFirstMonth = "") _
            Or Not IsNumeric(dtFirstMonth) Then
                MsgBox "Please Enter a Valid Numeric Month",, "Enter Month Number"
        ElseIf (dtFirstMonth <> vbNull) _
            And (dtFirstMonth <> "") _
            And IsNumeric(dtFirstMonth) Then
                Do
                    dtFirstMonth = Round(dtFirstMonth)
                    Wscript.Echo dtFirstMonth ' Infinite Loop Here (Basically, As Soon As We Get Into Loop with a Value of 1, We're Stuck)
                    dtFirstMonth = CInt(dtFirstMonth)
                        ' Must Convert User Input to Integer to 
                        '   Prevent Data Mismatch Errors In 
                        '   Following "If" Statement; Besides, 
                        '   It Passed the First Test to be a
                        '   Numeric Value in the First Place

                    If (dtFirstMonth < 1) Or (dtFirstMonth > 12) Then
                        MsgBox "Please Enter a Valid Numeric Month",, "Enter Month Number"
                        Exit Do
                            ' Drop Out of 2nd Level Loop to 
                            '   Enter Into 1st Level Loop
                    End If
                Loop Until (dtFirstMonth > 0) _
                    And (dtFirstMonth < 13) _
                    And IsNumeric(dtFirstMonth) _
                    And (dtFirstMonth <> "") _
                    And (dtFirstMonth <> vbNull)

                If (dtFirstMonth < 1) Or (dtFirstMonth > 12) Then
                    dtFirstMonth = ""
                End If
                    ' dtFirstMonth Was Converted to Integer Earlier
                    ' This is to Meet the Value that Didn't Pass 
                    '   the Nested Do & If Statement (Level 2 Do Loop)
                    ' Sets dtFirstMonth to "Empty String" to Continue 
                    '   Looping in the Level 1 "Do...Loop" Statement; 
                    '   If Omitted, Level 1 "Do...Loop" is Satisfied, 
                    '   Thus Ending the Subroutine (Since the Value 
                    '   of dtFirstMonth is Still a Numeric Value)
        End If
Loop Until IsNumeric(dtFirstMonth) _
    And (dtFirstMonth <> "") _
    And (dtFirstMonth <> vbNull)

    Wscript.Echo dtFirstMonth
End Sub

srTest

I had to set up the 1st "Do…Loop" to check that the User Input (dtFirstMonth) was a indeed a Numeric Value and not a Null Value nor an Empty String. The Nested "Do…Loop", or 2nd "Do…Loop", statement is where I have the same Criteria plus the extra Criteria defining the desired ranges (any number between 1 and 12).

This is working perfectly for number 2-12, but when the script parses the number 1, I enter into an Infinite Loop.

I've checked to make sure that the Infinite Loop is occurring in the 2nd "Do…Loop" by replacing the entire 2nd "Do…Loop" section with "Wscript.Echo dtFirstMonth". By doing this, I get the expected results: a single Echo, not an infinite number of them (technically, I get 2, as I do have another "Wscript.Echo dtFirstMonth" string at the bottom of the Subroutine for the purpose of debugging, but either way, it's not an Infinite Loop).

I've also changed the criterion for the lower range to be like this, yet this doesn't remediate the error:

Do
    ' If...Then Statements Here
Loop Until (dtFirstMonth >= 1)

I've also tried this, with no resulting success:

Do
    ' If...Then Statements Here
Loop Until (dtFirstMonth >= CInt(1))

In all reality, there really is no need for this segment, since I converted the User's Input to an integer anyway.

Since this was starting to get confusing, I decided to add the "Round" statement before the script passed the User's Input to the "CInt" function, hoping that it would make sure that it wasn't getting caught as a 0 value or decimal value somehow; yes, this is irrational thought on my part, but I still wanted to explore all avenues (there's also the fact that I have some users with "Fat Finger Syndrome" and some others with "Abuse The Program" mentality, so I figured I'd make sure the script accounted for decimal entries). I added the "Round" string before and after the nested "Do…Loop" and I still had the Infinite Loop issue.

This is as far as I've been able to get on this and now I'm stuck.

I realize that there are likely better ways to do Date/Time Validation in VBScript, and I'm certainly open to any new suggestions, but I'd love to solve this for the pure sake of edification.

Best Answer

Way too much code for a simple input of a number. Just try to keep it short and simple. Example:

Do
    dtm = InputBox("Please Enter a Numeric Month for the Starting Range", _
                "Starting Range Month")
    Select Case True
        Case isNull(dtm), (not isNumeric(dtm)), dtm = "", dtm = empty, (dtm < 1 OR dtm > 12)
            ' too exhaustive, but just for the sake of the example.
             MsgBox "Please enter an amount between 1 and 12"
        Case else
            ' Hey, this seems to be a valid amount!
            Exit do
    End Select
Loop While True

'  Do something with dtm

Just showed you some creative Select Casing, this supports lazy exit, so if a value is Null, it escapes before getting evaluated where evaluating could throw an error.

Related Topic