Filtering Access subform2 via VBA - vba

I have a database with a main form called frmIndex.
frmIndex has a subform1 control named Sub.
Sub contains a form named frmMaintenance.
frmMaintenance has a subform2 control named Child9.
Child9 contains a form named frmHolidays.
In frmHolidays I have a combo named cboCountry and a code that filters the forms underlying table by countrycode, so that I can see the holidays for a specific country.
Private Sub cboCountry_AfterUpdate()
DoCmd.ApplyFilter , "[COUNTRYCODE]='" & Me.cboCountry & "'"
End Sub
The filter works fine when the frmHolidays is open as stand-alone form, but it doesn't work when frmHolidays is opened inside frmIndex/frmMaintenance.
Can anyone help in fixing this issue please?

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.

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.

How can i make or not make particular Tabs visible by loading a form in Access with VBA?

Question
How can i make or not make particular Tabs visible by loading a form in Access with VBA?
Explanation:
I have a Acess Database with 4 forms containing buttons. Today i started to create ribbons to get rid of those in the forms so everything is sorted and easy to overview. I want the Tabs in my Access Database to be unvisible until i open a form from my main form.
Main Form (no tabs showed) --> Switching to another form by clicking a button in my main Form (now i want to show a particular tab after opening the form)
I created my Ribbons with "Ribbon Creator 2019" for Office 2019.
Problem:
I cant solve it ... i tried so many things until i found a excel worksheet having a function by swithing sheets to display particular tabs. Its exactly what i want but i can't get it to work for my access.
By getting the name of the active form i cant get it to work and in my opinion this would be tha fastest way.
My approach:
I set "StartFromScratch" in my XML to 'true' and gave my tabs names like this: "CustomTagValue1:=xstart".
Code for my tabs (Module):
Sub GetVisible(control As IRibbonControl, ByRef visible)
' Callbackname in XML File "getVisible"
' To set the property "visible" to a Ribbon Control
' For further information see: http://www.accessribbon.de/en/index.php?Downloads:12
' Setzen der Visible Eigenschaft eines Ribbon Controls
' Weitere Informationen: http://www.accessribbon.de/index.php?Downloads:12
Select Case control.ID
Case "tab_3"
' Tab: tab_3
visible = False
Case "tab0"
' Tab: tab0
visible = False
Case "tab1"
' Tab: tab1
visible = False
Case Else
visible = True
End Select
End Sub
Code from another Module to declare my tabs:
Option Compare Database
Option Explicit
'**************************************************************************
' About this Code:
'
' This Code checks if a Formular is in active use by his 'Name'. Simple.
'**************************************************************************
Dim MyTag As String
'Callback for customUI.onLoad
Sub RibbonOnLoad(ribbon As IRibbonUI)
Set Rib = ribbon
End Sub
Sub GetVisible(control As IRibbonControl, ByRef visible)
If control.Tag Like MyTag Then
visible = True
Else
visible = False
End If
End Sub
Sub RefreshRibbon(Tag As String)
MyTag = Tag
If Rib Is Nothing Then
MsgBox "Fehler RBC1018, bitte starten Sie das Programm neu."
Else
Rib.Invalidate
End If
End Sub
Code in the Form onLoad:
Private Sub Form_Load(ByVal Sh As Object)
Select Case Screen.ActiveForm
Case "frmVerteiler": Call RefreshRibbon(Tag:="xverteiler")
Case Else: Call RefreshRibbon(Tag:="")
End Select
End Sub
Help:
I want it to work as in this excel Dokument: https://www.rondebruin.nl/win/s2/win012.htm
It is far less work and significant more easy to just create a custom ribbon for each form, and that way you don't have to write all kinds of code to hide show tabs on the ribbion. So just specify the correct ribbon for the given form, and no code is required.
I also suggest that you do NOT use call backs in the ribbon. If you adopt this approach, then the ribbon can directly call your EXISTING button code. So the code, buttons you now have can be transferred to the ribbon for that form, and you don't have to setup ribbon call backs, and all of your existing button code can remain "as is" and be called directly from the ribbon - and the ribbon will run the button code that is and remains in the form.
All you need to do is to declare any function you want called as a public function.
You then set the on action as follows:
=MyPublicFunctionName()
Note CAREFULL how we have = and () (you must have these), and they must be under the quotes.
Eg for the xml we have:
onAction="=MyDelete()"
Note how the above is DIFFERENT then a call back for a ribbon (and callbacks use sub, where this is a function). Even better is the above means you do NOT have to place the code in a standard code module, but can place the function it in the current form. So, no macro needed, no callback, and the code can go in the current form (just like it does for a command button). And bottoms to dollar, in 9 out of 10 cases, the code you need for particular form and button belongs in that particular forms code module anyway. In fact it's a very bad programming practice to start taking code that belongs in a form and placing that code in a standard public code module. The reason is for many, but all kinds of issues can crop up if you have multiple instances of that same form which is allowed in access. Furthermore when copying forms between applications, or even making a copy of the form within the same application means that you have outside code dependencies that we normally as access developers do not expect (we assume for the most part is that the code we're using for the form belongs in the forms code module and I 100% agree). I am open to the idea that this does go against the well known concept of moving UI and code apart but this is "HOW" access works. So the access way does go against trends in our industry.
Keep in mind the above function call idea is the same format we can and would have been using since near day one with menu bars in previous editions of access. So, if you are wanting to change menu bar code to ribbon, use the above idea. Also, if you have several buttons that runs code in a given form, then again the above syntax allows one to KEEP the code in the current form and simply declare the button code as a public function (you can thus real easy move buttons from a form to a ribbon if you do this).
If the function name you specified in the menu or ribbon was named as public in the form's code module, then the CURRENT FORM with the CURRENT FOCUS is where the function will be first looked for to execute. This is SIGNIFICANTLY important because it means you can use one custom menu bar for five different forms, but each of the five different forms will run a custom delete routine for example (no messing with screen.Activeform). And, you don't have to use a bunch of messy case statements as you do with a call back. In fact, all of the code stays in the form where it likely was or belongs in the first place, and that is in the forms code module.
So, if you have specific and specialized delete code that might be required for the given form that has the focus, then that's forms function code in the forms module will be run when it is called from the on action in the menu bar, or now ribbon.
This means if you set the on action to =MyDelete()
Then in each form you have, you simply declare a public functions such as
CODE
Public function MyDelete()
Code here to delete the record
End function
However it turns out for probably more then half or even close to 90% of your forms, it's entirely possible that you want a general catchall delete routine that works for all forms that don't need specialized custom deleting code. In this case you simply place the function in a standard code module (and again as public). If the current form does not have that function, then it is run from a standard code module (again, ideal behavior, and again this is how the onAction worked before ribbon).
Also, note that you also pass values directly from the ribbon.
So, ribbon xml might be:
CODE
<button id="MyDelete" label="Delete Record"
imageMso="Delete" size="large"
onAction="=MyDelete('Staff','tblStaff')"
supertip="Delete this record"
/>
In the above, I passed the table name, and a prompt text of Staff.
And the public catch all function in a standard code module will be:
CODE
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
etc....
Note again how I passed two parameters to the delete routine (the text must be under single quotes). The prompt part so the msgbox command will say "Delete this staff ?". And, then I also pass the table name. What the above means is that for ten forms, if you don't specify a public function inside of the form, when the menu button is clicked on is selected, the catchall general routine in an standard code module (non forms code module) will run.
And for the few forms that have specialize deleting code, the function inside of the forms code module will run. That code might look like:
CODE
Public Function MyDelete(s1 as string, s2 as string)
' check for history
....
lngHistory = Nz(DLookup("ContactId", "NHistory", "ContactID = " & Me.ContactID), 0)
If lngHistory > 0 Then
Beep
MsgBox "You cannot delete a person with past history bookings!" & vbCrLf & vbCrLf & _
"You should simply check the 'Do NOT INCLUDE in mailings' to remove from" & vbCrLf & _
" future mailings.", vbExclamation, "Rides"
Exit Sub
End If
...code here with sql to delete record....
So a few things:
I would just create a ribbon for the given form (take your xml for the given tab, and create a whole new ribbon). Now, if you have 2 or 5 forms open, then the ribbon will automatic flip and change for you. If you try and use tabs, then a simple change of focus to another form will require you to hide+show given tabs - it becomes a real mess rather quick.

How to navigate to a form based on a comb box selection in Microsoft Access

I'm creating a form for my Microsoft Access database. I have a combo box, and I need it to navigate to the form based on which item the user clicks.
How would I do this? I know it requires some VBA code, but none of the methods I have tried have worked thus far.
The form I am trying to navigate to is called "Forms_Reports"
My current code:
Private Sub Combo0_AfterUpdate()
If Me.Combo0.Value = 1 Then
DoCmd.OpenForm "Forms_Reports", acNormal
End If
End Sub
Your code is basically okay, but you can't combine it in a single line. Also, I'm guessing your form is really just named "Reports". You don't include the Form_ prefix displayed in the project window. Try this:
Private Sub Combo0_AfterUpdate()
If Me.Combo0.Value = 1 Then
DoCmd.OpenForm "Reports", acNormal
End If
End Sub

Access 2007 VBA - Rename report upon closing it?

I have a report that is dynamically generated depending on the button pressed on my main form, in order to change the filter, the query used, etc. I have DoCmd.Rename working to rename the report to the current (dynamic) report title. However, it appears that I cannot rename the report back to a generic name upon closing the report.
Using the Report_Close() event doesn't work; Access tells me the report is still open and therefore can't be closed. Using DoCmd.Close doesn't work either; I get Runtime error 2501 (The Close action was cancelled).
How can I rename this report after it's closed?
Are you saying that each time someone changes the settings and opens a report, you want to save that as a new report in Access?
I wouldn't recommend this.
If the dynamically changed stuff are just things like filter and query, why not always use the same report and set the RecordSource dynamically?
EDIT:
Okay, now I understand what you actually want to do.
You can set the Caption property of the report at runtime in code:
Private Sub Report_Open(Cancel As Integer)
Me.Caption = "Incidents By Assignee"
End Sub
You can also pass the text for the caption from your main form to the report:
Pass the text from the form in the OpenArgs parameter when opening the report:
DoCmd.OpenReport "YourReport", acViewNormal, , , , "Incidents By Assignee"
...and in the report, just set the Caption to OpenArgs if it's not empty:
Private Sub Report_Open(Cancel As Integer)
If Nz(Me.OpenArgs) > "" Then
Me.Caption = Me.OpenArgs
End If
End Sub