Requery a subform from another form? - vba

I've struggling with this problem on my own, then with some help, then search about it; but I haven't had any luck. So I decided to ask.
I have two forms in Access 2007 lets call them MainForm and EntryForm.
MainForm has a subform and a button. The button opens the EntryForm in Add Mode. What I want to do is when the EntryForm saves the new record it would update (requery) the subform in MainForm.
I've try this setup code
Private Sub cmdSaveAndClose_Click()
DoCmd.Save
'requery list
Forms![MainForm]![subformName].Requery
'' I've also tried these
'Forms![MainForm]![subformName].Form.Requery
'Forms.("MainForm").[subformName].Requery
'Forms.("MainForm").[subformName].Form.Requery
DoCmd.Close
End Sub
None of these attempts seem to work. Is there a way to make this requery?
Thanks for the help in advance.

You must use the name of the subform control, not the name of the subform, though these are often the same:
Forms![MainForm]![subform control name Name].Form.Requery
Or, if you are on the main form:
Me.[subform control name Name].Form.Requery
More Info: http://www.mvps.org/access/forms/frm0031.htm

Just a comment on the method of accomplishing this:
You're making your EntryForm permanently tied to the form you're calling it from. I think it's better to not have forms tied to context like that. I'd remove the requery from the Save/Close routine and instead open the EntryForm modally, using the acDialog switch:
DoCmd.OpenForm "EntryForm", , ,"[ID]=" & Me!SubForm.Form!ID, , acDialog
Me!SubForm.Form.Requery
That way, EntryForm is not tied down to use in one context. The alternative is to complicate EntryForm with something that is knowledgable of which form opened it and what needs to requeried. I think it's better to keep that kind of thing as close to the context in which it's used, and keep the called form's code as simple as possible.
Perhaps a principle here is that any time you are requerying a form using the Forms collection from another form, it's a good indication something's not right about your architecture -- that should happen seldom, in my opinion.

I tried several solutions above, but none solved my problem.
Solution to refresh a subform in a form after saving data to database:
Me.subformname.Requery
It worked fine for me. Good luck.

I had a similar kind of issue, but with some differences...
In my case, my main form has a Control (vendor) which value I used to update a Query in my DB, using the following code:
Sub Set_Qry_PedidosRealizadosImportados_frm(Vd As Long)
Dim temp_qry As DAO.QueryDef
'Procedimento para ajustar o codigo do cliente na Qry_Pedidos realizados e importados
'Procedure to adjust the code of the client on Qry_Pedidos realizados e importados
Set temp_qry = CurrentDb.QueryDefs("Qry_Pedidos realizados e importados")
temp_qry.SQL = "SELECT DISTINCT " & _
"[Qry_Pedidos distintos].[Codigo], " & _
"[Qry_Pedidos distintos].[Razao social], " & _
"COUNT([Qry_Pedidos distintos].[Pedido Avante]) As [Pedidos realizados], " & _
"SUM(IIf(NZ([Qry_Pedidos distintos].[Pedido Flexx], 0) > 1, 1, 0)) As [Pedidos Importados] " & _
"FROM [Qry_Pedidos distintos] " & _
"WHERE [Qry_Pedidos distintos].Vd = " & Vd & _
" Group BY " & _
"[Qry_Pedidos distintos].[Razao social], " & _
"[Qry_Pedidos distintos].[Codigo];"
End Sub
Since the beginning my subform record source was the query named "Qry_Pedidos realizados e importados".
But the only way I could update the subform data inside the main form context was to refresh the data source of the subform to it self, like posted bellow:
Private Sub cmb_vendedor_v1_Exit(Cancel As Integer)
'Codigo para atualizar o comando SQL da query
'Code to update the SQL statement of the query
Call Set_Qry_Pedidosrealizadosimportados_frm(Me.cmb_vendedor_v1.Value)
'Codigo para forçar o Access a aceitar o novo comando SQL
'Code to force de Access to accept the new sql statement
Me!Frm_Pedidos_realizados_importados.Form.RecordSource = "Qry_Pedidos realizados e importados"
End Sub
No refresh, recalc, requery, etc, was necessary after all...

By closing and opening, the main form usually runs all related queries (including the subform related ones). I had a similar problem and resolved it by adding the following to Save Command button on click event.
DoCmd.Close acForm, "formname", acSaveYes
DoCmd.OpenForm "formname"

Just discovered that if the source table for a subform is updated using adodb, it takes a while until the requery can find the updated information.
In my case, I was adding some records with 'dbconn.execute "sql" ' and wondered why the requery command in vba doesn't seem to work. When I was debugging, the requery worked. Added a 2-3 second wait in the code before requery just to test made a difference.
But changing to 'currentdb.execute "sql" ' fixed the problem immediately.

All your controls are belong to us!
Fionnuala answered this correctly but skimmers like me would find it easy to miss the point.
You don't refresh the subFORM you refresh the subform CONTROL. In fact, if you check with allforms() the subForm isn't even loaded as far as access is concerned.
On the main form look at the label the subform wizard provided or select the subform by clicking once or on the border around it and look at the "caption" in the "Other" tab in properties. That's the name you use for requerying, not the name of the form that appears in the navigation panel.
In my case I had a subform called frmInvProdSub and I tried for many hours to figure out why Access didn't think it existed. I gave up, deleted the form and re-created it. The very last step is telling it what you want to call the control so I called it frmInvProdSub and finished the wizard. Then I tried and voila, it worked!
When I looked at the form name in the navigation window I realized I'd forgotten to put "Sub" in the name! That's when it clicked. The CONTROL is called frmInvProdSub, not the form and using the control name works.
Of course if both names are identical then you didn't have this problem lol.

I ran into this issue today.
I was in a form that contained a button on subform1. Subform1 made changes to Subform2 that required a requery.
I found success with: Me.Parent.subform2.form.recordset.requery

Related

Why form object doesn't load RecordSource attribute in VBA for Ms Access

I need to read programmatically the RecordSource attribute of a form, to know what table or query is the form depending on.
After some research, it seems that the form object needs to be actually open in a window (or hidden, but open) so that certain attributes can be accessed. I've put together the following code snippet:
Application.DoCmd.OpenForm "Form1", view:=acDesign, windowMode:=acWindowNormal
Dim frm as Access.Form
Set frm = Forms("Form1").Form
Debug.print frm.Name 'works ok
Debug.print frm.RecordSource 'prints an empty string
Application.DoCmd.Close AcForm, "Form1"
I can see that the form is correctly open, but the RecordSource attribute is empty, eventhough the form is fed from a table.
What could be going on? I'm using .accdb Ms Access database files. And have compacted the database, just in case the db were corrupted, but the issue remains.
Edit: The form is very minimal, and I realize that actually has no RecordSource at all; it only has a subform which, since it is indeed fed with a table, does have a non-blank RecordSource.
So VBA was right returning a blank RecordSource for the parent form. The script posted was correct after all. Thanks for your inputs!!
Any hints or directions would be greatly appreciated. Thank you in advance!!
Most likely, the RecordSource is assigned in code when the form is loaded, either as a table name or as SQL:
Me.RecordSource = "Select * From SomeTable Order By SomeField"
In design view you can't get RecordSource programmatically. You can see from Property window. You have to open it as normal form, may be you want it to open as hidden. You can specify WindowMode to open form hiddenly by DoCmd.OpenForm "Form1", acNormal, , , , acHidden. Try below codes.
Private Sub CmdTest_Click()
Dim frm As Access.Form
DoCmd.OpenForm "Form1", acNormal, , , , acHidden
Set frm = Forms("Form1")
Debug.Print frm.Name
Debug.Print frm.RecordSource
DoCmd.Close acForm, "Form1"
End Sub

Code for button on form to update table in ms access

I'm trying to create a simple form using unbound combo boxes and a button that updates a table when clicked. I have already created another form that is similar to this that works great, so I tried to replicate it using the appropriate fields, but I get an error message- Run-time error '3061: Too few parameters. Expected 1.
The only two fields on the form are FrameID and FrameLocation and the button is MoveFrame. The table to be updated is StockFrames.
This is the code I have on the on-click event on the button:
Private Sub MoveFrame_Click()
CurrentDb.Execute "UPDATE StockFrames SET frameLocation = " & Me.frameLocation & _" WHERE FrameID = " & Me.FrameID
Me.frameLocation.Value = Null
Me.FrameID.Value = Null
End Sub
I appreciate any help anyone can offer. I'm very new to MS Access. If there is any other information that you need as far as the property settings, please let me know. I'm eager to learn and to get this form working properly.
Thank you.
If frameLocation is a text field, parameter needs apostrophe delimiters:
='" & Me.frameLocation & "' WHERE.
Remove that underscore character.
Date/Time fields use # delimiter.

MS Access Form Bind to ADO Recordset

Driving me bonkers...
The problem is one of speed.
I have a working SQL Server linked to a client accessible website, which I am wanting to add an Access front end to enable us office bound staff to better support both client and field staff.
The current form I have constructed is a main form with five sub forms contained within it, giving us all the relevant client information in one view. This works however is taking 24 seconds to load a single clients complete records.
I have looked at the SQL Server and found the absence of indexes, fixed this and got the time down to 24 seconds with consequent loads closer to 18 seconds depending on the client (some have a lot more records). This might be okay, as whilst this is a relative eternity in computing time in real world time its okay...but not great. I would like to see if I can get a better load by changing the way I connect and how the form is bound to the records etc.
In looking at the various ideas and reading a lot I found:
https://learn.microsoft.com/en-us/office/vba/access/concepts/activex-data-objects/bind-a-form-to-an-ado-recordset?source=docs
Which appealed to me as I am more inclined to use ADO, seldom if ever to I use DAO. ADO I understood originally was intended to use with SQL and so on, and it seems like a sensible idea.
Again as I understand it if I can get this to work it will act as a pass through query returning only one record over the net and should consequently speed my form up considerably. However it wont work.
My code is:
Private Sub cssSetForm(lngID As Long)
Dim cnn As New ADODB.Connection
Dim Rs1 As New ADODB.Recordset
Dim strSQL As String
Dim strR As String
cnn = "Provider=MSOLEDBSQL;Server=Server;Database=DatabaseName;UID=UserName; PWD=Password;"
cnn.Open
strSQL = "SELECT Clients.Clientid, Clients.AccountContact, Clients.AccountEmail, Clients.Address, Clients.Name, Clients.OfficePhone, Clients.PostCode, " & _
"Clients.ShentonAcc, Clients.Suburb FROM Clients WHERE (((Clients.Clientid)=" & lngID & "));"
With Rs1
Set .ActiveConnection = cnn
.Source = strSQL
.LockType = adLockPessimistic
.CursorType = adOpenKeyset
.Open
End With
Debug.Print Rs1.RecordCount
Me.Recordset = Rs1
End sub
Now I am getting no errors until Me.Recordset=rs1 which is generating an error 3251 Operation is not supported for this type of object which is very nice for someone that understands why this is not supported when it is no different than I can see to the example I was copying from.
I don't understand why the form I am working on doesn't support recordsets according to the error message? Is there an error in my code? Is the error in my understanding of the destructions from the linked site? Is the error something else?
Thanks for the help
Well, loading up 5 sub forms is a lot of data pulling. converting to ado reocdsets is NOT going to speed this up.
What you want to do here is NOT load up the sub forms until such time the user say clicks on the appropriate tab to load the one given sub form.
As long as the form in question is opened with a were clause, then the one main form will ONLY pull the one main record from sql server. So doing all kinds of fancy reocrdsets etc. will gain you next to nothing. So, always - but always launch your main form to the one record. If that main form is bound to a table of 5,000 rows, or 1 million rows, it will load instant despite the fact that the form is bound directly to the linked table with 1 million rows.
With this one main form, you edit or do whatever, and then close it. You are then of course right back to the search form/prompt you have to ask the user what reocrd to work on. So, how a accouting package works, or even google? You search, display the search resutlts and pick ONE thing to view. This approach should get your main form load down to about 1 second. Again, just use the "where" clause when you open that form:
eg:
dim strInv as string
strInv = InputBox("Enter invoice number to view")
docmd.OpenForm "frmInvoice",,,"InvoiceNum = " & strInv
Of course the above is air code, and you will likely build some search form say like this:
So in above, the user types in a bit of the name. We then fill the form with a simple where clause, or
me.MySubForm.RecordSource = "select * from tourCust where LastName like '" & sTextbox & "*'"
When a user clicks on the glasses icon to edit + view the ONE row, we use this:
docmd.OpenForm "frmDetails",,,"id = " & me!id
Again, all bound forms, and dispite the tables having 500,000+ rows, the loading of the forms is instant - even when the back end is SQL server.
So, adopt a prompt + search results + edit/view design pattern. EVERY single software system has this loop or design pattern. Not only is it user friendly, it also performs well since access DOES NOT pull the whole table, but ONLY the reocrds you tell the form to load by using the where clause as per above.
Now, for the child forms (sub forms).
As noted, don't load them until the user actually clicks on the given tab.
So, in the on-change event of the tab, you can go:
If Me.TabMainpage.Pages(Me.TabMainpage).Name = Me.pgeDocs.Name Then
'' the tab been changed to show past tours
dim strSQL as string
strSQL = "select * from tblPastTours where tour_ID = " & me!ID
me.
' dynamic load the sub form
If Me.frmSubPastTours .SourceObject = "" Then
Me.frmSubPastTours.SourceObject = "Forms.frmPastTours"
End If
' now load sql into form
me.frmSubPastTours.Form.RecordSource = strSQL
The above is mostly air code, but the idea here is:
don't load the sub form until you need to.
OR YOU can have the sub form load, but leave its RecordSource blank and STUFF in the sql you need for display WHEN you click on the tab.
It is possible that you need all sub forms to display. You could thus leave all sub form RecordSource blank, and then it the main form on-load event, simply stuff in the sql to each sub form. This might improve speed a bit, and with your slower connection this would be the least amount of work.
You "fail" to mention how you launch + load the main form, but as noted, it should be opend to the ONE reocrd. The link master/child pulling of data can be bit slow, and I can't say JUST using the above sql stuff into those forms will help a lot. I would try that first as it is the least amount of work. If load time is still too slow, then placing te sub forms behind a tab control and ONLY loading the sub form, and then setting the datasource will be the fastest.
Attempting to build all those recordsets, and then bind them to a form? It not speed things up, and just shoving a sql string into the form (or sub form) recordSource amounts to really the SAME thing and same performance anyway. So, you save tons of work and code, and quite much the above idea not only applies to sql server back ends, but we all VERY often dynamic load sub-forms and don't load them until such time you view the sub form say behind a tab control.

Running a report directly and from a navigation form - reference issue

I have a form in MS Access (365) which accepts various selection criteria and runs a report with those criteria built into the wherecondition of a DoCmd.OpenReport command. The report is run via a button with On Click VBA code, since the wherecondition has to be built according to which, if any, criteria have been chosen. That all works fine when I open the selection criteria form directly. I want to open the selection criteria form via a navigation form, since there will be other, similar reports with selection criteria that I want to run from within the same navigation form.
As stated above, everything works when I open the selection criteria form directly and run the report but when I tried it via a navigation form, it didn't work. That's ok, I found a solution on the MS Dev Center site which works when I run the selection criteria form (and then the report) from the navigation form. All fine. But then (of course) the references within the button On Click code don't work when I open the selection criteria form directly and run the report. I would like to be able to run the selection criteria form and then the report from both positions - directly from MS Access and via the navigation form. There will presumably be some way to achieve this but (as I said above, I am new to MS Access and VBA) I could spend a lot of time clutching at shadows. Hopefully, someone will be able to tell me the simplest way to do this?
Code sample with relevant comments below. On runnning the selection criteria form and report directly, the line commented as AAA works ok, MsgBox ABB and DDD and those beyond all show; on running them via the navigation form, line BBB works ok, MsgBox ABB and DDD and those beyond all show (well, they would except that I haven't yet coded the [NavigationSubform] option into all the other whereconditon building stuff). When I switch the lines AAA and BBB (ie, comment the other one out) MsgBox AAA show ok, then it fails with:
Can't find referenced form "frmSelectSpeciesSiteDates"
before reaching MsgBox DDD.
MsgBox "ABB"
'If Not Forms![frmSelectSpeciesSiteDates]![cboCommonName] = "" Then
' AAA Works when frmSelectSpeciesSiteDates is run directly
If Not Forms![frmNavSelectiveReports]![NavigationSubform].[Form]![cboCommonName] = "" Then
' BBB Works when frmSelectSpeciesSiteDates is called from a navigation form
strWhereCondition = strWhereCondition & "[common name] = " & Chr(34) & Me![cboCommonName] & Chr(34)
End If
MsgBox "DDD"
You have a form named frmSelectSpeciesSiteDates which has a combobox named cboCommonName. The form also includes VBA code which uses the combobox value to modify a string variable ...
strWhereCondition = strWhereCondition & "[common name] = " & Chr(34) & Me![cboCommonName] & Chr(34)
However you only want to modify the string when the combobox contains something other than an empty string. And that is where you're struggling. You reference the combobox one way when the form is opened directly as a top-level form, and another way when it is contained in a navigation form ...
Forms![frmSelectSpeciesSiteDates]![cboCommonName]
Forms![frmNavSelectiveReports]![NavigationSubform].[Form]![cboCommonName]
I suggest you abandon both of those and refer to the combobox the same as where you modify the string (Me!cboCommonName) ...
If Not Me!cboCommonName = "" Then
strWhereCondition = strWhereCondition & "[common name] = " & Chr(34) & Me!cboCommonName & Chr(34)
End If

Access VBA unable to refresh a form

I have a form (frmDropDownEdit) that has a filtered table as the data. A "New" button is created that opens another form (frmDropDownNew) and the user can enter new data. When complete the new form is closed and the user is back to the original form. The code for frmDropDownNew correctly add the info to the table, then the code refreshes the frmDropDownEdit form but it does not refresh. If I click the refresh button in the ribbon, it also does not refresh. But refresh all does work.
How can I have my code refresh the data in frmDropDownEdit. I also put code me.refresh on the OnGotFocus event but that does not even run.
Here is my source code
Private Sub Command5_Click()
'Add Button
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset("tblDropDown")
rst.AddNew
rst!DdCategory = Me.txtCategory.Value
rst!DdDescription = UCase(Me.txtDescription.Value)
rst.Update
rst.Close
DoCmd.Close
Forms!frmDropDownEdit.Refresh
End Sub
On my MS Access 2010 ×64 single user PC, Forms![AnyForm] .Refresh never worked in VBA, independently where it is placed in any database's code. Form_Current() doesn't run either as it should after data are modified (verified by putting a Stop therein). Moreover, records with modified data are neither marked dirty nor refreshed before the vba code has finished. Procedures which should run without delay when data are modified don't run, even when placed into the modified fields' events.
Thus, one has to use a work-around. Many people recommend to use .Requery instead of .Refresh and then to return by vba code to the desired record, but this requires a field with a primary key.
My solution for tables without primary key is the following:
'…
' ESSENTIAL: this code must be run from ANOTHER module !
' (it runs without error in MyForm's own code [eg. in Form_Activate(),
' but then MyForm is NOT immediately refreshed as desired,)
' one still has to repeat these steps by hand afterwards…
DoCmd.GoToRecord acForm, "MyForm", acNext
DoCmd.GoToRecord acForm, "MyForm", acPrevious
' NB: Forms![MyForm].Refresh doesn't work
' at this place in "MyOtherModule" either.
'…
As mentioned in above code comments: this code must be run from another module ("MyOtherModule") - in my case, a form-independent procedure called upon closing a pop-up form opened from the first form, which interactively modifies data. These data should be updated/refreshed immediately when closing the pop-up form, reflecting all changes and their consequences (for example, automatic filling-in/deleting of other data and/or en/disabling controls or making them [in]visible, depending on the modified fields' values).