How to reference events on objects in a subform from inside the main form - vba

Imagine a form that, for demontration purposes, contains only a subform and a textbox that need to mirror each other.
I tried to accomplish this by setting the Control Source on the textbox to the value of the field in the subform and this worked to make them mirror each other, but the textbox isn't editable so this is an unsuitable solution.
The next thing I decided to try was using the AfterUpdate event on both controls to run code that sets the value of the other control.
This is easy for the textbox:
'Set value of Notes field on subform whenever value of the corresponding textbox
Private Sub Notes_Textbox_AfterUpdate()
Me.subform.Form![Notes] = Me.Notes_Textbox.Text
End Sub
However, this isn't as simple for the subform field. I don't know how to reference an event on a field in a subform in a way that will still allow me to reference controls outside that subform.
As a demonstration, I need a way to do this:
Private Sub subform_Notes_AfterUpdate()
Me.Notes_Textbox.Text = Me.subform.Form![Notes]
End Sub
I can access the subform fields AfterUpdate event within the scope of the subform but if I do that, then I can't access the Textbox because it is in the main form, not the subform.
So I either need a way to define an event function on a field in a subform from within the scope of the main form, or a way to make the textbox part of the subform while maintaining the subforms ability to open in datasheet view.

Not sure I get the whole problem (how does datasheet view come into play?), but this should do what you want:
(in the subform)
Private Sub Notes_AfterUpdate()
Me.Parent!Notes_Textbox.Value = Me![Notes].Value
End Sub
Edit from comment: By far the easiest solution would be a continuous form instead of a datasheet in a subform.
You can have two textboxes, a one-liner in the Details section, and a large one in the form header or footer. Both have the same control source and are automatically updated when the other one is edited. No code required.
If it must be a subform-datasheet, you can use a similar approach: bind the main form to the same recordsource, and in On Current of the subform, move the main form to the same current record.

Related

ms Access: Switching between subform recordsource when changing records

I have a main form and a subform on it. I want the recordsource of the subform to change depending on the value of an ID field of the main form. This works when I do it in the Form_Load event of the parent Form. However, I also want it to update when the user switches to a new record on the main form (single form) while it is open.
The code I have atm is the followng:
Private Sub Form_Load()
'***************************************************************************
'Purpose: Switch subform recordsource based on recipe ID
'Inputs: None
'Outputs: None
'***************************************************************************
Dim strRecipeID As String
Dim strSub1QueryName As String
strRecipeID = Forms![frmMainForm]![RecipeID] 'get RecipeID
strSub1QueryName = DLookup("[QueryName]", "tblRecipeQueries", [RecipeID] = strRecipeID) 'Get name of query
Forms!frmMainForm!frmSub1Sub.Form.RecordSource = MakeSqlString(strSub1QueryName) ' Set Subform1 recordsource
End Sub
MakeSQLString() is a function that gets the SQL SELECT statement as a string from a given access query. I tried the change event, the Click event and the Current event and requerying the subform after that but none have any impact on contents of the subform (the recordsource does not change) but stays the same one that was selected when the form loaded.
I'm not sure which other events could work for this or from where I can execute the change in recordsource most effectively, maybe the subform instead? Maybe it has something to do with the subform loading before the parent form? I'm not sure, might be a rooky mistake.
I appreciate any help. BTW, the fields on the subform stay the same, so changing the recordsource just updates the calculations that are made in the query to get the values for those fields. The query names are stored in a table in my db. Again, It works in the Load event of the main form I just can#t get it to update on the fly while the main form is open and the user navigates to a new RecipeID on said main form.
In your DLookup you are not enclosing the where portion in quotes. You have:
DLookup("[QueryName]", "tblRecipeQueries", [RecipeID] = m_selectedId)
But it should be:
DLookup("[QueryName]", "tblRecipeQueries", "RecipeID =" & m_selectedId)
That should take care of your issue.

How to Update the Values of a Dropdown in a Subform when the Main Form Changes

I have two forms:
InterviewMaster and InterviewDetail
InterviewDetail opens up as a subform in InterviewMaster and these two forms are linked through a common field called InterviewID
In InterviewDetail I have a textbox called Questiontype as well as combobox called InterviewDropdown.
The data in the dropdown varies based on the data on in the textbox. To make this happen, I have a next button to move to the next question. Whenever I click on next the following runs:
Dim ctlCombo As Control
Set ctlCombo = Forms!InterviewDetail!cmbInterviewDropdown
ctlCombo.Requery
The Row Source setting for my combobox is set to look up the required answers, again this is based on the value as per the textbox:
SELECT [queryAnswerOptions].[Answer] FROM queryAnswerOptions ORDER BY [Answer];
So the options are determined by my query called queryAnswerOptions
So as I cycle through my questions using my next and previous buttons, the dropdown options are updated based on the value of my textbox. This works perfectly when I open the subform from the navigation pane. However, when I open the main form and click on the next button my dropdown does not have any values. I've tried requerying the subform with no luck. I've also tried opening the subform in full screen from my main form but this also does not work. I also don't want to go that route as it does not work well with the overall flow of my form.
Any assistance will be greatly appreciated.
Problem with the query WHERE criteria parameter is when form is installed as a subform, the form reference no longer works because it must use the subform container control name. I always name container control different from the object it holds, such as ctrDetails.
Option is to put SQL statement directly in combobox RowSource instead of basing combobox RowSource on a dynamic parameterized query object - then it will work whether form is standalone or a subform.
SELECT Answer FROM InterviewAnswers WHERE QuestionID = [txtQuestionID] ORDER BY Answer;

find parent of a subform

I need to be able to tell what's opening an object where a control is sitting.
I have a procedure that refreshes comboboxes but I will never know whether the combobox is sitting on a form, a subform or inside another subform (2 levels of subforms)
Now, on opening of the form, I hardcode that info to a hidden control and it's passed to a procedure, but I was wondering if there's a way to do something like this, instead of me hardcoding.
it will be either or, depending on where the combobox is sitting
VMainForm = Me.Parent.Name
VMainForm = Me.Name
VMainForm = Me.Parent.Name '(? not even sure how to do this one,
'this would be where the combo is sitting inside another subform,
' so, there's Main!Subform1#Subform2)
Even better solution would be to get the full path to the subform.
So, if I'm on the 2nd subform, I'd get mainform!subform1!subform2
If I'm on a subform, I'd get mainform!subform1
If I'm on main, I'd get mainform.
And you didn't even try?
VMainFormName = Me.Parent.Name
This will, of course, fail if not a subform. So either catch that error or loop the Forms collection for having the form of the control.

How to have subforms load after the the main form in access 2010

I have an Access 2010 database, with document information in a primary table.
I have forms that display specific document type information (credit card statements, invoices, etc.) from the table.
I have a main form, with separate subforms, each subform representing a specific document type.
I want to be able to filter from the main form, so that each document type subform displays only the documents that fall within a user-specified dollar amount range.
I'm thinking, that if I can get the sub forms to open after the main form (the reverse of this is the default order), I can set the filter in the open event of each sub form, from the main form, and get my desired results.
What I have found to cause the sub forms to open after the main form, is to remove the SourceObject from the Data tab of the Properties sheet of the sub form; and then assign the sub form name to the SourceObject property in vba in the open event of the main form.
The example I have is Me.MySubForm.Form.SourceObject = "frmSubFormName", where everything on the left is verbatim, and frmSubFormName is the name of my subform.
This isn't getting past the compiler - it's complaining about MySubForm, and unfortunately the post/blog with the example doesn't indicate what "MySubForm" is, in assigning the SourceObject property to my sub form name.
Any thoughts on this approach to the filtering?
Can anyone shed light on the syntax of setting the SourceObject; or perhaps provide another way of having the sub forms load after the main form?
Thanks in advance.
Remove the Form class object reference. Recommend naming the subform container control different from the object it holds, such as ctrSomething
Me.ctrSomething.SourceObject = "frmSubFormName"

Save record in subform

I have a main form with a tab control containing multiple subforms. I need to be sure that the data in a subform is saved when the user switches tabs. The problem is that DoCmd.RunCommand acCmdSaveRecord seems only applies to the current form so it doesn't save the data in the subform.
I have tried different events on the subform such as deactivate, OnLostFocus etc but they don't fire until another field somewhere else gets the focus.
The ideal solution would seem to be to put something on the OnChange event of the tab control to be sure that all the data is saved. That is my question, how to do I save the record in a subform?
In Access, the default is to save, so unless you have done something pretty complicated to prevent this, moving the focus from a subform will automatically save the record. You can test this by adding a record, moving from the subform, and then checking the table.
You don't have to do anything at all, as the subform is saved as soon as it loses focus (when the tab control changes).
But as an exercise, I've outlined the code you'd write if you needed to.
You can save any form by setting it's .Dirty property to False. For something like this that's going to run a lot, I think I'd write a sub to walk through the subforms, check if any are dirty, and save the dirty ones. Something like this:
Public Sub SaveSubFormsOnTab()
Dim pge As Control
Dim ctl As Control
For Each pge In Me!ctlTab.Pages
Debug.Print pge.Name
For Each ctl In pge.Controls
If ctl.ControlType = acSubform Then
If ctl.Form.Dirty Then
ctl.Form.Dirty = False
End If
Debug.Print ctl.Name
End If
Next ctl
Next pge
Set ctl = Nothing
Set pge = Nothing
End Sub
Now, that's actually quite inefficient in cases where you have lots of controls on your tab control that aren't subforms. If your tab has nothing but subforms, it will be fairly efficient. In either case, it's much more efficient to use a custom collection populated in the form's OnLoad event, and then you'd walk that collection that includes nothing but your tab control's subforms, and save any that are dirty.
Either of these is preferable to using the OnChange event of the tab, because each time you add a tab page with a subform or change the name of a subform control, you'd have to alter the OnChange event.
I was having a similar issue where I needed various code to run in the subform and values in the main form - that were based on values in the subform - to be recalculated. Here is what finally worked:
This is an example with a main form named 'frmCustomers' containing a subform 'sfmTransaction', which in turn has a subform called 'sfmOrderLine'. The forms have a button 'cmdSave' that is only visible when the user clicks the 'cmdEdit' button (the purpose of which is to lock all the controls until the user clicks the edit button, and then to re-lock them when he clicks save):
On the main form ('frmCustomer') go the subform's exit event, and add 'me.recalc' twice, like this:
Private Sub sfmTransaction_Exit(Cancel As Integer)
If (Not Form_sfmTransaction.NewRecord And Form_sfmTransaction.cmdSave.Visible) Or (Not Form_sfmOrderLine.NewRecord And Form_sfmOrderLine.cmdSave.Visible) Then
'To save subforms
Me.Recalc
Me.Recalc
End If
End Sub
In the subform ('sfmTransaction') go the subform's subform's exit event, and add 'me.recalc' twice, like this:
Private Sub sfmOrderLine_Exit(Cancel As Integer)
If Not Form_sfmOrderLine.NewRecord And Form_sfmOrderLine.cmdSave.Visible Then
'To save subform
Me.Recalc
Me.Recalc
End If
End Sub
Hope this helps.
Setting the dirty property to false may force Access to save the data to the database, but it bypasses the before_update event. This means that if you've used this event for validation or other purposes, you can now have bad data in your database.