Assiging a 'User Stamp' when saving a record - ms-access

So the first thing is that every table has 4 fields. Created_By, Created_Date, Last_Updated_By and Last_Updated_Date. This will allow me to keep a track of who saved what records and when. I want a public sub (or function?) to update these fields when any record is saved.
Ideally I don't want to have to copy/call my code from every form, but I will if that's what is necessary. I imagine there is a way of doing this globally.
I currently have the following:
Public gLoggedIn As Integer
Public Function get_global(Global_name As String) As Variant
Select Case Global_name
Case "Employee_ID"
get_global = gLoggedIn
End Select
End Function
My next thing is to add vba code to fill the 2 of the 4 fields. The following is something I have in one of my forms, but like I say, I want to able to achieve this globally on every save.
Private Sub Form_BeforeUpdate(Cancel As Integer)
If Me.NewRecord = True Then
Me.[Created_By] = gLoggedIn
Me.[Created_Date] = Now()
Else
Me.[Last_Updated_By] = gLoggedIn
Me.[Last_Updated_Date] = Now()
End If
End Sub
How can I do this globally?
I'm not sure if 'me' is the correct reference to us if this is global?

Exactly for your demand, you could use a VBA modul with following sub
Public Sub setTimestamp(objForm As Form)
If objForm.NewRecord = True Then
objForm![Created_By] = gLoggedIn
objForm![Created_Date] = DateTime.Now
Else
objForm![Last_Updated_By] = gLoggedIn
objForm![Last_Updated_Date] = DateTime.Now
End If
End sub
You need to call this method in every form when the Timestamp Update should be fired (BTW: I would recommend an event when a save button is clicked or field update, because an edit in the dataset of the form at form update event will probably cause another form update event and could lead to an endless loop).
call setTimestamp(Me)
But you should alternatively consider using a macro like #E Mett said in comment.
Another hint: If you set the variable gLoggedIn to public, you can refer directly without using a function. (You did this even in your example) A function makes sense when you want to hide the variable inside a modul as private. This is called encapsulation, if you want to learn more about it.
EDIT
Changed code by andre451 ' s suggestion.

Related

MS Access VBA, efficient way to enable a button only after all required textboxes contains valid data

My code is working, but I just want to know if there is a more efficient way to achieve the same effect.
I have this layout in a form:
In my effort to foolproof the record creation process, I would like to have the "Save and Clear fields" button enabled only after all but the 'Comment' textbox/combobox contains some valid data.
The text/combo boxes are called txtBatteryID, cmbModelNumber, cmbChemistryType, txtSpecVoltage, txtSpecCapacity.
My code is as follow
Private Sub EnableSaveBtnCheck()
'this checks if the required fields contains valid data, if so, enables the save button.
If Me.btnSaveAndCLear.Enabled = False Then
If IsNull(txtBatteryID) = False And IsNull(cmbModelNumber) = False And IsNull(cmbChemistryType) = False And IsNull(txtSpecVoltage) = False And IsNull(txtSpecCapacity) = False Then
Me.btnSaveAndCLear.Enabled = True
End If
End If
End Sub
As you can see, I did the most straightforward way of using AND to combine all must-have conditions in an IF statement. This sub is called in After_Update() event of each text/combo box. Like this:
Private Sub cmbChemistryType_AfterUpdate()
Call EnableSaveBtnCheck
End Sub
My question, in the end, is: Is there a more efficient way to setup the condition "all text/combo box need to have something valid in them"? And is there a more elaborate way to check if the condition is met (something like a event on the form itself)?
Add the values of those 5 fields. If any of them is Null, the sum will be Null. So you only need call IsNull() once.
If IsNull(txtBatteryID + cmbModelNumber + cmbChemistryType + txtSpecVoltage + txtSpecCapacity) = False Then

VBA Add combo box values together

I have 3 combo boxes that contain numbers:
Me.Authorized
Me.Officer
Me.Enlisted
What I'm trying to do is add the values of Me.Officer and Me.Enlisted and make sure it equals Me.Authorized. I have all the other statements/commands figured out, but I can't wrap my head around this one.
The combo box selected value is a string, even when that string contains only digits. You can use Val() to convert that string to a number.
So your required condition can be expressed as ...
Val(Me.Officer) + Val(Me.Enlisted) = Val(Me.Authorized)
You can enforce that requirement in the form's Before Update event ...
Private Sub Form_BeforeUpdate(Cancel As Integer)
If (Val(Me.Officer) + Val(Me.Enlisted) <> Val(Me.Authorized)) Then
MsgBox "Officer plus Enlisted must be equal to Authorized."
Cancel = True
End If
End Sub
That event procedure will abort a record save when your requirement is not satisfied.

VBA code that changes background color of form conditionally by answer

I want to use VBA (or some other solution) to conditionally change the background color of a form based off what number users enter in a numeric field. Basically, after they enter their answer to the Starter question, if they entered 1 then I want the form background to change to a specific shade of blue, and if they entered 2 then I want the form background to change to a specific shade of green. I saw a code that looks like it would be very similar to my need in another question on here, but I couldn't figure out how to make the code work, and was having trouble figuring out exactly how/where to put each module.
Some information:
The field I want it to be based off of is numeric, called Starter, and through data validation users are limited to entering 1, 2, 9, or leaving it blank. I only want the color to change if it's entered as 1 or 2.
I'm using Access 2010
the form has neither header nor footer
the code I was attempting to use and made some alterations to is the following:
Private Sub Form_AfterUpdate()
blue_yes = "15325906"
green_no = "13888226"
Dim colorThis As String
booWhatever = Me.Starter ''Use of the variable can prevent problems
If booWhatever = 1 Then
colorThis = "blue_yes"
End If
If booWhatever = 2 Then
colorThis = "green_no"
End If
subFrm.Form.Section(acDetail).BackColor = colorThis
subFrm.Form.Repaint
End Sub
I've also managed, off a very different piece of code, to sort of do what I want, but the way it's working it seems to change the status of all forms, not just the one I'm currently working with, which is the goal. So for example if I enter 2 to starter, it changes the background color of every single record's form.
Private Sub Starter_AfterUpdate()
If Me.Starter = "1" Then Me.Detail.BackColor = vbBlue
If Me.Starter = "2" Then Me.Detail.BackColor = vbGreen
End Sub
EDIT:
Welp, embarrassingly I found the solution. It's not a very neat one, but it works.
Private Sub Form_Current()
Dim Presence As String
Presence = Nz(Me.Starter.Value, 9)
Select Case Presence
Case "1"
Me.Detail.BackColor = 15325906
Case "2"
Me.Detail.BackColor = 13888226
Case Else
Me.Detail.BackColor = vbWhite
End Select
End Sub
Private Sub Starter_AfterUpdate()
Dim Presence As String
Presence = Nz(Me.Starter.Value, 9)
Select Case Presence
Case "1"
Me.Detail.BackColor = 15325906
Case "2"
Me.Detail.BackColor = 13888226
Case Else
Me.Detail.BackColor = vbWhite
End Select
End Sub
I know it is a really old question (probably you have already solved it in a better way) but I will give it a try anyways.
Try the following:
Private Sub Text0_Change()
Select Case Me.Text0.Text
Case ""
Case "1"
Me.Detail.BackColor = 15325906
Case "2"
Me.Detail.BackColor = 13888226
Case Else
Me.Detail.BackColor = vbWhite
End Select
End Sub
EDIT:
I tried that and it works I think now as it supposed to do.
When you change the text on the text box triggers this event every time, runs the Sub, checks it's own text and changes the color of the form as described.
The change is that I changed the property of the field it checks. From Value to Text. We want when the event triggers to check the current text because the Value property updates when you "finish" with the textbox (after you press enter or the focus on the control is lost) and we want the change to happen the same moment we press the key changing the value and not later.
The second change and the reason we got strange patterns before is that I have added one more Case when the text is "" to do nothing on that change (empty case). Without that case when we used delete or backspace to remove the text and left the textbox empty ("") then the case else was True and it changed the background color.
I hope this is the correct answer now. Please let me know!

ms access vba code I can disable a field based on content of another field, but my code to re-enable is not working

I have a simple form where I have a field InstrumentTypes_ID and a field DGLenders_ID.
When InstrumentTypes_ID equals "Mortgage" or "Modification", I want DGLenders_ID to stay enabled, but any other value should make DGLenders_ID become disabled.
I have the following code in an AfterUpdate for the InstrumentTypes_ID textBox, which to me seems would be sufficient to get this effect (However, when testing, I can type in "Warranty Deed" (or anything that's not "Mortgage" or "Modification"), which disables the DGLenders_ID field, but if I go back and update it with "Mortgage" or "Modification", it won't re-enable that field):
Private Sub InstrumentTypes_ID_AfterUpdate()
Me.DGLenders_ID.Enabled = True
If Me.InstrumentTypes_ID = "Mortgage" Then
Me.DGLenders_ID.Enabled = True
ElseIf Me.InstrumentTypes_ID = "Modification" Then
Me.DGLenders_ID.Enabled = True
Else
Me.DGLenders_ID.Enabled = False
End If
End Sub
You should try to put your code in a subroutine and call it on the current event of the form and in the lost focus event of the field.

Global Date Variable Works Only for Entered Values

I'm currently working on what should be a relatively simple database, which is very close to being at its end, until I hit the inevitable problem.
I'm using Global Variables and a Form to collect parameters to pass into the Criteria portion of a Query, which works just fine for the first two, which are basic strings and integers.
Then comes the dates, which work, so long as you chose a date from the DatePicker that is entered into the query.
For example, if the query field holds 6/1/2014, 6/3/2014, and 6/8/2014, and the date 6/5/2014 is picked, the form will crash and go blank, though if you pick 6/8/2014, it'll go on as it should.
I had tried a variety of different forms of the code, but in the most basic form I simple have:
Between Get_Global('GBL_Start_Date_ID') AND Get_Global('GBL_End_Date_ID')
I'm not sure if I should be limiting the DatePicker based on the values entered in the query, or if there's a more robust way of going about this, or maybe I just completely missed a simple checkbox.
EDIT
My code for the Global Variables looks like this:
Option Compare Database
Global GBL_Start_Date_ID As Date
Global GBL_End_Date_ID As Date
Global GBL_Customer_ID As Long
Global GBL_Engineer_ID As Long
Public Function Init_Globals()
GBL_Start_Date_ID = #6/1/2014#
GBL_End_Date_ID = #6/30/2014#
GBL_Customer_ID = 1
GBL_Engineer_ID = 1
End Function
Public Function Get_Global(gbl_parm)
Select Case gbl_parm
Case "GBL_Customer_ID"
Get_Global = GBL_Customer_ID
Case "GBL_Engineer_ID"
Get_Global = GBL_Engineer_ID
Case "GBL_Start_Date_ID"
Get_Global = GBL_Start_Date_ID
Case "GBL_End_Date_ID"
Get_Global = GBL_End_Date_ID
End Select
End Function
And I just add a simple line to the AfterUpdate event of the ComboBoxes and TextBoxes to assign the variable:
GBL_Engineer_ID = Me.EngineerSelection
Thanks in advance,
Aaron
You can do two things. Fix the query as it is written or make it much more robust.
To fix it as written
Between "#" & Get_Global('GBL_Start_Date_ID') & "#" AND "#" & Get_Global('GBL_End_Date_ID') & "#"
OR
change your Get_Global function
Public Function Get_Global(gbl_parm)
Select Case gbl_parm
Case "GBL_Customer_ID"
Get_Global = GBL_Customer_ID
Case "GBL_Engineer_ID"
Get_Global = GBL_Engineer_ID
Case "GBL_Start_Date_ID"
Get_Global = "#" & GBL_Start_Date_ID & "#"
Case "GBL_End_Date_ID"
Get_Global = "#" & GBL_End_Date_ID & "#"
End Select
End Function
You are correctly specifying that the values of GBL_Start_Date_ID and GBL_End_Date_ID are dates by using #s when you create them however when you use them in your query they appear without them. You can prove to yourself this is what is happening by typing ?#1/1/2014# into the immediate window. The date is printed as 1/1/2014 which when used in your query, makes Between 6/1/2014 AND 6/30/2014 which is a syntax error.
To make things all that much better you need to parameterize this part of your query. Change this
Between Get_Global('GBL_Start_Date_ID') AND Get_Global('GBL_End_Date_ID')
to this
Between pStartDate AND pEndDate
Before you call your query you need to do your usual checks: are either of these null? is pStartDate < pEndDate?
By performing these checks and parameterizing this you ensure that you never end up with a query like this. Calling your query means you need to need to populate the parameters with DAO or ADO.
Between AND