I had a similar situation with a promotion tracking system I wrote where each individual client could potentially have any of the available promotions assigned to them.
Here is what I did and I think it could be modified for your situation. Your contacts file would be related to your individual clients. So think of each individual client contact as a line item on an invoice. Each client could have multiple invoices with multiple lines.
Using FancyPrairie's excellent work above and modifying it just slightly, your base table for contacts would be tblClient.
Then I would add one table tlbClientContact. There would be one tblClientContact for each client contact incident. The reason for doing this is that it removes tblClient from this process (you could probably leave it out without causing a problem) and allows you to have a header type record for tracking client contact. To me, it is easier to visualize this process as a header and detail type situation.
So I would split FancyPrairie's tblContact as below:
tblClientContact
lngClientContactID (unique)
lngClientID (pointer to record in tblClient)
dtmContact (Date/Time client was contacted)
memComments
tblContact
lngClientContactID (pointer to record in tblClientContact)
lngStaffID (pointer to record in tblStaff)
After splitting the tables as above, the only thing left in tblContact is a pointer to tblClientContact and a pointer to tblStaff.
Now what you can do on your client contact form is to simululate creating a checkbox array. Use as many as you need and allow plenty of room for future expansion. So you name checkboxes as chkStaff00, chkStaff01, chkStaff02, ..., chkStaff24, chkStaff25, etc.
In form load processing build your checkbox captions on the fly from tblStaff. You can select staff names and keyids into an array and built them similar to this:
For intX = 0 To UBound(StaffArray, 2)
me("chkStaff" & intX).controls(0).cation = _
StaffArray(0, intX)
me("chkStaff" & intX).tag = StaffArray(1, intx)
If intX = MaxNumberOfCheckBoxes Then
Exit For
End If
Next intX
The above code loads current staff names into the captions and saves the staff keyid in the control tag for later processing.
If UBound(StaffArray, 2) < MaxNumberOfCheckBoxes Then
For intX = UBound(StaffArray, 2) + 1 To MaxNumberOf etc
me("chkStaff" & intX).Visible = false
me("chkStaff" & intX).Left = 0
me("chkStaff" & intX).Top = 0
Next intX
End If
The above code hides any unused checkboxes and moves them to the upper left hand corner of the form so they are out of the way in case you wish to resize the form.
Now that the form is set up, you create new ClientContact records by filling in the dates and other misc information about the contact and checking the staff who made them. In the form AfterUpdate code you spin through the controls and insert a tblContact record for each staff checked something like the following:
For Each ctl In Me.Controls
If Left$(ctl.Name, 8) = "chkStaff" Then
If ctl.Value Then
Call InsertContactRecord(ctl.tag)
End If
End If
Next ctl
Make sure you verify checkboxes with .value if you have Access97. Some versions have a bug that doesn't allow Access to close cleanly if you reference an object directly. If you want to allow edits you would need to have logic to determine if it changed so that you could delete the tblContact record if it was unchecked or do nothing if it was still checked.
As an aside, you can save yourself a little work on the front end by creating one checkbox and then copying it on your form as many times as you need it and then using a utility function to do some of the dirty work for you.
When I set mine up I did something like the following after I did massive copies. Open the form in design mode and then run something like this:
On Error Resume Next
For Each ctl In Forms("YourFormName"

.Controls
If ctl.ContrlType = acCheckBox then
ctl.Name = "chkStaff" & intX
ctl.Controls(0).Caption = ctl.Name
ctl.TabIndex = intTabIndex + 1
intX = intX + 1
End If
intTabIndex = ctl.TabIndex
If Err.Number > 0 Then
Err.Clear 'In case control can't receive focus
End If
Next ctl
Sorry this is so long. It makes for a pretty slick User Interface once you get it up and running.
Good Luck and Happy New Year!