Subform to search record on main form - forms

I have a subform like so:
When i click the 'select' button, i wish for the record on the main form to navigate to the appropriate one (the one which holds the same Staff ID).
What I have tried so far is for when the button is pressed to run the following vba:
Private Sub Command6_Click()
Dim rs As Object
Dim strLinkValue As String
strLinkValue = Forms![navigation form]![NavigationSubform]![teacher search qry subform]![Staff ID].Value
Set rs = Forms![navigation form]![NavigationSubform]![teacher search qry subform].Form.RecordsetClone
rs.FindFirst "[Staff ID] = '" & strLinkValue & "'"
Forms![navigation form]![NavigationSubform].Bookmark = rs.Bookmark
End Sub
But when I do this I get run-time error 438 (object doesn't support this property or method).
Any ideas? I feel like I'm over-complicating things.

You first got error 438 ("Object doesn't support this property or method.") at this line ...
Set rs = Forms![navigation form]![NavigationSubform].Recordset.Clone
Changing from Recordset.Clone to Form.RecordsetClone cured the error (at that line).
Unfortunately you then got error 438 again when attempting to set Bookmark at this line ...
Forms![navigation form]![NavigationSubform].Bookmark = rs.Bookmark
The reason for the error at that point was because [NavigationSubform] is a subform control, and a control does not have a Bookmark property. You need to set the Bookmark on the Form contained within that control.
This code does what I believe you want. I tested it in Access 2010 with a copy of your database.
Dim rs As DAO.Recordset
Dim strLinkValue As String
strLinkValue = Me![Staff ID].Value
With Me.Parent.Form
Set rs = .RecordsetClone
rs.FindFirst "[Staff ID] = '" & strLinkValue & "'"
.Bookmark = rs.Bookmark
End With

Related

Navigate programmatically through the records of a continuous form

I would like to navigate through the records of a continuous form in Access 97. I don't find how to do it. This is what I tried:
Me.RecordSetClone.MoveFirst moves to the first record logically, but not in the UI. Also the CurrentRecord property does not change.
I cannot set the CurrentRecord property, it is readonly. Me.CurrentRecord = 1 gives an error.
DoCmd.GoToRecord Record:=acFirst seems to have no effect.
What is the correct way to move to the first record in a continuous form (and to the next/previous)?
Use the Bookmark property of RecordsetClone and Form.
Caveat: I'm pretty sure all this worked in Access 97, but that was a really long time ago.
Sub DemoNavigate()
Dim RS As DAO.Recordset
Set RS = Me.RecordsetClone
RS.MoveFirst
' or
RS.AbsolutePosition = 0
' Navigate in form
Me.Bookmark = RS.Bookmark
' next record
RS.MoveNext
' or
RS.AbsolutePosition = 1
Me.Bookmark = RS.Bookmark
' Move to searched record
RS.FindFirst "someField = 42"
Me.Bookmark = RS.Bookmark
End Sub

MS Access: Link listbox to textbox

I have a textbox and listbox, one is for entering a new topic in a help form while the other looks up those new topics. I would like to be able to present the finished topics in both the textbox and listbox simultaneously to edit or lookup as well write new records in the help form. The listbox provides functionality to view which records there are now.
I find if I put nothing in and I go to a new record the prev/next buttons will stop working, maybe there is a control I need to add to keep it from freezing or to refresh? Normally I press esc to get out of a new record edit and return to others but that does not work as usual.
Or how else may I point to the listbox's current record source?
I currently have this code:
Private Sub List35_AfterUpdate()
DoCmd.GoToRecord acDataForm, "Help Form_Editor2", acGoTo, Me.List35.ListIndex + 1
Me.List35 = Me.List35.Column(0, Form.CurrentRecord - 1)
Dim index As Integer
index = Form.CurrentRecord - 1
Me.Text53 = Me.List35.Column(Me.List35.ListIndex + 1, index)
End Sub
I keep getting some of the items to read but others are null. I have about 8 items in the source table... what is going wrong? Why would there be nulls?
Another issue after getting this updated. When the code is setup the recordset starts at new when I allow additions and edits on the form. The code displays the list item as it should but the other items will not activate from the requeried listbox item. What might correct this issue?
Private Sub List35_AfterUpdate()
Dim myTitle As String
With Me.List35
If .ListIndex > -1 Then
'Use this one if you are using bound column
myTitle = .Column(1, Form.CurrentRecord)
'use this if you want something other than the bound column
'and you have more than one column in the list (hidden or not)
'nId = .Column(1, .ListIndex)
Me.RecordSource = "SELECT * FROM FormsHelpTable WHERE HelpTitle = '" & myTitle & "'"
Me.Text53.Value = myTitle
Else
Me.RecordSource = "SELECT * FROM FormsHelpTable WHERE HelpTitle IS NULL"
'Me.Text53.Value = "(New)"
End If
End With
Me.Requery
End Sub
This checks for ListIndex. It will be -1 if you don't have anything selected.
Private Sub List35_AfterUpdate()
Dim index As Integer
With Me.List35
If .ListIndex > -1 Then
DoCmd.GoToRecord acDataForm, "Help Form_Editor2", acGoTo, .ListIndex + 1
.Value = .Column(0, Form.CurrentRecord - 1)
index = Form.CurrentRecord - 1
Me.Text53 = .Column(.ListIndex + 1, index)
End If
End With
End Sub
I'm not sure what all your code is trying to do, so I didn't make any other adjustments other than to reduce all references to List35 to a single With statement.
I normally do something like this:
Private Sub List35_AfterUpdate()
Dim nId As Long
With Me.List35
If .ListIndex > -1 Then
'Use this one if you are using bound column
nId = .Value
'use this if you want something other than the bound column
'and you have more than one column in the list (hidden or not)
'nId = .Column(1, .ListIndex)
Me.RecordSource = "SELECT * FROM TableName WHERE Id = " & nId
Else
Me.RecordSource = "SELECT * FROM TableName WHERE Id IS NULL"
End If
End With
Me.Requery
End Sub

Filter form based on unbound control value

I have a form bound to a query, except for one field that I am leaving unbound. The idea is that the user will enter a value in that textbox and press a button to bring up the record. I have some code that I thought would work based on the interwebs. When I use DoCmd.ApplyFilter(filter_string) I get a popup asking for the value to filter on (which is not what I want). When I go ahead and paste it in, the form does not get filled. When I use Me.Form.Filter = filter_string, sometimes the form fills, but always with the same record, regardless of what the filter_string says. An example filter_string is
filter_string = "InventoryDetailsID = 'B01MFC000100/01'"
I have another similar form that, instead of filling with an existing query, generates the query (with 5 joins) and fills the form from the resulting recordset. It works just fine, but is slow because it has to run the query each time. That is why I want to use a method where I generate the query once, and then filter it.
Edit
Oh, and I also tried using a variant on the run-the-query-every-time approach, where I query the already generated query (the one I'm trying to filter). I'm using:
query_string = "SELECT * FROM qry_ISBN_All WHERE InventoryDetailsID LIKE '" & Me.InventoryDetailsID & "';"
But I get the error Run-time error '3061' Too few parameters, expected 1
Edit II
Private Sub btn_Seek_Click()
Dim temp As String
filter_string = "InventoryDetailsID = '" & Me.InventoryDetailsID & "'"
Me.temp = filter_string
Me.FilterOn = True
Me.Form.Filter = filter_string
Me.FilterOn = True
'DoCmd.ApplyFilter (filter_string)
' Dim query_string As String
' query_string = "SELECT * FROM qry_ISBN_All WHERE InventoryDetailsID LIKE '" & Me.InventoryDetailsID & "';"
End Sub
Typical filter string is given. It is printed to the form control Me.temp.
After this line:
Me.Filter = filter_string
Add this in:
Me.FilterOn = True
Also I agree, run the query every time approach is definitely overkill. The filter should provide you with the functionality you seek. You just simply have to "turn it on" after you set it.

Loop through fields of recordset to populate form?

I'm trying to use a For loop to loop through the fields in a single record recordset to populate the fields on a form. I was hoping to find a way that is neater/reusable than typing out half a dozen lines of txtField.value = rs!Field.
When I look at the code during runtime both variables have the correct information in them, it just isn't displaying them on the form. Any help would be greatly appreciated.
Dim strClient As String
Dim rsClient As dao.Recordset
Dim tfield As String
Dim ffiend As String
Dim fld As dao.Field
Set dbs_Current = CurrentDb()
strClient = "Select * from tblClient where pk_client_id = " & gbl_Client_ID
Set rsClient = dbs_Current.OpenRecordset(strClient)
For Each fld In rsClient.Fields
On Error Resume Next
tfield = "txt" & fld.Name & ".value"
ffield = "rsClient!" & fld.Name
tfield = ffield
Next fld

Displaying a recordset on a form in Access 2010 using VBA

I'm developing a data retrieval application in Access 2010 in which the user chooses which table, columns, and rows to view by selecting listbox entries. The VBA code generates a SQL statement from these choices and then creates an ADBDB.Recordset object from this.
How can I display the recordset records in Access? None of the grid controls work in Access 2010 and the subform just isn't designed for this purpose. Can someone recommend another strategy?
You could save the SELECT statement as a named query, then open the query as a datasheet. It's not really a form, but somewhat form-like.
Call DatasheetFromSql(strSql)
Public Sub DatasheetFromSql(ByVal pSql As String)
Const cstrQuery As String = "qryDiscardMe"
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim strMsg As String
On Error GoTo ErrorHandler
Set db = CurrentDb
db.QueryDefs.Delete cstrQuery
Set qdf = db.CreateQueryDef(cstrQuery, pSql)
DoCmd.OpenQuery cstrQuery, , acReadOnly
ExitHere:
On Error GoTo 0
Set qdf = Nothing
Set db = Nothing
Exit Sub
ErrorHandler:
Select Case Err.Number
Case 3265 ' Item not found in this collection. '
Resume Next
Case Else
strMsg = "Error " & Err.Number & " (" & Err.description _
& ") in procedure DatasheetFromSql"
MsgBox strMsg
GoTo ExitHere
End Select
End Sub
I opened the query read-only. If you want to allow users to edit the data returned by their custom queries, I would not recommend this approach. Instead I would invest the effort in the approach HK1 offered because it can support better control of the user data changes.
With the query opened as a datasheet, you can use Screen.ActiveDatasheet to inspect its properties. At least some of the methods are also available to you. For example you could resize/reposition the datasheet like this:
Screen.ActiveDatasheet.Move Left:=0, Top:=0, Width:=(4 * 1440), Height:=(3 * 1440)
The units are twips (1440 twips / inch), so that would make the width 4 in., height 3 in., and move it to the upper left corner of the Access window.
Here's what I think you'll have to do to get this kind of functionality.
You'll first need to create enough of the correct controls on a form to handle every possible scenario. You'll then need to set the form to be a datasheet form so that it appears as a grid.
Now set the controlsource on your controls to correspond with one of the fields in the recordset. On every control that is not in use needs to have it's ColumnHidden property set to true. You'll also have to change the caption of the associated label to show the appropriate column name for each control that will be visible.
Now, bind that form to your ADO recordset object.
Me.Recordset = rst
'or
Me.Subform1.Form.Recordset = rst
Is this a perfect solution? Most certainly not. Access doesn't have anything that compares to the DataGridView in .Net or even to the Grid controls that are used in VB6. In my opinion, you're really pushing the limits of Access to try to get this sort of functionality. It's like swimming upstream. You'll find that everything you do is going to be fairly difficult and some things just aren't going to be possible.
for an ADP Project where you can't have local MS Access query definitions, you can create a datasheet form with multiple textboxs named txt1, txt2,.... txt30 and labels name lbl1 ... lb30 and this code will set the form.recordsource and set the textbox.controlsource and the label.caption to the appropriate fields from an ADO recordset object. This form will allow you to view your ADO Recordset similar to the Docmd.OpenQuery method.
You must pass the ADO recordset's SQL statement to the form using the OpenArgs property of the form. the code below shows the VBA code to call\open the form (which shows the ADO Recordset like a query) and pass your sql string. The vba code on the form's load event will set all the control properties, resize the columns that have data and hide the columns that do not have a corresponding field from the ado recordset:
'stevekirchner 09/29/2012 Replace Access parameterized query with SQL Server in-line function
'DoCmd.OpenQuery "qry_SearchMaster_CaseTitles", , acReadOnly
strsql = "Select * from dbo.UDF__qry_SearchMaster_CaseTitles ('%" & Me.tbxSearchTerm.Value & "%') "
Call Display_ADO_Recordset_from_Datasheet_Form(strsql, "frm_Display_ADO_Recordset_Result1")
'create a non-form module and put the code for the sub Display_ADO_Recordset_from_Datasheet_Form
'and function fIsLoaded in it (this will allow you make several forms to view ADO recordset and
'call the code from one place\module):
Sub Display_ADO_Recordset_from_Datasheet_Form(sSQL As String, sFormName As String)
On Error GoTo Error_Handler
If fIsLoaded(sFormName) Then
DoCmd.Close acForm, sFormName
End If
DoCmd.OpenForm sFormName, acFormDS, , , acFormReadOnly, , OpenArgs:=sSQL
Exit_Sub:
Exit Sub
Error_Handler:
MsgBox Err.Description & " Error No: " & CStr(Err.Number)
Resume Exit_Sub
End Sub
Function fIsLoaded(ByVal strFormname As String) As Boolean
On Error GoTo Error_Handler
'Returns False if form is not open or True if Open
If SysCmd(acSysCmdGetObjectState, acForm, strFormname) <> 0 Then
If Forms(strFormname).CurrentView <> 0 Then
fIsLoaded = True
End If
End If
Exit_Function:
Exit Function
Error_Handler:
MsgBox Err.Description & " Error No: " & CStr(Err.Number)
fIsLoaded = False
Resume Exit_Function
End Function
'Create a datasheet view form (named frm_Display_ADO_Recordset_Result1) with 30 textboxes and 30
'30 labels named txt1 - txt30 and lbl1 - lbl30 and put this code in the form's module:
Option Compare Database
Private Sub Form_Load()
On Error GoTo Error_Handler
Dim conn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim rsClone As ADODB.Recordset
Dim strsql As String
Set conn = CurrentProject.Connection
Set rs = New ADODB.Recordset
strsql = Me.OpenArgs
rs.Open strsql, conn, adOpenStatic, adLockOptimistic
Set rsClone = rs.Clone
Call Update_Form_Controls("your text goes here", strsql, rsClone)
Exit_Sub:
rs.Close
conn.Close
Set rs = Nothing
Set conn = Nothing
Exit Sub
Error_Handler:
MsgBox Err.Description & "; Error Number : " & Err.Number, vbOKOnly
Resume Exit_Sub
End Sub
Sub Update_Form_Controls(Header_Label As String, SQL As String, CloneRS As Recordset)
Dim rsCount As Integer
Dim i As Integer
On Error GoTo Error_Handler
Me.Form.Caption = Replace(SQL, "Select * From ", "Display: ")
rsCount = CloneRS.RecordCount
If rsCount <= 0 Then
MsgBox "The Query did not return any data to view", vbOKOnly
DoCmd.Close
Else
Me.Form.SetFocus
Me.RecordSource = SQL
i = 1
Do Until i = 31
Me("lbl" & i).Caption = ""
Me("txt" & i).ControlSource = ""
Me("txt" & i).ColumnHidden = True
i = i + 1
Loop
i = 1
With CloneRS
For Each Field In .Fields
On Error Resume Next
Me("lbl" & i).Caption = .Fields(i - 1).Name
Me("txt" & i).ControlSource = .Fields(i - 1).Name
Me("lbl" & i).Visible = True
Me("txt" & i).ColumnHidden = False
Me("txt" & i).SizeToFit
i = i + 1
'Debug.Print Field.Name
On Error GoTo 0
Next Field
End With
End If
Exit_Sub:
Me.Requery
Exit Sub
Error_Handler:
MsgBox Err.Description & "; Error Number : " & Err.Number, vbOKOnly
Resume Exit_Sub
End Sub
I don't use ADO but simply VBA, in which case above approach is wrong: one doesn't need any means for displaying an existing recordset in a form, but should on the contrary define an adequate recordset within the form !
Instead of creating MyDataBase.OpenRecordset ("SELECT … [SQL query] ;"), just set the form's RecordSource to the very same query definition:
Forms![MyDisplayForm].RecordSource = "SELECT … [SQL query] ;"
Forms![MyDisplayForm].Requery
For me this works perfectly (Windows 7 pro ×64 / MS Office pro ×64)