Updating subforms

garywood84

Registered User.
Local time
Today, 18:46
Joined
Apr 12, 2006
Messages
168
I have a form with a subform. The subform displays the results of a query, as a datasheet view below the items on the main form (i.e. it's effectively a copy of what you can see if you open up the query itself in datasheet view, but neater because it's in the same window).

The query changes frequently to include different fields. Is there a way that I can make the subform update so that it always shows all the fields that the query contains?

At the moment I can't find a way to do this: the subform always tries to display the fields that the query had in it when the subform was created and, if those fields are no longer there, it just puts #!Name in the field!

Thanks in advance if anyone can help.

Gary
 
When you change the query, capture the SQL statement and store
it in a string variable. Use this string as the record source of your
subform.

e.g. Me.subformName.recordsource = your string variable

I believe this will work.
 
Thanks, edtab.

I'm not sure what you mean by "capturing the SQL statement and storing it as a string variable" - I'm new to VBA and would be grateful if you could tell me how to do this.

However, what I have tried is copying the SQL statement manually and entering it as the record source of a blank subform. This works, in that the subform then has the right record source and, in design view, I can add the fields in the SQL query to the form.

The problem is that unless I manually add the fields to the form in this way, the datasheet just shows up blank. How can I tell the form to always show all fields available in the record source?

Thanks again for your help so far and for any further assistance you can offer.

Cheers,

Gary
 
If you post your db with some test records, I will see if I
can help you further.

I need to know how you are changing your query/SLQ ie.
what triggers the change or are you always manually changing it?
 
edtab,

Many thanks for this. Please find attached a very cut down version of my database with the relevant tables, forms and queries and some dummy data.

When you open this, you'll see a form called "Set Query Options". Open this and select options with its controls to set query criteria (NB - there's not much dummy data so don't be too specific!!). When you click the OK button, "BaseQuery" will open to display the results. (Note that "BaseQuery" is a saved query that gets fed an SQL statement by code behind the OK button to update what it displays in line with your selections on the form).

So far, all of this is working as I want it to. However, you'll see that there are also two other forms. "Query Results" is the main form and "BaseQuery subform" a subform which is displayed on it. I want this subform to display everything from "BaseQuery", in datasheet view. I will then change the code which works the OK button "Set Query Options" form so that it opens the "Query Results" form instead of "Base Query".

Doing this is problematic, though, because the saved "BaseQuery subform" has fields on it for all the fields that were in "BaseQuery" when the subform was made. Depending on the selections you made in "Set Query Options" some of these fields may no longer be in BaseQuery and hence the subform doesn't work.

What I need to do, therefore, find some way to make "BaseQuery subform" a blank form, but have some code running somewhere which automatically picks up all the available fields from "BaseQuery" as the form loads and adds those fields to the view so they are visible.

I hope this makes sense and that you'll be able to advise me further. However, if you need any more information or any of it isn't clear, please let me know.

Cheers,

Gary
 

Attachments

Now that I fully understand the nature of your problem,
I must say that it is one of the toughest I have come across.
I spent a good hour on it last night, but to no avail.

Basically, what needs to happen is for the field contents of your
subform to match the underlying query "on the fly" ie. if there
are only 5 fields chosen, then your subform structure must
change to show only these 5 fields. You can not prepare your
subform format ahead of time, as there are a number of possible
combinations depending on what the user chooses.
The change in the subform structure needs to be done via vba code
- however, I'm not sure if this is possible at this point in time.

I don't know if it is an absolute must for you to allow the users
to pick the field combinaton to display, but it if you can skip this
part, then it should work everytime.

You might want to consider the above suggestion and make your
subform "continuous". I think you have a total of 16 fields to display -
you can design it in such a way that you'll have 2 lines of 8 fields
for each record. This way, it would be easy for the user to read the results
even with some of the fields being null or blank.
 
edtab,

Many thanks for your reply. I spent a bit more time looking in this problem this morning and came across the following post:
http://www.access-programmers.co.uk/forums/showthread.php?t=59959
which seems to be doing a similar thing to what I want.

Since I'm new to VBA I don't understand all of the code given in that thread, but I wonder if you (or anyone reading this!) can tell me if this code will do what I'm looking for, and, if so, perhaps provide me with some pointers on which bits I need to put in my code (using my previously attached example as a starting point) to make it work.

Cheers,

Gary
 
I have now managed to figure this out. However, the subform created is always called "form1" and this is not what I want. Can anyone advise how to modify my code, given below, to call the subform the current users' name, based on the strUserName variable?

Thanks,

Gary

Code:
Option Compare Database

Private Sub Command3_Click()

End Sub


Private Sub cboSort1_BeforeUpdate(Cancel As Integer)
'Check if sort field has already been chosen
    If Me.cboSort1.Value <> "Not sorted" Then
        If Me.cboSort1.Value = Me.cboSort2.Value _
        Or Me.cboSort1.Value = Me.cboSort3.Value Then
            MsgBox "You have already chosen that item."
            Cancel = True
            Me.cboSort1.Dropdown
        End If
    End If

End Sub

Private Sub cboSort1_Change()
'Disable following sort options if "Not sorted" is chosen
    If Me.cboSort1.Value = "Not sorted" Then
        With Me.cboSort2
            .Enabled = False
            .Value = "Not sorted"
        End With
        With Me.cboSort3
            .Enabled = False
            .Value = "Not sorted"
        End With
    Else
        Me.cboSort2.Enabled = True
    End If
End Sub

Private Sub cboSort2_BeforeUpdate(Cancel As Integer)
'Check if sort field has already been chosen
    If Me.cboSort1.Value <> "Not sorted" Then
        If Me.cboSort1.Value = Me.cboSort2.Value _
        Or Me.cboSort1.Value = Me.cboSort3.Value Then
            MsgBox "You have already chosen that item."
            Cancel = True
            Me.cboSort2.Dropdown
        End If
    End If
End Sub

Private Sub cboSort2_Change()
'Disable following sort options if "Not sorted" is chosen
    If Me.cboSort2.Value = "Not sorted" Then
        With Me.cboSort3
            .Enabled = False
            .Value = "Not sorted"
        End With
    Else
        Me.cboSort3.Enabled = True
    End If
End Sub

Private Sub cboSort3_BeforeUpdate(Cancel As Integer)
'Check if sort  field has already been chosen
    If Me.cboSort1.Value <> "Not sorted" Then
        If Me.cboSort1.Value = Me.cboSort3.Value _
        Or Me.cboSort2.Value = Me.cboSort3.Value Then
            MsgBox "You have already chosen that item."
            Cancel = True
            Me.cboSort3.Dropdown
        End If
    End If

End Sub

Private Sub cmdCancel_Click()
DoCmd.Close acForm, "DIAQRY_BaseQuery"
End Sub

Private Sub cmdOK_Click()

On Error Resume Next

Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim varItem As Variant
Dim strCriteria As String
Dim strCriteriaCtr As String
Dim strSortOrder As String
Dim strFieldList As String
Dim strSQL As String
Dim frm As Form
Dim subfrm As Control
Dim strQueryName As String
Dim strUserName As String

Set db = CurrentDb()
'Set qdf = db.QueryDefs("BaseQuery")
strUserName = Environ("username")
strQueryName = strUserName


'Build Criteria String
If Me!lstAB.ItemsSelected.Count > 0 Then
    For Each varItem In Me!lstAB.ItemsSelected
        strCriteria = strCriteria & "Centres.[Area Board] = " & Chr(34) _
            & Me!lstAB.ItemData(varItem) & Chr(34) & "OR "
    Next varItem
    strCriteria = Left(strCriteria, Len(strCriteria) - 3)
Else
    strCriteria = "Centres.[Area Board] Like '*'"
End If

If Me!lstCtrType.ItemsSelected.Count > 0 Then
    For Each varItem In Me!lstCtrType.ItemsSelected
        strCriteriaCtr = strCriteriaCtr & "Centres.[Centre Type] = " & Chr(34) _
            & Me!lstCtrType.ItemData(varItem) & Chr(34) & "OR "
    Next varItem
    strCriteriaCtr = Left(strCriteriaCtr, Len(strCriteriaCtr) - 3)
Else
    strCriteriaCtr = "Centres.[Centre Type] Like '*'"
End If


'Build sort order code
If Me.cboSort1.Value <> "Not sorted" Then
    strSortOrder = " ORDER BY Centres.[" & Me.cboSort1.Value & "]"
    If Me.cboSort2.Value <> "Not sorted" Then
        strSortOrder = strSortOrder & ",centres.[" & Me.cboSort2.Value & "]"
        If Me.cboSort3.Value <> "Not sorted" Then
            strSortOrder = strSortOrder & ",centres.[" & Me.cboSort3.Value & "]"
        End If
    End If
Else
    strSortOrder = ""
End If
              
              
'Build Field List
strFieldList = "Centres."
If Me!lstFieldList.ItemsSelected.Count > 0 Then
    For Each varItem In Me!lstFieldList.ItemsSelected
        strFieldList = strFieldList & "[" & Me!lstFieldList.ItemData(varItem) & "], "
    Next varItem
    strFieldList = Left(strFieldList, Len(strFieldList) - 2)
Else
    strFieldList = "*"
End If

     
strSQL = "SELECT " & strFieldList & " FROM Centres " & _
    "Where " & strCriteria & _
    " And " & strCriteriaCtr & strSortOrder & ";"
    
db.QueryDefs.Delete strQueryName
qdf.SQL = strSQL
Set qdf = db.CreateQueryDef(strUserName, strSQL)

Call fDelete_Form                                       'If subform already exists, delete it
Set frm = CreateForm()                                  'Create subform in memory
With frm
    .Caption = "My Form"
    .RecordSource = "BaseQuery"
    .DefaultView = 2                                    'Datasheet View
    .RecordSelectors = False
End With
Call fGet_Result_Columns                                'Determine which fields will be populating the subform
DoCmd.Save
DoCmd.Close acForm, "form1", acSaveYes                  'Needs to be unloaded to place it on the parent form
Set frm = Nothing
DoCmd.OpenForm "Query Results", acNormal                 'Open parent form
Set subfrm = Forms![Query Results]!subfrmResults
subfrm.SourceObject = "form1"
DoCmd.Save
Set subfrm = Nothing




Set db = Nothing
Set qdf = Nothing

End Sub

Private Sub Form_Current()

End Sub
Public Function fGet_Result_Columns()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim qry As DAO.QueryDef
Dim fldcount, i As Long
Set db = CurrentDb
Dim ctl As Control
Set rs = db.OpenRecordset("SELECT TOP 1 * FROM BaseQuery")       'Get a small recordset
fldcount = rs.Fields.Count                                       'so that we can Count
For Each qry In db.QueryDefs                                     'Column Headings
    If qry.Name = "BaseQuery" Then                               'Find the query, get the Column Names
        For i = 0 To (fldcount - 1)
            Set ctl = CreateControl("form1", acTextBox, acDetail, , _
                db.QueryDefs("BaseQuery").Fields(i).Name)        'Create controls equal to
            ctl.Name = db.QueryDefs("BaseQuery").Fields(i).Name  'Number of query fields
            ctl.Visible = True
        Next
    End If
Next
Set ctl = Nothing
Set rs = Nothing
Set db = Nothing
End Function


Public Function fDelete_Form()
'Find subform if it exists by looping through the forms collection and then delete it
Dim frm As Object
For Each frm In Application.CurrentProject.AllForms
    If frm.Name = "form1" Then
        DoCmd.DeleteObject acForm, "form1"
        Exit For
    End If
Next
Set frm = Nothing
End Function
 

Users who are viewing this thread

Back
Top Bottom