Can I make some fields on an Access form conditional? - vba

I am creating a database and I have a table where I am collecting if a patient has been or is currently on specific medications.
I have a list of 17 medications that we care about and have a yes/no checkbox for each one. If a patient is or has ever been on one of these medications we want to collect 9 additional fields.
I want to create a form that lists only the medications and checkboxes. When the user checks a checkbox I then want the additional fields to appear for them to fill out.
Most patients will have only been on 2-5 of these medications, so I don’t want to clutter the form with unnecessary blank fields.
Is there a way to do this without VBA? If no, will someone give me an example of what the VBA code should look like?
Thanks so much! We collect this data as part of an ongoing registry monitoring the long term safety of a specific research medication. We usually collect this data differently when the patient is in clinic however, in lite of the pandemic we need to do this via telephone and this database will be crucial in ensuring the continued collection of this vital data!!
Thanks,
Allen

What you can do is to rely on the fact that Yes/No fields are stored as 0 (False) and non-0 (True). You can then have a small piece of VBA code behind the form that adds all of the Yes/No fields to determine whether to display the additional text boxes or not:
Sub sCheckMedication()
On Error GoTo E_Handle
If (Me!Medication1 + Me!Medication2 + Me!Medication3) <> 0 Then
Me!txtMedicationNotes.Visible = True
Else
Me!txtMedicationNotes.Visible = False
End If
sExit:
On Error Resume Next
Exit Sub
E_Handle:
MsgBox Err.Description & vbCrLf & vbclf & "sCheckMedication", vbOKOnly + vbCritical
Resume sExit
End Sub
You would then call this procedure in the Form's Current event (to cover when the form is first loaded, and also when navigating between records), and also on the CheckBox's Click event:
Private Sub chkMedication1_Click()
Call sCheckMedication
End Sub
Regards,

Related

Combo Box selecting First Record and not the defined record

first time asking here because i'm stumped!
I have a MS Access Form with 2 combo boxes:
First combo box (cboPub) selects a Publisher which then filters the second combo box (cboTitle), this works fine however the pulled record is the first record and not the one that meets the criteria.
Code below:
Private Sub cboPub_AfterUpdate()
cboTitle = Null
cboTitle.Requery
End Sub
Sub cboTitle_AfterUpdate()
' Find the record that matches the control.
Me.RecordsetClone.FindFirst "[Supplier] = """ & Me![cboTitle] & """"
Me.Bookmark = Me.RecordsetClone.Bookmark
End Sub
I suspect it is because of the line here:
Me.RecordsetClone.FindFirst "[Supplier] = """ & Me![cboTitle] & """"
but i dont know what to change to have it select the correct record.
A common task is to filter the data in a form's details section from unbound combo boxes in the form header section. (don't set the comboboxs' data sources) I assume that is what you are trying to do because me in the afterupdate event refers to the form. If so set the forms filter rather than messing with the forms record source. Your second problem is cboTitle's afterupdate event doesn't fire when cbotitle's value is changed through vba code. So put all the code in cboPub.
Private Sub cboPub_AfterUpdate()
'cboTitle = dlookup("Title", "SomeTable", "SupplierID = " & cboPub.value) 'how I filtered cboTitle
Me.Filter = "SupplierID = " & cboPub.Value
Me.FilterOn = True
End Sub
Private Sub cboTitle_AfterUpdate()
Debug.Print "check the immediate window for how cboTitle's after update event does not fire when cboTitle is updated with VBA"
End Sub
warning: treat this as pseudo code; the exact filter depends on how Supplier, Publisher, and Title are related in your tables and combo boxes.
Explanation: I think the programmers behind access intentionally forced us to set up our forms entirely at design time. No matter what I have tried Access does not display runtime changes to it's record source in any acceptable fashion. It is the access way or the high way. Linking up your record source and form variables at design time then filtering is the only approach I have found that works. I assume the reasons behind why you cannot trigger an afterupdate event through code are similar.

MS Access 2019: How do I check for duplicate records before update, then run a specific procedure if duplicates are found?

I am very new to both StackOverflow and to doing any sort of advanced programming in MS Access. I created a database to catalog my trading card collection (Excel just wasn't cutting it since we're talking about over 2000 unique cards). At first it was just a simple table of records, but now it's turned into a full-fledged database that I have search forms for and queries and everything.
What I'm trying to do right now is streamline my process a bit, and there is something very specific that I want to make Access do. I'm almost certain that whatever I want to do will have to be done in VBA, and I'm just not familiar enough with it to do what I want.
What I want it to do is this: Any time a new record is entered, I want it to check the record before it saves the record into the DB (I'm fairly confident that I need to use the "Before Update" event for this) and make sure that the "Sort ID" field (an auto-calculated field I've created) contains no duplicates (I know I'll most likely have to use queries for this since auto-calculated fields can't be indexed). If the program detects a duplicate, I want it to produce a message box saying that I'm trying to enter a duplicate record and ask me if I want to update the "number owned" field of the existing record instead of creating a new one, and then take me to the record in question on an affirmative response.
What I currently have is a validation rule that uses an index (comprised of the fields that generate the Sort ID), which generates a custom error message by using the following VBA code in the "On Error" event:
Private Sub Form_Error(DataErr As Integer, Response As Integer)
Const conErrRequiredData = 3022
If DataErr = conErrRequiredData Then
MsgBox ("Duplicate Sort ID. Please update the 'number owned' field on the existing record instead.")
Response = acDataErrContinue
Else
Response = acDataErrDisplay
End If
End Sub
This code works exactly as it should, but I want more than a pop-up error that I can't do anything with. I have a query entitled "CheckDuplicateSortID" that I created using the Query Wizard, and it checks the "Sort ID" field for duplicates, but that's as far as I've managed to get. The example on This site is about the closest I've managed to find to what I'm looking for, but the code sample given is very difficult for me to understand because there's very little explanation with it; I'm not familiar enough with Access VBA to know which parts are important code and which parts are his specific field names and other variables; I haven't gotten any error messages because I'm stumped on even trying to figure out what needs to be changed from that sample code and what it needs to be changed to.
Edit: Just for the sake of clarification, the solution doesn't have to involve the Sort ID field. I created that so I'd have one field I can point the program to. But if it would be simpler to just use the index that I use for my current validation rules (with the error message generated by the above code), I'm open to that too.
After some considerable finagling, I actually managed to find a solution to this on my own, though it is probably needlessly complicated (I'm definitely open to simpler solutions, if anyone has any).
Rather than using the actual SortID field, I modified the code in the OP to this:
Private Sub Form_Error(DataErr As Integer, Response As Integer)
Dim strMsg As String
Dim iResponse As Integer
'The text to be displayed in the message prompt.
strMsg = "Unable to save record. The values you have entered would generate a duplicate." & Chr(10)
strMsg = strMsg & "Would you like to clear this form and edit the existing record instead?"
'Calls for the yes/no message prompt specifically when the no-duplicate
'validation rule is violated (error 3022).
Const conErrRequiredData = 3022
If DataErr = conErrRequiredData Then
iResponse = MsgBox(strMsg, vbQuestion + vbYesNo, "Invalid Sort ID")
Response = iResponse
If iResponse = vbYes Then
'Calls a custom function that opens the record in question for editing.
UpdateOnError
Else
'Cancels the operation on a negative response and does not clear the form.
Cancel = True
End If
Else
Response = acDataErrDisplay
End If
End Sub
As you can see from the above code, the event calls a custom function, which is coded as follows:
Function UpdateOnError()
On Error GoTo UpdateOnError_Err
Dim UpdateGoToID As Variant
'Selects the Sort ID in question for the purpose of opening the existing record.
UpdateGoToID = Forms![Card List Entry Form]!txtSortID
'Clears the invalid form.
DoCmd.RunCommand acCmdUndo
'Opens the existing record the user attempted to duplicate.
DoCmd.OpenForm "Card List Entry Form", acNormal, "", "[Sort ID]=" & "'" & UpdateGoToID & "'", , acNormal
UpdateOnError_Exit:
Exit Function
UpdateOnError_Err:
MsgBox Error$
Resume UpdateOnError_Exit
End Function
Like I said, this is probably a lot more steps than actually needed, but it does work as I want it to: when the user attempts to enter a duplicate record, an error message pops up asking if they would like to update the existing record. If yes, it takes them to the existing record. If no, it closes the error message without clearing the form or saving the record.

Error catching a form in Access using VBA

So i have a form that's updating a table in Microsoft Access. I'm using a BeforeUpdate event call to stop the form from updating if the 'first name' hasn't been filled in.
I basically only want the form to be saved once everything has been filled in, and then switch to see the updated table (the bit under If not cancel).
Currently the popup box to say 'You must enter a First Name' correctly fires, the next pop up box asking if the user wants to undo any changes fires. But then a pop up box saying 'No current record' appears and then the view changes to the table. I'm not sure why this is all happening.
Option Compare Database
Private Sub Form_BeforeUpdate(Cancel As Integer)
Cancel = False
' perform data validation
If IsNull(Me.customer_f_name) Then
MsgBox "You must enter a First Name.", vbCritical, "Data entry error..."
Me.customer_f_name.BorderColor = vbRed
DoCmd.GoToControl "customer_f_name"
Cancel = True
End If
If Not Cancel Then
DoCmd.SelectObject acTable, "ticket_tracker_table"
DoCmd.Requery
DoCmd.GoToRecord acDataTable, "ticket_tracker_table", acLast
End If
' if the save has been canceled or did not pass the validation , then ask to Undo changes
If Cancel Then
If MsgBox("Do you want to undo any changes?", vbYesNo, "Confirm") = vbYes Then
Me.Undo
End If
End If
End Sub
Review https://learn.microsoft.com/en-us/office/vba/api/Access.Form.BeforeUpdate(even)
Instead of GoToControl, use SetFocus.
I did a very simple test with the Undo question and it does work:
Private Sub Form_BeforeUpdate(Cancel As Integer)
If IsNull(Me.customer_f_name) Then
MsgBox "Must enter customer name."
Cancel = True
If MsgBox("Do you want to undo edits?", vbYesNo) = vbYes Then Me.Undo
Me.customer_f_name.SetFocus
End If
End Sub
Suggest you put table code in AfterUpdate event.
so to supplement J7, with some big picture view: "basically only want the form to be saved once everything has been filled in" …. that is swimming against the tide; which is why you are having to write a lot of code. The product enters data as you go fundamentally. that is it's core design.
it is very normal to do field checks as you go - typically in the AfterUpdate event, the check code is applied and if invalid - generate a message box and invoke an Undo plus reset the focus back to the field they were attempting to leave.
A totally different design, in some cases it may justify a temp local duplicate table just for the purposes of holding form input data - - this approach allows a very elaborate check(s) against data in the production database; where upon if valid an Append Query then writes the data into the permanent table.

Using For Loop to Check for duplicates - Error The error is: Object reference not set to an instance of an object

I have a problem that I and my limited experience cannot figure out.
I have a multi-display (form) program that is for a game show system which uses a (5) display system. As I am wrapping this project up, I have been doing some house keeping and handling some potential user errors up front.
In this instance: There is a form called GameSetup which has drop down menus that are filled via a database selection of "Teams". When a Team is selected, (10) labels are populated with registered team members. The user drags and drops a team member (ie. player) to a group of (6) labels, which will make up the active team for the game.
The problem: I wanted to have a check when a name is added to the active team roster to make sure there are no duplicates. The cleanest way to do this, I thought, would be on the .TextChanged action of the active player label and use a For loop to check the other active team player names.
Private Sub lblT1_P1_TextChanged(sender As Object, e As EventArgs) Handles lblT1_P1.TextChanged
cmdReady.BackColor = Color.Yellow
For i = 1 To 6
If i = 1 Then
' Do nothing
ElseIf Me.Controls("lblT1_P" & i.ToString).Text = lblT1_P1.Text Then 'This is the line triggering the NullException
MsgBox("This Player is already selected. Please choose another Player", MsgBoxStyle.OkOnly)
Me.Controls("lblT1_P" & i.ToString).Text = "DRAG PLAYER HERE" 'This is the other line triggering the NullException
End If
Next i
End Sub
i = 1 Do Nothing is so that it wont compare against itself (in this instance)
When I run the program (de-bug), before the form GameSetup loads, I am getting a Null Exception, which makes sense as it is looking at a form or an object in a form that is not yet initialized. Clearly, the Me.Controls is the problem, but I do not know how to handle using the integer (i) in the For Loop otherwise.
The label names are lblT1_P1 - lblT1_P6 (3 instance of each group (T1/T2/T3). I'm only dealing with T1_P1 at the moment.
Any suggestion would be greatly appreciated.
Use string.Format() to generate your control names, because it is more readable.
Instead of Me.controls("lblName").Text
use DirectCast(Me.FindControl("lblName"), Label).Text

display searched data in listbox in vba

I am new to VBA coding..
help me in this situation..
I have a table like in sheet 1
Data table
& the user-form is like
User form
I need to display the searched data in this list-box...my logic which i have tried...
1) a variable which holds the text-box value
2) 1st tried with advanced filter but its not working
3) then tried with find function it also shows error..
I have tried but it does not display in list-box...it is my first working with list-box...thanks in advanced....
The details might well vary between Access and Excel, and the version of those tools ... I happened to use Access 2000 for this example.
In case you're not sure how to see what an icon is named: float the mouse cursor over it.
I opened the form in design view
I activated a toolbar that had the "Toolbox" icon
I selected "List box"
I clicked on the form and dragged a box shape. This made a caption box containing "List1:" and also a list box
I changed the caption to whatever matches the table I plan to use, which is "tblDomainName" hence "Domain Name:"
I opened up the properties for the list box and clicked in the "Row Source" area.
I typed "SELECT DomainName FROM tblDomainName ORDER BY DomainName" based on the table planned to use, so if your table were named "Stuff" then you'd type what's inside the double-quotes, here: "SELECT [Name] FROM Stuff ORDER BY [Name]" ... notice the square brackets in case "Name" is a reserved word that might cause confusion otherwise.
I changed to form "view" mode and clicked through the various values. They matched what's in my table, and they were sorted besides. Yay!
So, the above gets the list box basically working and gets you past your first hurdle ... as I understand it to be.
What's next? As to how you use that list box, and the selected value, to your benefit .... that depends on what the big picture is, so feel free to elaborate.
Does this help?
~Tanya
can you please show your codes you have tried? I'm sorry if I can't just comment on your question coz I'm still lacking in reputation. Thanks!
Please Try this code below:
Private Sub cmdSearch_Click()
Dim ws As Worksheet
Dim numRow As Integer
Dim found As Boolean
Set ws = ThisWorkbook.Worksheets("display")
For numRow = 1 To (ws.Range("A" & ws.Rows.Count).End(xlUp).Row)
If nameTxtBox.Value = ws.Range("A" & numRow).Text Then
nameList.AddItem (ws.Range("A" & numRow).Value)
prodList.AddItem (ws.Range("B" & numRow).Value)
saleList.AddItem (ws.Range("C" & numRow).Value)
found = True
Exit For
End If
Next numRow
If found = False Then
MsgBox "No Match Found!", vbCritical
nameList.Clear
prodList.Clear
saleList.Clear
End If
End Sub
userForm screen shot
Spread Sheet Screenshot:
hope this is what you want to do!
Thanks!