Role-based Form recordsource - forms

Is there a best practice around opening a form based on recordsources whose columns are limited by the user's role?
We have some users who modify data that don't want to see the columns marking criteria for inclusion on different reports (columns with boolean values named isOnRpt1, isOnRpt2, etc. used for filtering purposes) and other users who only run reports that need to sort and filter data but not see columns used for internal calculations. Say we have 65 columns total and everyone wants to see the same 5 key columns and 10 filtering columns but some users need visibility of 30 additional columns and others want to see 20 other columns. What I have now is the God view with all of everyone's columns, and it's freaking them out.
Is there a best practice for maintaining a form for users in different roles whose datasheet view contains different subsets of columns? I'm not worried about visibility of controls on the form view, users in the reporter role won't use that view at all.
I don't want to create different forms for each role (frmDetailReporter, frmDetailWriter) whose only difference is the qry in the recordsource property. I have a main form staff in any role could use to navigate to a role-specific instance of this detail form (they need to navigate to other forms with aggregate data) but I'm not sure if I should have an entry point for each role in the form's VBA code or change the recordsource property before opening the form or if there's a better way to support users of different views of the same data source.
TIA
Let's say I've identified two roles, Reporter and Writer. I can create two queries for those roles, qryDetailReporter and qryDetailWriter with different columns. I have two buttons on a main form for the two different roles, btnDetailReporter and btnDetailWriter used to open the shared detail form, frmDetail, containing all the VBA code for all the roles. Is there a best practice for the VBA code behind frmMain.btnDetail* for loading frmDetail? I'd like to set the recordsource property to one of the two queries before loading the form, but Access forms don't work that way, so I'm thinking I could have a global variable containing a roleID referenced in frmDetail's load event that sets the recordsource property, but I'd prefer to do this without a global variable.
Here's what I have now:
' module
Public g_roleID As Integer
' frmMain
Private Sub btnDetailWriter_Click()
g_roleID = 1
DoCmd.OpenForm "frmDetail", acFormDS
End Sub
Private Sub btnDetailReporter_Click()
g_roleID = 0
DoCmd.OpenForm "frmDetail", acFormDS
End Sub
' frmDetail
Private Sub Form_Open(Cancel As Integer)
Dim objCtl As Control
Dim sTxt As String
Dim sFld As String
Select Case g_roleID
Case 0
RecordSource = "qryDetailReporter"
Case 1
RecordSource = "qryDetailWriter"
Case Else
RecordSource = "vw_detail"
End Select
On Error GoTo noFld
For Each objCtl In Controls
Select Case objCtl.ControlType
Case acTextBox, acComboBox
sTxt = objCtl.ControlSource
objCtl.ColumnHidden = False
sFld = RecordsetClone.Fields(sTxt) & ""
End Select
Next
Exit Sub
noFld:
objCtl.ColumnHidden = True
Resume Next
End Sub

I would suggest to create different queries for each role with different set of fields and change RecordSource property of form depending on user role. The form should have set of all available columns. After selecting required recordsource a simple VBA code should compare set of available fields in recordsource with set of ControlSource properties of each form's control. If the field is missing in recordsource, hide the column using ColumnHidden control's property.

Related

How do I search forms in Access using values from another table that is being referenced?

The management staff in my department has been asked to record any and all errors committed by our team. I created a database to store them and a simple form for the management team to use to record each error. Several fields are referencing other tables such as Staff, issue category, root cause, etc...
We need to be able to search the forms for specific records to either update or review, and I have found the best way for us to search is by filtering the forms based on the individual who committed the error. Here is the code that I am using for the search button:
Private Sub SearchRecord_Click()
Dim Search As String
Search = InputBox("Please enter who committed the error", "Name", ErrorMadeBy)
If Search = "" Then Exit Sub
Me.Filter = "ErrorMadeBy = """" & Search & """
Me.FilterOn = True
End Sub
The filter works great, but instead of filling out the name, you have to use the ID number in the Staff table when filling out the Input Box. I'd like to be able to input the name (or part of the name) instead of having to have everyone memorize the ID numbers from the staff table.
What I do in these cases?
Fire up the query builder - left join in those extra tables (with the text parts in place of the id).
So be it a part number, quote number for a project etc? Just left join in those tables in the query builder and save that query.
Now, your search box and code can be somthing like:
dim rst as DAO.RecordSet
strSQL = "Select * from MyCoolQuery where PartName like '" & txtPartName & "*'"
set rst = currentdb.OpenRecordSet(strSQL)
if rst.EOF = false then
me.RecordSet.FindFirst "PartID = " & rst!PartID
end if
In fact, you can even often left join in those extra tables right into the current form, and even use ctrl-f to search if the said text boxes are place on the given form. However, I tend to separate out the search process from the actual form. So I might build a search form, say like this:
So in above, they can search say by a Hotel name, or project name or whatever. Becuase the one query has the text parts, then they can be searched. But I put the query results into a grid and each row of course has the PK ID, and thus a search could result in 10 matches, they are now free to click on any row - and i jump to the form to display the one records.
eg: the row click button does this:
docmd.OpenForm "frmTourBooking",,,"ID = " & me!ID
So, this makes for a great work flow. Users search, see, pick and then jump to the form with the one record, and then close and return back to search form - and often it has the several "hits" from that search that you want to work on anyway.

MS Access - Advancing through record groups

I have a form with a subform. The record source for the subform is as follows:
SELECT [firstID], [secondID], [AAA], [BBB], [CCC], [DDD]
FROM Table1
WHERE firstID = [Forms].[frm1].[txtfirstID];
The subform groups the records together on the basis of txtfirstID but when I advance through the record selector it goes through every record, as expected. I would like to know if there is a way to click through the groups rather than each record within each group. I'm open to any way of doing it. Perhaps filtering through VBA??
Thanks!
First, add a combo box to your form. Set the RecordSource for the combo box to a distinct list of groups, or, if you have a group lookup table, select * from tblGroups. Set the display field to be group name, and the value field to be group id.
Second, after an item is selected from the combo box, modify the RecordSource sql of the form (your query) so that it uses the current value of the combo box. The value of the combobox would be what your where clause should be looking for.
I think you can do two ways to solve this:
1.- If you related main form to subform by a field. In this case TxtFirstID of Main to FirstID of subform. It do all work when change main form and filter automatically on subform
2.- You can do and event OnChange form TxtFirstID on main form.
Sub TxtFirstID_Change()
Me.subfrmName.Form.RecordSource = "Select * from table1 where firstID=" & Me.TxtFirstID 'change the record source for the SubForm
me.subfrmName.Form.Requery 'Force Access to refresh the Record Source
end sub

How to add a multiple values field to an MS Access form

I have a database which records and tracks the training records for each employee within our group of companies.
One of the forms on the database is 'add training record' and currently this is done per person ID, adding the course id, date, certificate, etc. What I would love to do is be able to add multiple person IDs, as a number of people can attend the same course/ date, so I have to add the course details in many times, which is very time consuming and annoying.
You're going to need extensive VBA behind the scenes to do this, as well as a couple of controls to make your life easier (multi-select combo or list boxes). You could do it in a text box if you want, using the semi-colon between User IDs.
Since the text box is easier, let's look at that. What you would do is have something like this behind the Submit button:
Dim db as Database
Dim rec as Recordset
Dim str as String
Set db = CurrentDB
Set rec = db.OpenRecordSet("SELECT * FROM tblMyTable")
'Throw the User IDs into an array
Dim var As Variant
Dim i As Long
str = me.txtUserIDs
var = Split(str, ";")
'For every User ID, add a new record to the database
For i = 0 To UBound(var)
rec.AddNew
rec("UserID") = var(i)
rec("CourseID") = Me.txtCourseID
rec("CourseDate") = Me.txtCourseDate
'ETC... adding fields as needed
rec.Update
Next i
This is completely off-the-cuff and (of course) requires you to change the appropriate variable names, but it should give you a solid outline for how to solve the problem.

How to limit which fields can be updated in a form?

I am making a form in MS Access 2013 and it has 5 fields, this form is used to create an "Event." When creating an event, all 5 fields are used. However, the same form is also used to update an event. When updating an event, only three of the fields should be changed. How can I make it so that two of the fields are ignored when updating? I do not want to make a separate form for updating.
One option would be to set field.enabled = false if the primary key of a record (shoudl be a field of type autovalue) is set to a value in the Form_Current trogger, i.e. do something like this:
Private Sub Form_Current()
If IsNull(Me!pk) Then
Me!Field.Enabled = True
Else
Me!Field.Enabled = False
End If
End Sub
(just replace pk and Field with your real field names)

How to create a universal MS Access form?

I have a database that has a two tables which differ only in several fields so I thought of creating a single form for them and adding an option group (radio switch) witch would determine to which table the data from fields should go. The thing i I dont know how to hange the destination and some field should be hidden or at least on one but not another option.
This gave me an idea that for small databases this could be used to create universal form.
How to control data destination from form field in MS Access depending on option goup?
You can call different tables based on variables you create in a blank form. Here's an example if you use the table name in a combo box.
Dim var as String
Dim myR as Recordset
var = me.combo_box_name.column(0)
Set myR = CurrentDb.OpenRecordset (var, dbOpenDynaset)
'Code here based on variable, use an if statement if you want
Set myR = Nothing