How do i use Dlookup for Multiple Criteria to create a dynamic Combobox - vba

I have two Comboboxes on a from: txtKategorie and txtTyp.
The values for the frist Combobox (txtKategorie) are fix!
I want the values of the second Combobox (txtTyp) to change according to what the user chooses in the first one.
If the user chooses "Datalogger" the second combobox should only contain "Base Layer Classic" and "Base Layer Plus" as can be seen in the image.
The same idea is true for "Accelerometer".
I've put my code in the AfterUpdate Event of the first Combobox:
If txtKategorie.Value = "Datalogger" And txtTyp.ListCount = 0 Then
i = 1
Do While txtTyp.ListCount < DCount("ID", "tblNomenklatur", "[Kat] = 'K'")
txtTyp.AddItem DLookup("[Typ]", "tblNomenklatur", "[ID] =" & i And "[Kat] = 'K'")
'And "[Kat] = 'K'"
i = i + 1
Loop
When the form opens only the first Combobox "txtKategorie" has Values. When the user chooses Datalogger the code checks how many records in the table have the [Kat] = "K" to define how long the Do While-Statement will run. Then the "txtTyp.AddItem"-Statement should add "Base Layer Classic" and "Base Layer Plus" to the "txtTyp" Combobox. But unfortunately the Code doenst work. There is a problem with the Dlookup-Statement containing tow criterias. If i remove either one of the two criterias the Code works but delivers wrong results for the second Combobox obviously. If i leave it like this the second Combobox stays empty.
Does someone know what im doing wrong?

You can do it easily by below code. Change table name with your table name.
Private Sub txtKategorie_AfterUpdate()
Me.txtTyp.RowSource = "SELECT DISTINCT Table1.Typ FROM Table1 WHERE Table1.Kategorie='" & Me.txtKategorie & "'"
Me.txtTyp.Requery
End Sub
Or you can do it graphically from row source query builder. Below are steps.
Combobox txtKategorie is fix. Fine!
For second combobox txtTyp follow the below steps.
Select combobox txtTyp. From property windows select Row Source then click on query builder ... small three dot. See screenshot.
In query builder window build a query from your data table like screenshot and set criteria for Kategorie column is [Forms]![Form1]![txtKategorie] Save and close the query bulder window.
Now for Combobox txtKategorie in After Update event write below line to requery txtTyp. You are done!
Private Sub txtKategorie_AfterUpdate()
Me.txtTyp.Requery
End Sub

Related

How to handle Access "Run-Time Error 3021 - No current record" after DoCmd.Requery?

I have been having a quite annoying issue on my access project.
It is an Access 2007 - 2016 file.
My database has two queries that I intend to use to filter data to feed combo-boxes.
On one of my forms I have done that with success. The first list is fed from a table, and the succeeding ones are fed by filtering their respective table based on the previous list selection.
Here is a screenshot of my form that worked out.
And here is part of the code that goes with it:
Private Sub frm01ListSetor_Click()
DoCmd.Requery (qry01_frm01ListArea)
Me![frm01ListArea] = Null
DoCmd.Requery (qry02_frm01ListEquip)
Me![frm01ListEquip] = Null
Me![frm01TextID] = Null
End Sub
Private Sub frm01ListArea_Click()
DoCmd.Requery (qry02_frm01ListEquip)
Me![frm01ListEquip] = Null
Me![frm01TextID] = Null
End Sub
Here are the queries that goes along with the code above:
qry01_frm01ListArea
SELECT tblAreas.ID_Area, tblAreas.NomeArea
FROM tblAreas
WHERE (((tblAreas.SetorArea)=[Forms]![frm01_AddEquip]![frm01ListSetor]));
qry02_frm01ListEquip
SELECT tblEquipamentos.ID_Equipamento, tblEquipamentos.NomeEquipamento
FROM tblEquipamentos
WHERE (((tblEquipamentos.SetorEquipamento)=[Forms]![frm01_AddEquip]![frm01ListSetor]) AND ((tblEquipamentos.AreaEquipamento)=[Forms]![frm01_AddEquip]![frm01ListArea]))
ORDER BY tblEquipamentos.ID_Equipamento;
The code above works just fine. It filters data to previous selection accordingly and it also clears the data and selection of the "righter" lists every time another value is selected on the "lefter" ones.
So that was a form I created to help me out on populating my equipment database.
Let us get to the problematic twin now:
I created another form for Maintenance Orders of these equipment.
This one must be more user friendly since other people will use it. Therefore I used Combo-boxes for value selection instead of List Boxes. I say this before hand because it is the only thing I could notice that differs the new form from the one above.
Here I have this:
Screenshot of troubled form
After the expanded Combo-box on image 2 is selected I should run the following code:
Private Sub frm02SetorOM_Click()
DoCmd.Requery (qry04_frm02CBArea)
Me![frm02AreaOM] = Null
DoCmd.Requery (qry05_frm02CBEquip)
Me![frm02EquipamentoOM] = Null
End Sub
Private Sub frm02AreaOM_Change()
DoCmd.Requery (qry05_frm02CBEquip)
Me![frm02EquipamentoOM] = Null
End Sub
It is basically the very same thing I have done on the first form but with different variables.
But I get a "Run-time error 3021: No current record" every time I select a value on my "Setor" field.
The crash happens at the "DoCmd.Requery (qry04_frm02CBArea)" line.
Here is the query for this form's Area field (qry04_frm02CBArea):
SELECT tblAreas.ID_Area, tblAreas.NomeArea
FROM tblAreas
WHERE (((tblAreas.SetorArea)=[Forms]![frm02_SubmitOM]![frm02SetorOM]));
But the thing that is confusing me the most is that when I click "End" on the Run-time error dialog box, my Area combo-box - that was empty before - even with the error gets the proper options like if it actually "requeried".
How can I fix this issue?
Thank you in advance.
Btw, this is my first Access project so please consider that on the response.

MS-Access Form shows Number, not Name on load

I got a Database, where I apply to a name a Main and Subgroup.
When I enter a MainGroup f.e. Granades, just subgroup elements like "attack-granades" etc. should be shown.
In genereal it works by writing in this into the MainGroup-Combobox at my Form.
Private Sub MunHauptgruppeRef_AfterUpdate()
Me.MunUntergruppeRef.Requery
Me.MunUntergruppeRef.RowSource = " SELECT UnterGrpNR, UnterGrpName FROM tbl_UnterGruppen WHERE UnterHauptGruppenNr = " & MunHauptgruppeRef.Value & " ORDER BY UnterGrpName ASC"
The Problem is, if I load the datas in my form again, it just shows the related Number to the "Sub-Combobox data" 1( f.e. 35 for Attack-Grenade ) , but not the Name itself. After I reselect the entry in my Main-Combobox(Grenade), it shows the right sub-data which was saved. 2
Tried Requery on Form_Load or Requery of the Combo-Boxes itself. nothing helped so far.
Made some Video3
You need to add the code from Private Sub MunHauptgruppeRef_AfterUpdate() to your Form_Current event, this will refresh your combo box row source to the current value of your MunHauptgruppeRef combobox as you cycle through your records. Also you need to call the Me.MunUntergruppeRef.Requery after you've set the Me.MunUntergruppeRef.RowSource.
You can also add a check when your in a New Record, for the code not to run on the Current Event. See here https://learn.microsoft.com/en-us/office/vba/api/access.form.newrecord

How to select table values from combobox selection?

I'm using an Access 2003 database and have 2 comboboxes I am trying to work with. The first box I have perfected already, which is a dropdown of different tables (categories of parts). Once that table is selected, I want to be able to look at the part numbers within that category through a dropdown box selection. From here I want to be able to pull up the correct report for that category with that part number in it so I can print a report for every part number. I'm sure I'll have to write some sort of VBA, Query or Macro AfterUpdate() code, but I just don't know how to fill that second combobox with the selected table's part numbers.
Click here for an image of my Menu layout
Here's my Query for the first box to show the tables I want:
SELECT Msysobjects.Name
FROM Msysobjects
WHERE (((Msysobjects.Name) not Like "MSYS*"
And (Msysobjects.Name) not like "_*"
And (Msysobjects.Name) not like "~*"
) AND ((Msysobjects.Type)=1))
ORDER BY Msysobjects.Name;
And I think this is what I'll need to print after the second box has it's selection:
Private Sub partnumberselect_AfterUpdate()
DoCmd.OpenTable Forms![_Datasheet Printing].Form.TagLabelSelection.Column(1), acViewNormal
End Sub
Thank you in advance and let me know if you have any questions.
You are attempting what are called "cascading comboboxes" which means the second box is dependent on the selection of the first.
This is accomplished through the control source of the second combo box.
The first thing you should do is write a query that returns all possible options of the second combobox, without caring so much about filtering it based on the first combo selection. Once you have it returning the correct data, you will add a WHERE clause to the second box's control source that's something like:
WHERE Msysobjects.Name Like Forms![_Datasheet Printing]!TagLabelSelection.Value
This is referencing your first combobox on your form. So after a selection is made in the first combobox, the underlying control source of the second will have the proper criteria to return the appropriate options.
However, you will need to add some VBA to the AfterUpdate() event on the first combobox. Once the selection is made, you need the second box to refresh the control source to populate the correct selections. The code is simply:
Forms![_Datasheet Printing]![MySecondComboboxName].Requery
Please see the example below.
Private Sub cboCountry_AfterUpdate()
On Error Resume Next
cboCity.RowSource = "Select tblAll.City " & _
"FROM tblAll " & _
"WHERE tblAll.Country = '" & cboCountry.Value & "' " & _
"ORDER BY tblAll.City;"
End Sub
You can read all about this concept, and others, in the link below.
http://www.fontstuff.com/access/acctut10.htm

MS Access Can't go to specified record because of another control's VB where clause

I have a lookup listbox which is programmed to allow the user to find a specific record/help topic from the list and view it. Now when the list box is used the where clause locks in the record and the first, previous, next, last buttons freeze up and you cannot use them to go to a record. Is there a way to free up the functionality of the buttons to navigate through the records along with the where clause to select.
Here is the code that operates the listbox selections:
Private Sub List35_AfterUpdate()
Dim myTopic As String
myTopic = "Select * from FormsHelpTable where ([ID] = " & Me.List35 & ")"
Me.Form.RecordSource = myTopic
Me.Comment.Requery
End Sub
I believe since the where clause locks in the selection in the box it does not allow navigation from other controls to interfere. What might be a way around this?
You get the runtime error:
You can't go to specified record.
It appears not to be reading the other record in the source table named Help once it updates using the listbox.
Instead of changing the recordset (this is the 'pool' of records which the form could display), you just need to go to the record the user selects from the listbox.
Method 1 (probably the easiest way if your listbox is in the same order as the records of your form)
Use this code:
Private Sub lstSelect_AfterUpdate()
DoCmd.GoToRecord acDataForm, "HelpForm", acGoTo, Me.lstSelect.ListIndex + 1
End Sub
You need to ensure that:
The recordset of the form is ordered the same as the listbox. So, for example, you could order both by ID, or by Title.
Note that the +1 comes from the fact that the ListIndex starts at 0, whereas the record indexes start at 1.
Method 2
Ensure each record's Title is unique (set No Duplicates on this field).
Change your listbox to return the Title of the record, rather than it's ID.
Then use this:
Private Sub lstSelect_AfterUpdate()
Me.Title.SetFocus
DoCmd.FindRecord Me.lstSelect
Me.lstSelect.SetFocus
End Sub
Things to note:
It works by searching the field with focus for the string specified. That's why we have to SetFocus on the Title textbox on our form.
We could use ID instead, (which would mean we could have duplicate titles if we wanted), but then we would have to have an ID control on the form to SetFocus to. You can't hide this control either, because it needs to have focus whilst using FindRecord.
Update: Method 1 with reverse-selection
Add an Event Procedure in the Form_Current event, with this code. Then update the code in the lstSelect_AfterUpdate procedure as shown after.
Private Sub Form_Current()
Me.lstSelect = Me.lstSelect.Column(0, Form.CurrentRecord - 1)
End Sub
Note that, depending on how your lstSelect is set up, it may be Column(1, Form.CurrentRecord - 1) instead. Read on for details!
Private Sub lstSelect_AfterUpdate()
DoCmd.GoToRecord acDataForm, "HelpForm", acGoTo, Me.lstSelect.ListIndex + 1
Me.lstSelect = Me.lstSelect.Column(0, Form.CurrentRecord - 1)
End Sub
Explanation of new lines:
The Form_Current event fires every time we go to a new record. We need to look at the index of the record (ie. the position of it in the recordset), which we get by using Form.CurrentRecord. We then want to make the listbox select that record. However, we can't use me.lstSelect.ListIndex as before, because that is a read-only property (we can access it to read it, but we can't set it).
Therefore, we use me.lstSelect.Column(colNum,rowNum) instead, where we specify a column number and a row number. If your listbox has two columns (eg. ID and Title), we want to choose the second column. The index starts at 0, so we would use a value of 1. If, like my lstSelect, you only have one column (Title) then we use 0. Note: it doesn't matter if a column is hidden (ie. has width 0). It still 'counts'.
The row number is Form.CurrentRecord - 1. Remember that the forms recordset index starts at 1, but the index of our listbox starts at 0; hence the - 1.
So why do we need a duplicate of this new row in the AfterUpdate event? Try and comment it out to see what happens if we don't put it in. It's has to do with the Form_Current event firing after we use the listbox.
I fixed this issue with a union clause in the SQL lookup code. The UNION ALL clause and the following union on the table used in the other part had allowed all the records to be used.

navigation subform requery stopped working

I've built an unbound form which allows a user to select from two combo boxes that contain related information (Zone and Watershed Unit -- each Zone contains multiple watershed units) in order to see what regulations apply to each. Based on these selections (stored in txtZone and txtWU on the main form) a subform would show the existing regulations (sfrmRegsbyZWU based on qryRegsbyZWU). This serves as a reference for the user, who picks a new regulation to add from another subform, clicks a button, and the selection is added to the regulations for the Zone/Watershed Unit selected. I had this successfully built with a workaround in the OnCurrent event of the subform (which was undesirable because the user couldn't click on a record and delete it) and everything worked until I added inserted code to change the query definitions for the query which is the basis for the subform as opposed to having it in the "On current" event of the subform.
At that point the requery syntax in the main form which had previously worked stopped working. This is in all embedded in a navigation form in Access 2010, so the previously working syntax was:
Forms!frmNav!NavigationSubform.Form.sfrmRegsbyZWU.Requery
I've tried every permutation of Requery I can think of, and I can not get it working. The underlying query has been changed, but the form doesn't update to reflect it. Can anyone explain to me what has gone wrong, and how to fix it? The code (attached to the _After Update() event of the combo boxes) is:
Private Sub cboZone_AfterUpdate()
'Changes WU combo box as well as the underlying text boxes
Me.cboWU.SetFocus
Me.cboWU = ""
'Blank out other selections
Me.txtWU.SetFocus
Me.txtWU = ""
'Update text box with combobox selection
Me.txtZone.SetFocus
Me.txtZone = Me!cboZone.Column(0)
'Change the query underlying the Existing Regs panel (frmRegsbyZWU, qryRegsbyZWU) to reflect selection
Dim strZSQL As String
Set qdfZ = CurrentDb().QueryDefs("qryRegsbyZWU")
Dim myZVar As Variant
myZVar = Forms!frmNav!NavigationSubform.Form.txtZone
'MsgBox (myZVar)
If IsNull(myZVar) Then
strZSQL = "SELECT * FROM tblRegulations WHERE FALSE"
Else
strZSQL = "SELECT * FROM tblRegulations WHERE Zone_No=" & Forms!frmNav!NavigationSubform.Form.txtZone
End If
'MsgBox (strZSQL)
qdfZ.SQL = strZSQL
'DoCmd.OpenQuery ("qryRegsbyZWU")
Forms!frmNav!NavigationSubform.Form.sfrmRegsbyZWU.Requery
Thanks in advance for any help!