I'm new to MS Access and have been developing a basic CRM system. All has gone well so far, but am banging my head against what I assume is a very simple problem... I can understand VBS and get my way around Access in general, but am by no means an expert in either realm.
How do I make an unbound combobox automatically set itself to a certain value based on other values in a table?
I have a form for users to edit employee information, and this includes comboboxes for inputting an employee's Division and Branch. There are about 10 divisions, each with around 5 branches.
The Branch combobox saves the BranchID to the tblEmployee table, with this acting as a key to the tblBranch table. The tblBranch table also has BranchName and DivisionID, with DivisionID as the key to the tblDivision table, which basically just has Division ID and DivisionName.
Right now the Division combobox is unbound, as this is merely there to allow the user to narrow down the Branches combobox. Cascading the menus down like this works fine once you click on the Division combobox, but when I open the form, the Division combobox shows up blank (and therefore the Branch combobox also shows up blank, as it has a criteria reference to the Division combobox).
How do I make the Division combobox look to see what the BranchID is for a specific employee, and then pre-set itself with the relevant Division?
I tried doing this both by setting a binding and also as an event, but I couldn't get either way to work properly... (likely just newb-ness on my part).
Thanks!
Thanks! Glad to see I was generally on the right path. It's still not working, however, and I think it's because I'm not understanding the YourEmployeeIDField.
My code is as follows:
Private Sub cboDivision_Enter()
Dim sql_ As String
sql_ = "SELECT d.Division " & _
"FROM tblDivision d INNER JOIN (tblBranch b INNER JOIN tblEmployee e ON b.BranchID = e.BranchID) ON d.DivisionID = b.DivisionID " & _
"WHERE e.EmployeeID=" & Me.txtEmployeeID
Me.cboDivision.RowSource = sql_
End Sub
I removed the selection criteria on the comboboxes to make sure that things weren't getting filtered out accidentally.
I tried using EmployeeID, e.EmployeeID, txtEmployeeID (the field on the form), and Me.txtEmployeeID, without much luck.
After investigating the RowSource approach a little bit more, I wonder if I may not have explained what exactly I want? (Or I'm just misunderstanding) The combobox cboDivision is populated with the tblDivision.Division, which is want I want. However, because it is unbound, when a record is loaded in my form, cboDivision is blank. I want it to display the Division associated with the bound cboBranch combobox (but when you click on cboDivision, it still has the full list of Divisions available to select).
The button code that I'm using is as follows (it's simplified SQL, but the same result happens with your code):
Private Sub Command240_Click()
'Me.cboDivision.Value = 8
Dim sqlStr As String
sqlStr = "SELECT d.DivisionID" & _
"FROM tblDivision d INNER JOIN tblBranch b ON b.DivisionID = d.DivisionID)" & _
"WHERE b.BranchID=" & BranchID
Me.cboDivision.Value = sqlStr
MsgBox ("You clicked me.")
End Sub
The commented out "Me.cboDivision.Value = 8" makes the cboDivision combobox show the division associated with DivisionID 8, which is effectively what I want; however, if I click the button with the current code, the combobox updates to: "SELECT d.DivisionIDFROM tblDivision d INNER JOIN tblBranch b ON b.DivisionID = d.DivisionID)WHERE b.BranchID=45"
(The 45 at the end is the correct BranchID for the record, so that part is working at the very least).
You need to change the RowSource property of the combobox to populate the correct Division information based on the EmployeeID selected.
You can do this on the control's Enter event:
Private Sub YourComboBoxName_Enter()
Dim sql_ As String
sql_ = "SELECT d.DivisionName " & _
"FROM tblDivision d INNER JOIN (tblBranch b INNER JOIN tblEmployee e ON b.BranchID = e.BranchID) ON d.DivisionID = b.DivisionID " & _
"WHERE e.EmployeeID=" & YourEmployeeIDField
Me.YourComboBoxName.RowSource = sql_
End Sub
The combobox control's RowSourceType must be set to Table/Query.
I figured out what I wanted to do... and it may have been that I didn't explain it properly. The code to do what I needed was as follows:
Private Sub Form_Current()
Me.cboDivision.Value = DLookup("DivisionID", "tblBranch", "BranchID=" & BranchID)
Me.cboMinistry.Value = DLookup("MinistryID", "tblDivision", "DivisionID=" & Me.cboDivision)
End Sub
So when I change the current record, it updates the unbound comboboxes based on the bound value of BranchID.
Thanks for your help, responders!
Related
I am developing an Access database (using Office 2016) and have several tab controls which I want to display the number of records in the subform/subreport.
After a lot of searching etc I have it working for the subforms using a function which I call in the main forms current event (but in a seperate function so I can also call via a macro when I change the main forms record with a combo box, as it wasn't updating otherwise). The code I am using is:
Function ClientTotals()
Dim i As Integer
i = Form_sbfrm_ClientContacts.Recordset.RecordCount
Form_frm_Clients.ClientTabs.Pages("Contacts").Caption = "Contacts (" & i & ")"
End Function
This works perfectly for me and my tab name becomes "Contacts (No. of records)" but I can't get the syntax right to change this to work for a report, is it possible?
I have tried:
Function ClientTotals()
Dim i As Integer
i = Form_sbfrm_ClientContacts.Recordset.RecordCount
Form_frm_Clients.ClientTabs.Pages("Contacts").Caption = "Contacts (" & i & ")"
Dim j As Integer
j = Report_rpt_CurrentProjects.Recordset.RecordCount ' this line is highlighted with the debugger
Form_frm_Clients.ClientTabs.Pages("Current Projects").Caption = "Current Projects (" & j & ")"
End Function
As well as:
Dim j As Integer
j = rpt_CurrentProjects.Report.Recordset.RecordCount ' this line is highlighted with the debugger
Form_frm_Clients.ClientTabs.Pages("Current Projects").Caption = "Current Projects (" & j & ")"
and various others.
Another question I have is why is the syntax for the form "Form_sbfrm" etc and not using a "!". If I change to "!" it bugs out.
Thanks for your help, KAL
Thanks Delecron,
I think I will stick with the tabs for now as they are giving me exactly what I want, but remember what you have said for when I make future improvements if its a better way of doing it.
EDIT
Using what you have said I changed my VBA to a DCOUNT method:
Dim j As Integer
j = DCount("*", "qry_CurrentProjects", "FK_Project_Client_ID = Forms!Navigation!Navigationsubform.form!Client_ID")
Form_frm_Clients.ClientTabs.Pages("Current Projects").Caption = "Current Projects (" & j & ")"
This means my report tabs are now also working just how I wanted
I was getting in a muddle with the criteria/filter, hense the edit.
If Recordset is an old method I am assuming it would be best to replace my other code with the Dcount method?
Thanks again, KAL
Further EDIT
After doing this I could see that everytime the form was changed there was a slight flicker. Not bad but you could see there was a lot of calculation going on. Therefore I have changed my method to the following, and posted here for anyone looking at this in the future.
In the form footer a textbox with COUNT([Project_ID])
In my function
Dim j As Integer
j = Form_frm_Clients!rpt_CurrentProjects.Report!txt_CurrentProjectsCount.Value
Form_frm_Clients.ClientTabs.Pages("Current Projects").Caption = "Current Projects (" & j & ")"
Now I can see it is working quicker with no flicker.
Recordset if you need to return complex data, if you need one value, a total or a sum, Domain functions are the way to go. Don't overdue them though, having too many on a form or a report can start to bog down usability.
Glad I can help.
Recordset.Recordcount is a legacy feature that only worked in ADP files (Access front end's to a SQL database). Those are no longer supported.
If the report is based on 1 client only and there is no grouping then you can do this:
Click on the detail section and in Events create an event for On Paint. In there set
(Name of Page).Caption = DCount("*", "NAME OF QUERY/TABLE") or
(Name of Page).Caption = DCount("*", "NAME OF QUERY/TABLE", "Filter Expression") (Filter expression optional).
If the report is grouped where it will show a different page per client or date range or any other grouping this will not work since the Caption field is not data bound. You would have to add logic to the Dcount statement above to field by the current filter condition.
For example, say you have a database of 200 clients and you're running one big report on all of them, each page will get its own tab control per client, the syntax would be
(Name of Page).Caption = DCount("*", "ClientContacts, "ClientID = " & ClientID)
The better way to do it especially if you are grouping is get rid of the tab control and use databound controls. You could create a box around the information that would be in the tab page and put a textbox where the tab would go. Create a group header for however you are grouping the data. Create another invisible textbox in the group header and set the controlsource = Count([fieldname]) where fieldname is whatever you are grouping the data by (the inside brackets count).
Then in the textbox you created to simulate the tab, set the controlsource to the name of the invisible textbox.
Let me know if this helps.
i have 2 tables : Salesagent and Client which are related by id, each sales agent have too many clients with the same id ,
i want to add combo box to display the salesagent, then another combo box that displays the clients of that salesagent
combosale is ok ..
comboclient , displays the 1'st field of client table(only one not all of them ) ,when choosing only 1'st salesagent
it displays nothing when i choose another salesagent even if it has clients related to it
:(
i used :
Me.combmoclient = DLookup("[cname]", "[client]", "[salesagent]= '" & Me.Combosale & "'")
Don't use Dlookup, it will just return the first value that matches your criteria, when really you need the whole set of clients for that sales agent. Instead you should use the AfterUpdate() event of the combosale field to do something like this:
Private Sub Combosale_AfterUpdate()
Me.comboclient.RowSource = "SELECT cname FROM client WHERE id = " & Me.Combosale.Column(1) & ";"
End Sub
In general, pure SQL queries are much faster than the Dlookup, Dsum, etc. functions. You will have a much more stable application if you stay away from them and write SQL code into your Access VBA.
this vba solved the problem :)
Private Sub Combosale_AfterUpdate()
Me.comboclient.RowSource = "SELECT cname FROM client WHERE id = " & Me.Combosale.Column(1) & ";"
End Sub
tooo many thanx for your help !!
I have an access form, i want to know how to add item in combo box if there is not in there.
my combo box is in value mode.
Unfortunately you cannot change the rowsource permanently without changing the form to design mode and adding the new value. It is possible to do this with code, but it is not a good idea when people are working. The easiest thing is to create a small table and add the values to that. New values will then be saved when you close the form.
Allen Browne has a description of how to do this : http://allenbrowne.com/ser-27.html
This is one of the ideas he shows:
Private Sub CategoryID_NotInList(NewData As String, Response As Integer)
Dim strTmp As String
'Get confirmation that this is not just a spelling error.
strTmp = "Add '" & NewData & "' as a new product category?"
If MsgBox(strTmp, vbYesNo + vbDefaultButton2 + vbQuestion, "Not in list") = vbYes Then
'Append the NewData as a record in the Categories table.
strTmp = "INSERT INTO Categories ( CategoryName ) " & _
"SELECT """ & NewData & """ AS CategoryName;"
DBEngine(0)(0).Execute strTmp, dbFailOnError
'Notify Access about the new record, so it requeries the combo.
Response = acDataErrAdded
End If
End Sub
You'll need to set the property limit to list to true.
Then add some code in the On Not In List event that potentially adds the value to the combo box. Here is a tutorial. Or you can view the other answer.
Please note that it is usually better to utilize a table that stores the values for your combo box. With a value list, unless you disable the shortcut menus a user can right click on the combo box select Edit List Items... and modify the list even if it is set to limit to list... which effectively defeats any limitation you are trying to place on the field.
I'm trying to create a form that has several categories and sub categories.
Is there a way that i can create a relation between what is chosen in the first drop down (Main Category) to what is displayed in the second (sub category)?
I don't want to list all the sub categories at once. I only want the ones that relate to the specified one selected in the Main Category....
Thanks!
This is one of the most frequently-asked Access questions.
Approach 1: in the WHERE clause of the second combo box, use a reference to the first combo box as a criterion:
PARAMETERS [Forms]![MyForm]![cmbCategories] Long;
SELECT SubCategory
FROM tblSubCategories
WHERE CategoryID = [Forms]![MyForm]![cmbCategories]
ORDER BY SubCategory;
(it's important to define the control reference as a parameter in versions of Access after 97 because those versions of Access don't handle Nulls in the same way as 97 and before did)
Then, in the AfterUpdate event of the first combo box, requery the second:
Private Sub cmbCategories_AfterUpdate()
Me!cmbSubCategories.Requery
End Sub
Approach 2: Instead of hardwiring the second combo box's rowsource to include a reference to the first, write its rowsource on the fly in the first combo box's AfterUpdate:
Private Sub cmbCategories_AfterUpdate()
Dim strRowsource As String
strRowsource = "SELECT SubCategory FROM tblSubCategories WHERE CategoryID = "
strRowsource = strRowsource & Me!cmbCategories
strRowsource = strRowsource & " ORDER BY SubCategory;"
Me!cmbSubCategories.Rowsource = strRowsource
End Sub
I tend to do the latter because I often need to do other things besides just filtering to the first combo box, but it's probably easier for most people to take the first approach.
I am having trouble setting the row source of a certain combo box on my form (viewed as a continuous form, although I also seem to have some problems in single-form mode).
The combo-box is bound to a field called supplierID, and is meant to present the user with a list of all the possible suppliers for an item. The row-source I am using for the combo-box is:
SELECT DISTINCT Suppliers.name, Suppliers.supplierID
FROM Suppliers
INNER JOIN PartsSuppliers ON Suppliers.supplierID=PartsSuppliers.supplierID
WHERE PartsSuppliers.partID = partID;
When I view this query in the query designer (with a partID hard-coded), it works fine - it selects all the possible suppliers for the chosen item, and doesn't show any other items. But when I look at the items in the combo-box, it shows all the suppliers present in the PartsSuppliers table (which has just two columns, mapping the parts to the possible suppliers for them).
I have also tried to set the combo-box's RowSource using some VBA in the OnFocus event (hardcoding the partID value in), but it never seems to change the RowSource. The VBA code I am using is:
Private Sub supplierID_GotFocus()
Dim query As String
query = "SELECT DISTINCT Suppliers.name, PartsSuppliers.supplierID "
query = query & "FROM Suppliers INNER JOIN PartsSuppliers ON Suppliers.supplierID = PartsSuppliers.supplierID "
query = query & "WHERE (((PartsSuppliers.partID)=" & partID & "));"
supplierDropDown.RowSource = query
supplierDropDown.Requery
End Sub
I also tried opening that query in a RecordSet, and then using setting that RecordSet as the combo-box's RecordSet, but that didn't work either.
What am I doing wrong, or is there some other way that I should be looking at to make the correct drop down?
N.B. I have seen Custom row source for combo box in continuous form in Access, but that accepted solution didn't work for me either.
Use the OnEnter and OnExit events to change out your RowSource.
Private Sub supplierID_Enter()
supplierDropDown.RowSource = _
"SELECT DISTINCT Suppliers.name, PartsSuppliers.supplierID " & _
"FROM Suppliers INNER JOIN PartsSuppliers ON Suppliers.supplierID = PartsSuppliers.supplierID " & _
"WHERE PartsSuppliers.partID = " & partID & ";"
End Sub
Private Sub supplierID_Exit()
supplierDropDown.RowSource = _
"SELECT DISTINCT Suppliers.name, PartsSuppliers.supplierID " & _
"FROM Suppliers INNER JOIN PartsSuppliers ON Suppliers.supplierID = PartsSuppliers.supplierID;"
End Sub
I've been struggling with how to avoid the 'blanks' left behind in a datasheet once Combo items are restricted and couldn't find any straight forward option for a long time....until now!
Leaving all of the available options in the Combo box but adding a temporary validation rule, using OnCurrent, does the trick perfectly.
Hoping this prevents someone banging their head on the desk for as long as I have.