MS ACCESS 2007
VBA CODE BUILDER
I am able to show a MsgBox in VBA code when a Tab is selected with
Private Sub TabCtl34_Change()
If Me.TabCtl34.Value = 1 Then 'First Page
MsgBox "Hi"
End If
End Sub
But I also want to check if the second tab is selected and a field(Name) on the form IS NULL (not on tab), msgbox or cancel event to require Name to be entered before they see the second tab.
When I add in:
Private Sub TabCtl34_Change()
If Me.TabCtl34.Value = 1 AND [FORMS]![FORMNAME]![NAME] IS NULL Then
MsgBox "Hi"
End If
End Sub
It just goes directly to the second tab even if the name is null. How do i write the vba code so it can do what I want?
IS NULL is for use in query expressions, from VBA use the IsNull() VBA function.
If Me.TabCtl34.Value = 1 AND IsNull([FORMS]![FORMNAME]![NAME]) Then
As you are running this from the form's module you can use Me to refer to the current form-instance:
If Me.TabCtl34.Value = 1 AND IsNull(Me.[NAME]) Then
You should also consider that the value may be an empty string, rather than NULL. You can combine both checks using:
If Me.TabCtl34.Value = 1 And Len(Me.[NAME].Value & "") = 0 Then
Concatenating the empty string "" coerces a NULL value to a string.
(It is preferable to explicitly identify the property Value rather than assume it as the default property.)
Related
I am trying to create a function that will allow me to use various command buttons without having to recreate the code every time.
To do this I have to pass the form name through a function
Function:
public Function NewRecord(controlForm, focusForm)
focusForm.SetFocus
DoCmd.GoToRecord , , acNewRecord
controlForm.SetFocus
controlForm - This is the main form akin to the Me function
focusForm - This is for not only the main form but when I create subforms I have to have the focus on the subform to have the command work.
To call the function I did the following:
public sub Command19_Click()
Dim controlForm
Dim focusForm
Set controlForm = Forms![frm_Sales_CustomerProfile]
Set focusForm = Forms![frm_Sales_CustomerProfile]
Call NewRecord(controlForm, focusForm)
End Sub
I get this error that States: Compile Error: Invalid Use Of Property.
You got trapped using an already in this context (the form) used identifier and not using a strong name (NameOfLibrary.NameOfFunction).NewRecordis a forms property, soInvalid Use Of Propertymakes sense. If you useMyModulName.NewRecord(frm1,frm2)everything is fine. If you useNewRecordin Module òr Class it works too as there is no property with same name (I assume;-)).
To be honest, I don't use strong names either (except on database or recordset objects, as I got trapped there too, assuming DAO, using ADODB), but the Pros suggest that and now we know why!
Your function should have just one argument as it is sufficent to pass only the subforms reference if you need that form NewRecord(frm as Access.Form) (note the strong name!). You can easy refer to the mainform with Set mfrm = frm.Parent
Your code;
Public Function FrmNewRecord(frm As Access.Form)
frm.Recordset.AddNew
End Function
Public Sub Command19_Click()
FrmNewRecord(Forms![frm_Sales_CustomerProfile]) ' mainform
FrmNewRecord(Forms![frm_Sales_CustomerProfile]!sfrmControl.Form) ' subform
End Sub
You are passing the same form two times in your code, any reason? If Forms[frm_Sales_CustomerProfile] contains Command19 use Me.
I dropped the .SetFocuspart as not necessary or any reason to for setting focus? Why is NewRecord a function? Doesn't return anything.
btw: I am working on aSubForms(frm)function , that returns a collection of all subforms.
Code:
'SubForms(frm As Access.Form) returns a collection of all subform references in frm
Public Function SubForms(frm As Access.Form) As VBA.Collection
Dim ctr As Access.Control
Dim sfrm As Access.Form
Dim col As New VBA.Collection
For Each ctr In frm.Controls
If ctr.ControlType = acSubform Then
On Error Resume Next
Set sfrm = ctr.Form
If Err.Number = 0 Then
col.Add sfrm, sfrm.Name
End If
On Error GoTo 0
End If
Next ctr
Set SubForms = col
End Function
As a general rule to build say custom menu bars, or ribbons, you can write code that is “form” neutral like this:
Public Function MyDelete(strPrompt As String, strTable As String)
Dim strSql As String
Dim f As Form
Set f = Screen.ActiveForm
If MsgBox("Delete this " & strPrompt & " record?", _
vbQuestion + vbYesNoCancel, "Delete?") = vbYes Then
So note how we don’t need to pass the form name at all – the above code simply picks up the active screen as variable “f”.
At that point you can do anything as if the code was inside the form.
So
Me.Refresh (code inside the form)
Becomes
f.Refresh
So the key concept here is that you don’t need to pass the current active form since screenActive form will enable you to get the current form object anyway.
However, for sub forms and “common” type of code the above falls apart because screen.ActiveForm will return the main form, and not the sub form instance.
So as a second recommended approach, simply always pass the current context form object “me” like this:
Call MySub(me)
And you define your sub like:
Sub MySub(f as form)
Now in this code we can reference "anything" by using "f" in place of "me"
f.Refresh
So just pass “me” if you ever use sub forms. Given the above information, then your code becomes:
public sub Command19_Click()
Call NewRecord(me)
End Sub
And NewReocrd becomes:
Sub NewRecord(f as form)
Now in your newreocrd code, you can use “anything” form the object such as:
f.Name ' get name of the form.
or
City = f.City ' get value of city control
So pass the “whole” form context.
And you could say make a routine to display the City value for any form like:
Call ShowCity(me, "City")
And then
Sub ShowCity(f as form, strControlToShow as string)
Msgbox "City value = " & f(strControlToShow)
So OFTEN one will write code that works for any form by simply picking up the current active form as:
Dim f As Form
Set f = Screen.ActiveForm
And note how the above code picks up right away the active form – this is a good idea since then if focus changes, the “f” reference will remain intact for the code that follows in that “general” routine that is called + used from many forms.
However due to the sub form issue, then often it simply better to always pass the “whole” forms instance/object with:
Call MyNewRecord(me)
And then define the sub as:
Sub MyNewReocord(f as form)
DoCmd.GoToRecord acDataForm, f.Name, acNewRec
End Sub
And you could optional add “focus” to above with
f.SetFocus
So for a lot of menu or ribbon code, you don't pass the form object, but simply use screen.ActiveForm, and you can also use Screen.ActiveControl (again great for menu bar or ribbon code to grab what control has focus). However due to sub form limitations, then often passing "me" to the routine will achieve similar results if not better in some cases.
I'm a newcomer to Access trying to cobble things together from helpful information I've found here.
I have a form that needs to populate the fields based on a combo box selection in the form header. The form is based on an underlying query with the following criteria for field "StudID" [Forms]![frmStudConsentUpdate]![cmbStud] where cmbStud is my combo box. The combo box pulls in StudID, StudFN, StudLN with StudID as the bound columnn. The after update event requeries the form (Me.Requery). This works beautifully, but only if I first open the form in design view, open the Record Source, and save it. I don't make any changes at all, but once I've done this the form works. Otherwise, nothing happens when I select a student in the combo box. Any thoughts on what I need to do to make this work without having to re-save the underlying query?
This is old bug in MS Access, I have no idea why they still didn't fix it:
If underlying form's query has in criteria form's control and the form was filtered once (at start or manually/using VBA), it doesn't accept new values from form's control and uses old value.
Workaround: create public function, which returns control's value and use it in criteria instead of [Forms]![frmStudConsentUpdate]![cmbStud]. You will need to create function for each control or use this function:
Public Function GetControlValue(strFormName As String, strControlName As String, Optional strSubFormControlName As Variant, Optional varDefault As Variant) As Variant
' Returns : Variant, value of control in form/subform
' Comments:
' Params :
' strFormName
' strControlName
' strSubFormControlName
' varDefault - value returned if control is not accessible
'----------------------------------------------------------------------------
On Error GoTo ErrorHandler
If IsMissing(strSubFormControlName) Or Nz(strSubFormControlName, "") = "" Then
GetControlValue = Forms(strFormName).Controls(strControlName).Value
Else
GetControlValue = Forms(strFormName).Controls(strSubFormControlName).Form.Controls(strControlName).Value
End If
ExitHere:
On Error Resume Next
Exit Function
ErrorHandler:
If Not IsMissing(varDefault) Then
GetControlValue = varDefault
End If
Resume ExitHere
End Function
In criteria use function call GetControlValue("frmStudConsentUpdate","cmbStud") instead of [Forms]![frmStudConsentUpdate]![cmbStud]
In your afterupdate for your cmbStud combobox, create code that refreshes the recordsource to
me.recordsource = "SELECT * FROM {yourQueryName} WHERE StudID = '" & me!cmbStud & "'"
I been working on the following code to when the user click on the button to save and go new record that Access locates the highest client id used by set location and then adds 1 to it. Prior to saving the record and moving on to new record. While work through other errors, but I can not get past error object required on this line. "Me.ClientID = IIf(DMax("[ClientID]", "tClientinfo", "[CorpsName]=" & "'defaultcorps'") Is Null, 0, DMax("[ClientID]", "tClientinfo", "[CorpsName]=" & "'defaultcorps'")) + 1"
The more i look at the similar questions more confused I get as to what is wrong with the code. Thank you in advance for any suggestions David
Private Sub Save_Record_Click()
'declare variables for default values
Dim defaultinterviewr As String
Dim defaultcorps As String
'Variables get their values
defaultinterviewr = Me.Interviewer.Value
defaultcorps = Me.Corps.Value
'Check to see if ClientID field is Blank.
If IsNull(Me.ClientID) Then
'Check that Corps field is filled in
If IsNull(Me.Corps) Then
MsgBox "Corps must be entered before saving record.", vbOKOnly
Me.Corps.SetFocus
'set client id base on corps by finding the highest id and adding 1 to that number
Else
Me.ClientID = IIf(DMax("[ClientID]", "tClientinfo", "[CorpsName]=" & "'defaultcorps'") Is Null, 0, DMax("[ClientID]", "tClientinfo", "[CorpsName]=" & "'defaultcorps'")) + 1
End If
End If
MsgBox "Done", vbOKOnly
'save record
'DoCmd.RunCommand acCmdSaveRecord
'Me.stateidnum1 = ""
'open new record
'DoCmd.GoToRecord , , acNewRec
'set field default value
'Me.Interviewer.Value = defaultinterviewr
'Me.Corps.Value = defaultcorps
'Me.Child_Subform.Form.AllowAdditions = True
End Sub
I think you need to start off by figuring out if your DMAX() statement is correctly producing results. The next thing I see and which is probably your main culprit is the fact that you are using the Expression IIf() inside VBA. The IIf() expression you are using will work inside a query or in a textbox but VBA has it's own If statement block which you are correctly using in the lines preceding it.
I would actually use the Nz Function to simplify it even more as follows:
UPDATED Based off of your comment below I re-looked at your overall code and noticed that "defaultcorps" is a variable and not a value I originally thought you were trying to filter by. You were wrapping the variable in quotes. My updated answer should work for you.
Me.ClientID = (Nz(DMax("[ClientID]", "tClientinfo", "[CorpsName]= '" & defaultcorps & "'"),0)+1)
when double clicking on a value i need to open a form. the value gets passed to the opened form. I want the form to directly filter on that value instead of pushing on a button first. i tried filtering on change and on load but it doesn't work. when loading it doesn't know the value because it gets added after it opened the form.
this is the code for passing the value:
DoCmd.OpenForm "SubmenuRubrieken", acNormal
Forms!SubmenuRubrieken.Tv_rubrieknaam.Value = Me.Tekst14.Value
this is the code for filtering on that value in Tv_rubrieknaam:
Dim filter As String
filter = ""
If Not IsNull(Tv_rubrieknaam) Then filter = filter & " AND rubrieknaam = '" & Tv_rubrieknaam.Value & "'"
Me.filter = Right(filter, Len(filter) - 5)
Me.FilterOn = True
for some reason it doesn't trigger the filter on changing the value of Tv_rubrieknaam. how do i need to solve this?
I guess, the Form_Load() event is finished before you set the value (OpenForm is performed before value is set), so you would have to do the filtering in the OnChange() event of the Textfield or similar.
Better: pass the Me.Text14.Value with the DoCmd.OpenForm command either as a prepared whereCondition OR as OpenArgs with filtering option in the On_Load event.
A basic example:
I have a Form1 with a TextBox called Text0 on it. Text0 has a value of 2.
I have a Form2 with a Table called Table1 as Recordsource. Table1 has a column called Field1 containing numbers between 1 and 3
All I need to do is add the following code into the module of the Form1 and the moment I click on Text0 Form2 will be openend filtered down to rows with Field1 = 2
Private Sub Text0_Click()
DoCmd.OpenForm "Form2", acFormDS, , "Field1 = " & Nz(Me!Text0, 0)
End Sub
Such a simple question, but I cannot find the answer (Google, MS help, SO):
How can I check by VBA whether an unbound checkbox on an Access form is checked by the user or not? Can't find the right property.
UPDATE:
I used this code after the suggestions of #HansUp and #RC:
Private Sub CmdTest_Click()
MsgBox "Check1.Value = " & Me.Check1.Value
MsgBox "Check2.Value = " & Me.Check2.Value
End Sub
Private Sub Form_Load()
Me.Check1.Value = 25
Me.Check2.Value = 50
End Sub
2nd UPDATE:
The code should be this (thanks to #David-W-Fenton):
Private Sub CmdTest_Click()
If Me.Check1 = True Then
MsgBox "Check1 IS CHECKED"
Else
MsgBox "Check1 IS NOT CHECKED"
End If
If Me.Check2 = True Then
MsgBox "Check2 IS CHECKED"
Else
MsgBox "Check2 IS NOT CHECKED"
End If
End Sub
Private Sub Form_Load()
' set first checkbox default checked
Me.Check1.Value = True
' set second checkbox default unchecked
Me.Check2.Value = False
End Sub
Checkboxes are a control type designed for one purpose: to ensure valid entry of Boolean values.
In Access, there are two types:
2-state -- can be checked or unchecked, but not Null. Values are True (checked) or False (unchecked). In Access and VBA, the value of True is -1 and the value of False is 0. For portability with environments that use 1 for True, you can always test for False or Not False, since False is the value 0 for all environments I know of.
3-state -- like the 2-state, but can be Null. Clicking it cycles through True/False/Null. This is for binding to an integer field that allows Nulls. It is of no use with a Boolean field, since it can never be Null.
Minor quibble with the answers:
There is almost never a need to use the .Value property of an Access control, as it's the default property. These two are equivalent:
?Me!MyCheckBox.Value
?Me!MyCheckBox
The only gotcha here is that it's important to be careful that you don't create implicit references when testing the value of a checkbox. Instead of this:
If Me!MyCheckBox Then
...write one of these options:
If (Me!MyCheckBox) Then ' forces evaluation of the control
If Me!MyCheckBox = True Then
If (Me!MyCheckBox = True) Then
If (Me!MyCheckBox = Not False) Then
Likewise, when writing subroutines or functions that get values from a Boolean control, always declare your Boolean parameters as ByVal unless you actually want to manipulate the control. In that case, your parameter's data type should be an Access control and not a Boolean value. Anything else runs the risk of implicit references.
Last of all, if you set the value of a checkbox in code, you can actually set it to any number, not just 0 and -1, but any number other than 0 is treated as True (because it's Not False). While you might use that kind of thing in an HTML form, it's not proper UI design for an Access app, as there's no way for the user to be able to see what value is actually be stored in the control, which defeats the purpose of choosing it for editing your data.
Check on yourCheckBox.Value ?