What VBA event is triggered when closing a form? - ms-access

If I don't fill out all the required fields in my form, I get an ugly error when I click the "x" in the upper right corner.
I would like to override the default error with a custom error message, but I can't figure out which VBA event to associate this code with. the Form_Close event doesn't seem to work when I put an error handler in there.
Access 2010
Private Sub Form_Unload(Cancel As Integer)
On Error GoTo Err_Unload ' Initialize error handling.
'insert routine
Exit_Unload: ' Label to resume after error.
Exit Sub ' Exit before error handler.
Err_Unload: ' Label to jump to on error.
'MsgBox Err & " " & Error$ ' Place error handling here.
Resume Exit_Unload
End Subenter code here
Still receiving errors even while using this code.
Private Sub Form_Unload(Cancel As Integer)
On Error GoTo Err_Unload ' Initialize error handling.
' Code to do something here.
Exit_Unload: ' Label to resume after error.
Exit Sub ' Exit before error handler.
Err_Unload: ' Label to jump to on error.
'MsgBox Err & " " & Error$ ' Place error handling here.
Resume Exit_Unload
End Sub

When you attempt to close a form which has unsaved changes to the form's current record, Access will first attempt to commit those changes. You can't intercept that action from Form_Unload or Form_Close.
BTW, although you didn't mention it, I would expect you to see the same thing when navigating to a different record if the record you're navigating away from includes unsaved changes with missing values for required fields.
In the case where your form's record source includes a table with an autonumber field, use the form's before update event to check whether required values are present. If there is no autonumber field involved, consider doing the checking from both the form's before insert and before update events.
However if the whole point of this is to get a friendlier message for a missing value in a required field, see whether changing the table's properties is satisfactory. For example, you could set Required to No, then use Is Not Null for the field's Validation Rule which would allow you to assign your friendly text message as the field's Validation Text property.

From http://office.microsoft.com/en-us/access-help/order-of-events-for-database-objects-HP005186761.aspx,
Similarly, when you close a form, the following sequence of events
occurs:
Exit (control) → LostFocus (control) → Unload (form) → Deactivate
(form) → Close (form)
If you've changed data in a control, the BeforeUpdate and AfterUpdate
events for both the control and the form occur before the Exit event
for the control.
What's likely causing your error is the BeforeUpdate event when the form tries to save your changes, but fails because you haven't filled in required fields. You can create some validation code and run it in the BeforeUpdate event for the form to make sure everything is OK and send the appropriate message to the user.

You might like to use:
Private Sub Form_Unload(Cancel As Integer)
End Sub

There is actually a form event called On Error, which has two arguments: what the error is and what response Access should perform.

Related

"The value you enter isn’t valid for this field" - cannot be triggered by ribbon command

I have below two different controls.
Combo Box (CB) control which Record Source is query and limited to
List with "On Not In List" Event code.
Text Box (TB) control which is bounded to Integer control source.
I have question for error handler when data entry is incorrect on these two controls.
CB - "On Not In List" Event will be triggered if data entered is incorrect and press tab to move out focus. Instead of press tab to move out focus, I click ribbon command and Event will be triggered also.
TB - System error message "The value you enter isn’t valid for this field" will be shown when entering non-numerical character and press tab to move out focus. Error message will NOT show up when I click ribbon command.
Question:
For TB control, can I disable system error message "The value you enter isn’t valid
for this field" and replaced by my own error handler which will be
trigged when click ribbon command?
If system error cannot be disable, how to trig "The value you enter isn’t valid
for this field" error message when click ribbon
command?
For the combobox NotInList event, there are two parameters: NewData as String and Response as Integer. To suppress the ugly "The value you entered isn't valid..." prompt, simply add the line of code: Response = 0
Private Sub YourFieldName_NotInList(NewData As String, Response As Integer)
Response = 0
'---Additional code if desired. For me, in the form footer,
' I use a label called, lblHelper and set the caption using
' a custom string to visually show the user there is an error.
lblHelper.Caption = "Error: You must select a value from the list."
End Sub
For the textbox, use the BeforeUpdate event. Set the parameter 'Cancel' to true and perform a logical test to determine if the field is a real number. The IsNumeric function is built into VBA and returns either True or False.
Private Sub txtYourTextField_BeforeUpdate(Cancel As Integer)
If IsNumeric(txtYourField.Text) = False Then
lblHelper.Caption = "Error: invalid data"
Cancel = True ' or use Cancel = -1
Beep
'---Remember True and False are boolean data types. In MS Access VBA,
' you can assign integer values of 0 (False) and -1 (True) respectively
' without having syntax or run-time errors.
End If
End Sub
Alternatively, you can use the KeyPress Event. Simply use a Select statement to evalauate the ASCII code. If the case is not equal to the ASCII values of 0-9, then use:
DoCmd.CancelEvent

MS Access Textbox.OldValue equivalent for DateTime Format

When we update a bound textbox on a form, we can use the _BeforeUpdate event to perform logical checks and controls before the update, and reset the textbox to it's previous value using the txtboxfield.OldValue property if so desired.
This does not work if the underlying bound is a DateTime field.
Is there an equivalent for the DateTime field? If not, is there a workaround that I could use in the following piece of code?
Private Sub txtDueDate1_BeforeUpdate(Cancel As Integer)
'Alert if inital due date is modfied
If Not (Me.txtDueDate1 = vbNullString) Then
Select Case MsgBox("Are you sure you wish to modify the original due date?", _
vbOKCancel Or vbInformation, "Original Due Date")
Case vbOK
Exit Sub
Case vbCancel 'reset the previous value
Me.txtDueDate2.SetFocus
Cancel = True
Me.txtDueDate1.OldValue
'Me!txtDueDate1.Undo
End Select
End If
End Sub
Using the .Undo option doesn't work for me, as I with to use .SetFocus which gets blocked by...
run time error 2108: You must save the field before you can execute...
I have experimented with moving the .SetFocus command arround, but it does not matter where it is placed.
The _BeforeUpdate will not allow you to perform another save while current BeforeUpdate is being executed. It's like the transaction is locked until this event is completed.
You can undo the current field and cancel the event by:
Me!txtDueDate1.Undo
Cancel = True
If you require editing/modifying other fields, you can either move this code to OnAfterUpdate or move all validations to your Form'sOnBeforeUpdate on which you can then halt the entire update process

Action on Form Save

We have an Access 2010 database that acts as a front-end to a MS SQL database. When we edit data in the form there is a procedure that needs to run in order to properly save certain data back to SQL.
Our DB programmer added a "Save Button" to do this. But that causes another problem - there are multiple ways in Access by which to save a form -
Navigate to the next record
Click on the Confirmation bar on the left
Create a new record
Search for a new record
Use commands in the ribbon
Is there any way to attach a procedure the actual save action so that no matter how a person moves to a next form that the procedure gets run?
[update]
Here is the code behind the scenes: the first sub is attached to the "Save" Button. Of course, the second is attached to the form BeforeUpdate.
Private Sub SaveRecord_Click()
'From NAME form
Form_BeforeUpdate False
End Sub
Private Sub Form_BeforeUpdate(Cancel As Integer)
'used by NAME form
[Last_Update] = Now
'*********************
Save_Record
'*********************
MName_ID = Me.Name_ID
Me.Undo
Cancel = True
If Not IsNull(MName_ID) Then
Jump_to_Name_ID MName_ID, True
Else
End If
End Sub
I guess I just don't understand what the button is for.
So I installed an MS Access 2010 trial and finally managed to figure out a way to solve your problem. It includes data macros and a hidden gem that took me quite a while to find.
Here's how you run VBA when a table changes:
Create an ordinary module (haven't tried class modules) with public functions:
Module name: EventHandlers
Public Function InsertEvent(ByVal id As Integer)
MsgBox "inserted: " + CStr(id)
End Function
Open the table that, when modified, should run VBA and go to "Table" in the ribbon.
Click on "After Insert"
In the "Add New Action"-select box, choose SetLocalVar (or select it from the Action Catalog).
In the Name-field, insert the name of the module (in this case, EventHandlers, as we created earlier)
In the Expression-field, write the name of the function: InsertEvent([id]) (where [id] is an actual column in the table you're adding a data macro for)
Save and close
Whenever something is inserted to the table, a messagebox will be shown with the id.
You could do the same with the update event. The function could be something like this:
Public Function UpdateEvent(ByVal oldValue As String, ByVal newValue As String)
MsgBox oldValue + " changed to: " + newValue
End Function
and the data macro would be
Action: SetLocalVar
Name: EventHandlers
Expression: UpdateEvent([Old].[your_column_name];[your_column_name])
Note: Executing DoCmd.RunSQL with update, insert or delete will execute data macros and THEN ask the user if he or she actually WANTS to update/insert/delete the row. If the user clicks cancel, nothing is changed but your data macro executed anyway. If you haven't already, you should probably disable this check before implementing data macros.
Well, I was not able to use Mr. Sommer's solution because it was not possible to add an event handler to a linked table on account of their being read-only. But, I did work out a simple procedure that seems to work well enough.
So, I was actually already using the BeforeUpdate event, so I'm catching the right event here - this is the event that traps the save, whether it be on change of navigation or the save-record bar on the left. However, there were a few issues that resulted from using Application.Echo False to keep Access from posting back the old data to the control whilst the Me.Undo takes place.
So we use cancel=true to prevent the BeforeUpdate event from doing its normal processing, and we use Me.Undo to prevent Access from trying to save data to the linked tables.
Private Sub Form_BeforeUpdate(Cancel As Integer)
Cancel = True
[Last_Update] = Now
'*********************
Save_Record '-->This will save the data back to SQL
'*********************
MName_ID = Me.Name_ID
Application.Echo False 'don't show the undo in the controls
Me.Undo
If Not IsNull(MName_ID) Then 'used for the navigation buttons
Jump_to_Name_ID MName_ID, True
Else
End If
Application.Echo True 'turn the control refresh back on
Me.Repaint
End Sub

Error on entering data in a form in VBA access

Hello i am using a form in ACCESS to enter new data for a company. First of all the form shows me the current data with a query , and when i want to introduce a new data in the fiels in a line i press Tab many times and when ends it gave me an Error:
the data was added to the database but the data won't be displayed in the form because it
doesn't satisfy
and i close the form and when i open again the form for that company the values that i entered are there...
how can i solve this error , any ideas?
Add some rudimentary error trapping. If your code doesn't already contain it, you really need to read up on it. Any code without some error trapping is just flat out poorly written code.
To start, use a shell like this and modify it appropriately:
Sub|Function SomeName()
On Error GoTo Err_SomeName ' Initialize error handling.
' Code to do something here.
Exit_SomeName: ' Label to resume after error.
Exit Sub|Function ' Exit before error handler.
Err_SomeName: ' Label to jump to on error.
MsgBox Err.Number & Err.Description ' Place error handling here.
Resume Exit_SomeName ' Pick up again and quit.
End Sub|Function
If it hits an error, it will jump to the Err_SomeName: line and then display a messagebox with the error number and description. It will then exit the Sub/Function. What you really want to do is instead of just popping up a messagebox, do something that actually solves the problem. This is what error handling is all about, and it's critical to ensure your program functions exactly the way it's supposed to.

MS Access table validation

I was wondering if anybody would be able to tell me how to check if multiple fields in a form are valid or not. Basically I want to set up a validation rule for my last field to check if all of the previous fields are blank or not.
I have already tried this:
IsNull([FieldName])
I know that this is only for one field, but I can't even get that to work. I am pretty new with access so any help would be much appreciated. Thank you!
What i would do is in the tag property for each control you want to validate, put a word in there that you can check for (example - enter "VALIDATE" for each control you want checked). To find the tag property: look at the property sheet for each control, in the OTHER tab, the last field listed = tag).
Then as code in the afterupdate event of the last control, select EVENT PROCEDURE and enter this code:
Dim ctl As Control
For Each ctl In Forms!YourFormName
If ctl.Tag = "validate" Then
If IsNull(ctl.Value) Then
ctl.SetFocus
MsgBox "You must complete the " & ctl.Name & " field.", vbOKOnly, "Required Field Missing"
GoTo exitsub
End If
End If
Next
exitsub:
Exit Sub
If this finds and empty field, it will move back to that field, (set focus) and display a message box that states they must enter a value.