How to execute code when user closes form? - vba

I want a msg box to appear if certain fields are empty on close.
Private Sub Close_Click()
If IsNull(Me.startDate) Then
MsgBox “You are in Phase 1”
End If
End Sub
I want the pop up to appear when user clicks the exit x. I tried OnClose. Right now the code is attached to and works via a button.
I’d like the code to be executed when the user closes the form.
Edit New Code:
Private Sub Exit_Click ()
If IsNull(Me.startDate) Or IsNull(Me.stepOneA) Or IsNull(Me.stepOneB) Then
MsgBox “You are in Step I”
DoCmd.Close
ElseIf IsNull(Me.stepTwoA) or IsNull(Me.stepTwoB) or IsNull(stepTwoC)
MsgBox “You are in Step II”
DoCmd.Close
Else
DoCmd.Close
EndIf
End Sub

You can use the UnLoad event for this:
Private Sub Form_Unload(Cancel As Integer)
Cancel = IsNull(Me.startDate)
If Cancel = True Then
MsgBox "You are in Phase 1."
End If
End Sub

Related

Access VBA Preventing form record entry on close

I am working with Access Database VBA.
I have noticed if a user has filled a few of the text boxes in and then clicks the windows close button, the form logs that into the records.
I am wondering what is the best way to prevent the form from entering the uncompleted record on close?
There were a few sites pointing to placing a code in the beforeupdate function.
This is what I have tried.
Private Sub frmRecLog_BeforeUpdate(Cancel As Integer)
DoCmd.SetWarnings False
Me.Undo
Cancel = True
Exit Sub
End Sub
This code does not work at all for me.. I tried my best, haha.
Anything helps.
So, what you need is to insert a command button Save. If user do not hit on Save then it will not save any records. They will get a warning that data is not saved. You need declare a private boolean variable and write codes to save and warning. So full code will be like below.
Option Compare Database
Option Explicit
Private blnSaveRecord As Boolean
Private Sub cmdSave_Click()
blnSaveRecord = True
DoCmd.RunCommand (acCmdSaveRecord)
blnSaveRecord = False
End Sub
Private Sub Form_BeforeUpdate(Cancel As Integer)
Dim strMsg As String
If Not blnSaveRecord Then
Cancel = True
strMsg = "Please save the record.," & _
vbNewLine & "or press ESC from keyboard to cancel the operation."
Call MsgBox(strMsg, vbInformation, "Save Record")
'Me.Undo 'You can set undo option here if you do not want to press ESC.
End If
End Sub

How to exit a VBA macro when the form's "X" button is clicked?

I have an Outlook macro that pops up a form when someone sends an email and asks them to select a classification. Under ThisOutlookSession I have:
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim frm As classificationForm
Dim chosenvalue As String
Set frm = New classificationForm
frm.Show vbModal
Select Case True
Case frm.restrictedButton.Value
chosenvalue = "Restricted"
Case frm.internalButton.Value
chosenvalue = "Internal"
Case frm.publicButton.Value
chosenvalue = "Public"
Case Else
MsgBox "No classification chosen"
Cancel = True
Exit Sub
End Select
If TypeName(Item) = "MailItem" Then
Item.Subject = "[" & chosenvalue & "] " & Item.Subject
End If
End Sub
and under classificationForm I have:
Private Sub okCommand_Click()
Unload Me
End Sub
Private Sub cancelCommand_Click()
Unload Me
End Sub
The form is 3 option buttons (the classifications) and 2 command buttons (OK and Cancel).
The [Internal] option button is selected by default. However, if someone clicks the form's "X" button in the top-right corner or the "Cancel" command button, then the Macro sends the email with the selected classification button when I want it to kick me back to the draft email like it would if there were no options selected.
How would I do this? Thanks.
Unload is a lie. It seems to only work with the form's default instance, and working with forms' default instance is a poisonous place you don't want to go.
Don't unload. Hide instead.
Another problem is that since the calling code is querying the form's controls' state, it doesn't matter how the form was closed: Ok, Cancel, "X" - everything single one of these buttons gets the form unloaded and whatever was selected is acted upon: you have no mechanism in place to determine whether the user okayed the dialog, or wishes to cancel everything.
Add a Cancelled property:
Private IsCancelled As Boolean
Public Property Get Cancelled() As Boolean
Cancelled = IsCancelled
End Property
Handle the QueryClose event, set the Cancel parameter to False when the CloseMode is vbFormControlMenu, and Hide the form - actually, what you want is for that "X" button to do exactly the same thing as your Cancel button, so just do that:
Private Sub OkButton_Click()
Me.Hide
End Sub
Private Sub CancelButton_Click()
OnCancel
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
OnCancel
End If
End Sub
Private Sub OnCancel()
IsCancelled = True
Me.Hide
End Sub
Now your calling code can determine whether the form was cancelled, and act accordingly.
If frm.Cancelled Then
Cancel = True
Else
'user okayed the dialog: determine the selection...
End If
See this article for more in-depth information about user forms: the calling code doesn't need to care about the controls on the form.
use UserForm_QueryClose() event handler to intercept any userform red "X" clicking
then change your UserForm code pane as follows:
Private Sub okCommand_Click()
Me.Hide ' don't unload the Form, just hide it
End Sub
Private Sub cancelCommand_Click()
Me.Tag = "NO" ' signal to the calling sub that it must not send the email
Me.Hide ' don't unload the Form, just hide it
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = 0 Then Me.Tag = "NO" ' if user clicked the red X button signal to the calling sub that it must not send the email
End Sub
and adjust your Application_ItemSend event handler code accordingly:
Set frm = New classificationForm
With frm
.Show vbModal
If .Tag <> "NO" Then ' if userform didn't signal not to send the email
Select Case True
Case frm.restrictedButton.Value
chosenvalue = "Restricted"
Case frm.internalButton.Value
chosenvalue = "Internal"
Case frm.publicButton.Value
chosenvalue = "Public"
Case Else
MsgBox "No classification chosen"
Cancel = True
Exit Sub
End Select
Else ' the userform signaled not to send the email
MsgBox "No classification chosen"
Cancel = True
End If
End With
Unload frm

Userform - Redirect focus on textbox after MsgBox

I hope this is not that stupid, but I really did not find a post that was working for me.
Situation: I want someone to put a date into a textbox in a Userform.
ErrorHandler: I wanted to have a very simple solution if the user doesn't enter the right format. (EB_Start.Activate and EB_Start.SetFocus are NOT working at all)
For this I got:
Private Sub EB_Ende_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
On Error GoTo Error_Handler
Me.EB_Ende = CDate(Me.EB_Ende)
Error_Handler:
EB_Start.Activate
EB_Start.SetFocus
MsgBox ("Please enter a valid date"), , "Datum"
End Sub
Problem:
My Question is now, how do I redirect the focus on the textbox(EB_Ende)
The current reaction is, after the user presses Enter after the MsgBox showed up, It continued to the next textbox, but I want the user to be forced to reenter a valid date in the textbox.
If someone could help me out with this, or redirect me to a Post or link that will answer my question I would really appreciate it.
Best regards,
Lutscha
This is the whole UserForm
There are a couple of issues with your code (e.g. not exiting before the error handler, and do you want to use Cancel=msoTrue to cancel the text entry to EB_Ende when you get an error?) so you could try this:
Private Sub EB_Ende_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
On Error GoTo Error_Handler
Me.EB_Ende = CDate(Me.EB_Ende)
Exit Sub
Error_Handler:
EB_Start.SetFocus
MsgBox ("Please enter a valid date"), , "Datum"
End Sub
Or, you could skip the error-hander entirely:
Private Sub EB_Ende_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
If IsDate(Me.EB_Ende) Then
Me.EB_Ende = CDate(Me.EB_Ende)
Else
Cancel = msoTrue
EB_Start.SetFocus
MsgBox ("Please enter a valid date"), , "Datum"
End If
End Sub
Setting focus in BeforeUpdate event won't work - it is too soon. It is fired before focus is moved to the next control. Better approach is to handle Exit event and cancel it when needed:
Private Sub EB_Ende_Exit(ByVal Cancel As MSForms.ReturnBoolean)
On Error GoTo Error_Handler
EB_Ende = CDate(EB_Ende)
Exit Sub '<-- exit sub when there is no error
Error_Handler:
Cancel = True
MsgBox ("Please enter a valid date"), , "Datum"
End Sub
The funny thing is, you used the answer as a tag on your question:
Me.EB_Ende.SetFocus
Here is more information on SetFocus.
Something else that might help... you can change the default order that objects are "tabbed" through. (ie., what cell should get focus after you press enter or tab in the current control:
worked perfect
Private Sub txtSalary_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
If Not IsNumeric(txtSalary) Then
MsgBox "Please, only numbers!", vbRetryCancel
Cancel = True
txtSalary = ""
End If
If IsNumeric(txtSalary) Then
txtSalary = Format(txtSalary, "$#,##0.00")
End If
End Sub

Access Required Fields Before Exiting Form

I have this BeforeUpdate code to check if certain fields are filled out. These fields are required and must be filled or the record shouldn't save. If other fields have been filled without the ID and Staff field, then the message box prompts pop up (These are required fields, etc.).
Private Sub Form_BeforeUpdate(Cancel As Integer)
If Nz([ID], "") = "" Then
MsgBox "The ID field is required.", vbExclamation, "Required Field"
Cancel = True
End If
If Nz([Staff], "") = "" Then
MsgBox "Staff field is required.", vbExclamation, "Required Field"
Cancel = True
Me.[Staff].SetFocus
End Sub
I have a 'Close Form' button as follows:
Private Sub CmdCloseForm_Click()
DoCmd.Close , ""
End Sub
When this button is clicked, I get the warning that the fields aren't filled, but then the form closes. I want a Yes/No message box asking the user to see if they would still like to close the form or not. I've made a Yes/No messagebox in the BeforeUpdate sub. However it doesn't stop the sub CmdCloseForm.
Is there a way to create a messagebox to confirm if the user wants to exit the form?
For example:
If MsgBox("Would you like to close the form still? Changes won't be saved.", vbYesNo + vbQuestion, "Warning") = vbNo Then
Exit Sub
End If
If I put the above Msgbox into the CmdCloseForm function, it prompts the user before letting them know that they're missing the ID/Staff fields.
I came about this solution by Mr. Craig Dolphin and it worked for me.
The way he approached is to have a generic validation function that is saved in a general purpose module (ie not in a form module).
Public Function validateform(myform As Form) As Boolean
'returns true if all required fields have data, or false if not.
'It will also create a popup message explaining which fields need data
Dim boolresponse As Boolean
Dim strError As Variant
Dim ctl As Control
boolresponse = True
strError = Null
With myform
For Each ctl In .Controls
With ctl
If .Tag = "required" Then
If .Value & "" = "" Then
boolresponse = False
strError = (strError + ", ") & .Name
End If
End If
End With
Next ctl
End With
If strError & "" <> "" Then MsgBox "The following information must be entered first: "
& strError, vbInformation
validateform = boolresponse
End Function
Then, for any fields that are absolutely required, you just set the Tag property of the control to 'required'
You can then, for example, call the function from the onclick event of the 'save' button or 'close' button.
Private Sub Command5_Click()
On Error GoTo Err_Command5_Click
If Me.PrimaryID & "" <> "" Then
If validateform(Me) Then DoCmd.Close
Else
DoCmd.Close
End If
Exit_Command5_Click:
Exit Sub
Err_Command5_Click:
MsgBox Err.Description
Resume Exit_Command5_Click
End Sub
this essentially checks to see if the auto pk field has a value indicating that the record has been created. If it has, then it validates the required fields. If not, it closes without checking. If the record has been created, it validates the form and only closes if all the required fields are filled in. If more data is required, then it pops up a message reminding the user which fields to fill in.
The nice part of this is that you can set conditional requirements using the vba to set the tag property of certain controls to required if another field is updated to a value that you want to trigger an additional requirement. Of course, if you do that then you also need to initialize those tag value in the on_current event for when you switch records.
Many thanks to Mr. Craig Dolphin
Since you want to show consecutive pop-ups, cancel the auto-update altogether and validate on Close.
If validation is successful save the record, if not notify the user.
Private Sub Form_BeforeUpdate(Cancel As Integer)
Cancel = True 'cancel auto-update
End Sub
'Validate and either Save or Close
Private Sub CmdCloseForm_Click()
If Me.Dirty Then
If IsFormValidated Then
DoCmd.RunCommand acCmdSaveRecord
Else
If MsgBox("Would you like to close the form still? Changes won't be saved.", vbYesNo + vbQuestion, "Warning") = vbNo Then Exit Sub
End If
End If
DoCmd.Close acForm, Me.Name, acSavePrompt
End Sub
'Validation
Private Function IsFormValidated() As Boolean
IsFormValidated = True 'assume all is in order
If Nz([ID], "") = "" Then
MsgBox "The ID field is required.", vbExclamation, "Required Field"
IsFormValidated = False
End If
If Nz([Staff], "") = "" Then
MsgBox "Staff field is required.", vbExclamation, "Required Field"
Me.[Staff].SetFocus
IsFormValidated = False
End If
End Function

Access/VBA: "Run-time error 2169. You can't save this record at this time"

Using: Access 2013 with ADO connection to SQL Server back-end database
A form in my Access database is dynamically bound at runtime to the results of a SELECT stored-procedure from SQL Server, and allows the user to make changes to the record.
It has 2 buttons: Save and Cancel.
It is shown as a pop-up, modal, dialog form, and it has a (Windows) Close button at the top right corner.
I've put VBA code to ask the user whether he wants to Save, Ignore or Cancel the close action.
But there are problems and it gives the aforementioned error if Cancel is clicked. There are also other problems, like, after the error occurs once, then any further commands (Save or Cancel or closing the form) don't work - I think this is because the VBA interpreter has halted due to the earlier error. Another complication is that arises - I now need to end the MS-Access process from Windows Task Manager, doing this and then restarting the database and then opening this form will give an error and the form won't load. When the form is then opened in Design mode, I can see the connection string for the form is saved in the Form's Record Source property (this happens only sometimes), and which looks something like this:
{ ? = call dbo.tbBeneficiary_S(?) }.
Here is my code:
Dim CancelCloseFlag As Boolean
Dim SavePrompt As Boolean
Private Sub Form_BeforeUpdate(Cancel As Integer)
Dim a As Integer
If SavePrompt Then
a = MsgBox("Do you want to save changes?", vbQuestion + vbYesNoCancel, "Changes made")
Select Case a
Case vbNo:
Me.Undo
CancelCloseFlag = False
Case vbYes:
'do nothing; it will save the changes
CancelCloseFlag = False
Case vbCancel:
Cancel = True
CancelCloseFlag = True
End Select
End If
End Sub
Private Sub Form_Dirty(Cancel As Integer)
SavePrompt = True
End Sub
Private Sub Form_Error(DataErr As Integer, Response As Integer)
If DataErr = 2169 Then
Response = acDataErrContinue
End If
End Sub
Private Sub Form_Load()
LoadBeneficiaryDetails
End Sub
Private Sub Form_Unload(Cancel As Integer)
If CancelCloseFlag Then
Cancel = True
End If
End Sub
Private Sub btCancel_Click()
If Me.Dirty Then
SavePrompt = True
End If
DoCmd.Close
End Sub
Private Sub btSave_Click()
SavePrompt = False
DoCmd.Close
End Sub
I'm stuck and would like to know how others go about this issue? Basically I want to offer the user the choice Save, Ignore, Cancel when the user attempts to close the form with either Cancel button or the (Windows) close button. If the user chooses Cancel, then it should just return to the form without changing or undoing any changes to the data. The solution may be simple but it escapes my overworked mind.
Thanks in advance!
Please try the following code - I tested against all six scenarios and the proper action is taken.
Option Compare Database
Option Explicit
Dim blnAction As Integer
Dim blnBeenThereDoneThat As Boolean
Private Sub Form_BeforeUpdate(Cancel As Integer)
If blnBeenThereDoneThat = True Then Exit Sub
blnBeenThereDoneThat = True
blnAction = MsgBox("Do you want to save changes?", vbQuestion + vbYesNoCancel, "Changes made")
Select Case blnAction
Case vbNo:
Me.Undo
Case vbYes:
'do nothing; it will save the changes
Case vbCancel:
Cancel = True
End Select
End Sub
Private Sub Form_Error(DataErr As Integer, Response As Integer)
If DataErr = 2169 Then
Response = acDataErrContinue
End If
End Sub
Private Sub Form_Load()
LoadBeneficiaryDetails
End Sub
Private Sub Form_Unload(Cancel As Integer)
If blnAction = vbCancel Then
blnBeenThereDoneThat = False
Cancel = True
End If
End Sub
Private Sub btCancel_Click()
If Me.Dirty Then
Form_BeforeUpdate (0)
End If
If blnAction = vbCancel Then
blnBeenThereDoneThat = False
Exit Sub
ElseIf blnAction = vbYes Then
DoCmd.Close
Else
DoCmd.Close
End If
End Sub
Private Sub btSave_Click()
If Me.Dirty Then
Form_BeforeUpdate (0)
End If
If blnAction = vbCancel Then
Exit Sub
Else
DoCmd.Close
End If
End Sub