Combo Box selecting First Record and not the defined record - vba

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.

Related

Access button to open multiple reports depending on user input

I am new to access so this might be an easy task or I am just trying to tackle it wrongly. I have a report that has various columns, sample id, sample time, sample type, dry matter, moisture. I am trying to create a button that has an input box for the user to chose what column to sort the report by. So far I thought of creating various reports that have been sorted by each column, named the reports by the column that sorts them then I am trying to have the open report action have a parameter that opens the report linked to the column entered at the input box. Is this even possible or is there a workaround for this.
PS. I am avoiding creating various buttons since it will fill up the screen.
Okay, this is pretty generic and will require some tweaking but it shows the core of how to do this.
To start with you need a module (so not form/report code). This is where the globals will be assigned values:
Option Compare Database
Option Explicit
Global rptname As String
Global fldname As String
Sub setRptName(name As String)
rptname = "Report Sorted by: " & name
fldname = name
End Sub
You will call that code inside the Click() event of your command button on your form and then open the report after that. This will take a combo box value and pass that value to the module code, creating the two global variables.:
Private Sub cmd_report_Click()
mdl_Globals.setRptName Me.cmb_fields.Value
DoCmd.OpenReport "Report1", acViewPreview
End Sub
I'm unsure if this will work with non-preview views, but you probably want preview anyway.
Lastly in the report code behind, you need the Load() and open() events, you may be able to get it to work with both inside one or other but I know this one works.
So to set the caption:
Private Sub Report_Load()
Me.lbl_header.Caption = rptname
End Sub
And then to sort:
Private Sub report_open(Cancel As Integer)
Me.Report.OrderBy = "[" & fldname & "]"
Me.Report.OrderByOn = True
End Sub
If your entry box on the form does not have entries that exactly match the name(s) of the fields in the table you will get a parameter popup.

Can I make some fields on an Access form conditional?

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,

Excel VBA: How to create event handlers for dynamically generated controls within an active userform?

I’m struggling with handling controls that are dynamically added during runtime to a pre-existing, active userform.
The userform is called “SalesInvoices” and initially contains a 10x8 grid of Textbox and ComboBox fields (controls). These have been created within the design mode, along with a few command buttons.
After the userform is launched, the user can add and delete additional rows by clicking the appropriate buttons. The userform remains active throughout, and the original 10x8 grid cannot be removed by the user.
Aesthetically, adding, deleting, moving and resizing the controls and the containing frame all work as intended.
The issue I’m facing is with assigning event handling procedures to the additional controls.
WithEvents doesn’t appear to be useful in this scenario as I require the BeforeUpdate and AfterUpdate events to validate the entries made by the user.
As such, I’ve resorted to programmatically inserting and removing the requisite event handling procedures as and when the user adds/deletes additional rows.
However, whilst my code appears to place the additional procedures accordingly, the event handlers are not triggered by the corresponding controls.
For example, here is a snippet dealing with the addition of a single control, Net_Amount11:
Private Sub AddLineButton_Click()
Dim new_item_no As integer
Dim new_NetAmount As Control
Dim LineNum As Integer
Dim DynamicUserForm As Object
new_item_no = 11
Set new_NetAmount = Me.Controls("Frame6").Add("Forms.TextBox.1", "Net_Amount" & new_item_no, True)
With new_NetAmount
.Left = 25
.Top = 50
.Width = 50
.Visible = True
End With
Set DynamicUserForm = ActiveWorkbook.VBProject.VBComponents("SalesInvoices")
With DynamicUserForm.CodeModule
LineNum = .CountOfLines + 1
.InsertLines LineNum, _
"Private Sub Net_Amount" & new_item_no & "_AfterUpdate()" & Chr(13) & _
"Call validate_net_amount_SI(" & new_item_no & ")" & Chr(13) & _
"End Sub"
End With
End Sub
This code creates the additional control in Frame6 of the active UserForm, SalesInvoices, and it inserts the event handling procedure into the code section of that userform.
But, when I update the value in the newly created Net_Amount11 TextBox, the event handler is not triggered nor is the procedure validate_net_amount_SI called. (Note that the userform is active throughout).
No errors are reported by the Editor.
I’m all out of ideas and would be grateful for some assistance. Hopefully I’ve missed something simple.
I did wonder whether this was because the inserted code needs to be compiled before it becomes operable (is this even possible on the fly without affecting the contents of the active userform?). Or perhaps there is some mismatch between the temporary nature of the new TextBox control and the permanent code relating to the userform. I couldn't find a solution either way.

Changing Textbox.DefaultValue in Access

I would like to be able to change the Textbox.DefaultValue during the 'On Load' event of a form such that each time the form is loaded the user is prompted with an InputBox to change a specific TextBox.Default value which in my case the TextBox control on the table is called Stream. I have tried the following code but each time it gives me a
'RunTime Error 3422 Cannot modify table structure. Another user has
the table open'.
Private Sub Form_Load()
CurrentDb.TableDefs("Class 1 Students (C1)").Fields("Stream").DefaultValue = InputBox("Enter Stream Letter:")
End Sub
I am using Microsoft Access
As Doug Glancy said in a comment, don't change the field's default value in table design. Instead change the text box's default value.
This is a critical point in a multi-user database application --- you wouldn't want one user stomping on another's default value choice. But, even if this will always be a single-user application, changing the table design means you can't have the table open in the record source of your form.
Changing the text box default value is easy. I added an unbound text box, txtDefaultStream, to my form's header. And, in its after update event, I change Me.txtStream.DefaultValue. The code is below.
Here is a screenshot of that form in action. I had A as the default when entering the first 2 rows. Then entered B in the default stream text box. Notice the new record has B in its Stream text box.
Private Sub txtDefaultStream_AfterUpdate()
Dim strDefault As String
If Len(Trim(Me.txtDefaultStream & vbNullString)) > 0 Then
strDefault = """" & Me.txtDefaultStream.value & """"
Me.txtStream.DefaultValue = strDefault
Else
Me.txtStream.DefaultValue = vbNullString
End If
End Sub
As Doug Glancy said, use the textbox, so you should try
Private Sub Form_Load()
Me.AText.DefaultValue = "='S'"
End Sub

In Access form with disconnected ADO recordset, filter only works one time

Thanks to a great answer to a previous question (thanks Hansup and Remou), I've made an Access form based on a ADODB recordset that pulls at runtime. This enables it to have a checkbox that is only in memory. The checkbox is fine.
I've now been asked to add a drop-down filter by "Client" to the form. Easy enough. I made the drop-down box, made a little query for the control source, and in the After_Update event, added this code:
Private Sub Combo_PickClient_AfterUpdate()
Me.Filter = "Client='" & Combo_PickClient.Value & "'"
Me.FilterOn = True
Me.Refresh
End Sub
For testing purposes, I chose 2 clients. When I open the form, it shows both client's data (good). When I pick one client, it successfully filters the data (also good). When I pick the second client, it does nothing (not so good)
Why does this filter only work one time? It doesn't throw any error. The screen simply refreshes and that's it.
My best guess is that Access tries to reload the form's recordset from the data provider when you attempt to modify or remove a non-empty .Filter property. Since the disconnected recordset doesn't have a provider, that attempt fails. In my testing, I actually triggered error #31, "Data provider could not be initialized" at one point.
In your first attempt (which succeeded), the .Filter property was empty beforehand. I saw the same behavior and I'm guessing Access can apply a .Filter to an unfiltered recordset without revisiting the data provider.
Sorry about the guesswork. Unfortunately, that's the best I can offer for an explanation.
Anyway, I gave up trying to use the form's .Filter property to accomplish what I think you want. I found it easier to simply reload the disconnected recordset based on a query which includes your .Filter string in its WHERE clause. The code changes were minor, and the run time performance cost is neglible ... the reloaded recordset is displayed instantaneously after changing the combo box selection.
First I moved the code which builds the disconnected recordset from Form_Open to a separate function whose signature is ...
Private Function GetRecordset(Optional ByVal pFilter As String) _
As ADODB.Recordset
The function incorporates a non-empty pFilter argument into the WHERE clause of the SELECT query which feeds the disconnected recordset.
Then I changed Form_Open to one statement ...
Set Me.Recordset = GetRecordset()
So, if your combo box and disconnected recordset are both on the same form, the combo's After Update procedure could be ...
Private Sub Combo_PickClient_AfterUpdate()
Set Me.Recordset = GetRecordset("Client='" & _
Me.Combo_PickClient & "'")
End Sub
In my case, the disconnected recordset is displayed in a subform and the combo box is on its parent form. So I created a wrapper procedure in the subform code module and call that from the combo's After Update:
Call Me.SubFormControlName.Form.ChangeRecordset("Client='" & _
Me.Combo_PickClient & "'")
The wrapper procedure is very simple, but I found it convenient ...
Public Sub ChangeRecordset(Optional ByVal pFilter As String)
Set Me.Recordset = GetRecordset(pFilter)
End Sub