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.