Back

August 1997 Tips and Tricks:

Field Validation on Got Focus Vs Lost Focus

Doing field validation during Got Focus rather than Lost Focus allows  you to skip field validation if conditions warrant. For example, if you have a Cancel command button on your form, you don't want to do field validation when focus switches from a text box to the Cancel button because Cancel is going to refresh from the recordset anyway.

Triggering field validation with Got Focus is admittedly a little more work, but in my view well worth it. Here's how I do it:

1. Establish a module level memvar to indicate a field validation is pending. I use strFieldValidationPending. See the declarations at the top of the code samples.

2. In the form's load event handler, store an empty string to strFieldValidationPending. See Sub Form_Load().

3. In the Lost Focus event handler, for every field that requires validation, store a string identifying the field to strFieldValidationPending.

See Sub txtFields_LostFocus().

Remember, only store a value to strFieldValidationPending if the field loosing focus needs validation, otherwise leave strFieldValidationPending blank.

4. Create the routine that actually handles the validation. See Function ValidateFields1().

Notice that I use memvar strFieldMode to indicate what MODE the form is in. strFieldMode will contain values like "AddModeNew", "EditModeNew", "EditModeChanged", etc. The "New" or "Changed" suffix indicates whether or not changes have been made to any of the fields. I only do the field validation if changes have been made. Please note that when the field fails validation, a message box is displayed, focus is reset to the offending field, and the function returns false. Also note that strFieldValidationPending is ALWAYS set to an empty string before returning from ValidateFields1(), whether or not the field passed validation.

5. In the Got Focus event handlers, for all objects on the form that can receive focus (except command buttons), call the Field Validation routine. See Sub txtFields_GotFocus().

6. In the Click event handler, for command buttons (those that can receive focus during an add or edit), call the Field Validation routine. See Sub cmdGeneric_Click().

Notice that when the Cancel button is clicked, the field validation is NOT called. With the other command buttons the field validation IS called. The command button click is not processed unless the validation returns True.

The one thing I haven't talked about yet is what happens if the user clicks something outside the confines of the form(window). In this case, the control that had focus retains it. When the user returns to the form (unless he does so by clicking on another control), the original control still has focus so the validation will occur as user when another control gets focus. But what if the user closes the form via a menu option on the MDI parent? Query Close can be used to initiaite field validation, but because you attempted to close the form "off site" there's no way for Query Close to know which field had focus whey you did so. I've handled this a number of ways, and the one I like the best is as follows:

1. After the Field Validation routine to accept an optional Boolean parameter blnUnloading is True, it means the Field Validation routine is being called by the Query Unlad event handler. In this case, check ALL field validations. See Function ValidateFields2().

2. Call the Field Validation routing with the parameter from Query Unload. See Sub Form_QueryUnload().


CODE SECTION:

Option Explicit
Dim strFormMode As String
Dim strFieldValidationPending As String
 
Private Sub Form_Load()
<   strFieldValidationPending=""""
   Generic1.JCCInitialFormDisplay rsCustomer, Me
End Sub

 

Private Sub txtFields_LostFocus(Index As Integer)
' If a field requires field level validation, store the name of
' the field to a module level memvar.
    Select Case Index
        Case 1
        strFieldValidationPending = "Last/CompanyName"
        Case 6
        strFieldValidationPending = "State"
    End Select
    If Index = 6 Then
        strFieldValidationPending = "State"
    End If
End Sub
 
Private Function ValidateFields1() As Boolean
    ' Perform field leval validation if required
    DoEvents
    ValidateFields = True
    If Right$(strFormMode, 7) = "Changed" Then
        Select Case strFieldValidationPending
        Case ""
        ValidateFields = True
        Case "Last/CompanyName"
        If Trim$(txtFields(1).Text) = "" Then
        ValidateFields = False
        MsgBox "Last/Company Name cannot be blank"
        txtFields(1).SetFocus
        End If
        Case "State"
        If UCase$(txtFields(6).Text) <> "CA" Then
        ValidateFields = False
        MsgBox "State must be California"
        txtFields(6).SetFocus
        End If
End Select
End If
strFieldValidationPending = ""
End Function
 
Private Sub txtFields_GotFocus(Index As Integer)
    ValidateFields
End Sub
 
Private Sub cmdGeneric_Click(Index As Integer)
Dim blnProcessClick As Boolean
    blnProcessClick = True
If Index <> 4 Then
blnProcessClick = ValidateFields()
End If
If blnProcessClick Then
Select Case Index
    Case 0 ' Add button
        Generic1.JCCAddRec rsCustomer, Me
    Case 1 ' Edit button
        Generic1.JCCEditRec rsCustomer, Me
    Case 2 ' Delete button
        Generic1.JCCDeleteRec rsCustomer, Me
    Case 3 ' Save button
        Generic1.JCCSaveRec rsCustomer, Me
    Case 4 ' Cancel button
        Generic1.JCCCancelAddOrEdit rsCustomer, Me
    Case 5 ' Close button
        Unload Me
End Select
End If
End Sub
 
Private Function ValidateFields2(Optional blnUnloading As Boolean = False) As Boolean
' Perform field leval validation if required
Dim strFieldsToValidate(1) As String
Dim bytX As Byte
DoEvents
ValidateFields = True
If Right$(strFormMode, 7) = "Changed" Then
If blnUnloading Then
    ' Set strFieldValidationPending to every possible value, and call
    ' Validate fields until you either return a false, or run out of
    ' strFieldValidationPending values.
    strFieldsToValidate(0) = "Last/CompanyName"
    strFieldsToValidate(1) = "State"
    For bytX = 0 To UBound(strFieldsToValidate)
    strFieldValidationPending = strFieldsToValidate(bytX)
If Not ValidateFields() Then
    ValidateFields = False
    Exit For
End If
Next bytX
Else
    Select Case strFieldValidationPending
        Case ""
            ValidateFields = True
        Case "Last/CompanyName"
        If Trim$(txtFields(1).Text) = "" Then
        ValidateFields = False
        MsgBox "Last/Company Name cannot be blank"
        txtFields(1).SetFocus
        End If<> Case "State"
        If UCase$(txtFields(6).Text) <> "CA" Then
        ValidateFields = False
        MsgBox "State must be California"
        txtFields(6).SetFocus
        End If
End Select
End If
End If
strFieldValidationPending = ""
End Function
 

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
     If Right$(strFormMode, 7) = "Changed" Then
    If ValidateFields(True) Then
    If MsgBox("Save Changes?", vbYesNo, "Verify Save Changes") = vbYes Then
    Generic1.JCCSaveRec rsCustomer, Me
End If
Else
    Cancel = True
End If
End If
End Sub


Copyright 1998, 1999, 2000, 2001 Diablo Valley PC Users Group. All rights reserved.