MS Access - Disable Update on a Certain Field or Column - vba

How do we disable update or edit on a certain column for a record. For example I have Product table with fields of ID, Description, Count. I want to disable the changes on Description only. I know how to do this in sql, but how about in a program for Access or VBA code?

If you're using a form to present the data using a text box control bound to the field, you can lock the field for edits in the field properties. The property is called "locked".
You can also use vba code to lock and unlock the field under certain conditions.
Sub form_current ()
If x = "superuser" then
Me!SalaryField.enabled=true
Me!SalaryField.locked=false
Else
Me!Salaryfield.enabled=false
Me!Salaryfield.locked=true
End if
End Sub

Related

Microsoft Access VBA - Locking a field when value in the field is not null

I have fallen into a rut building a quote creation tool. I have a combo box that selects an item for the quote and will populate all of the fields for that line. In this case, I want the [Cost] field to be locked, preventing any changes. However, there are times when a user must type an item for the quote that is not in the combo box; therefore, all of the fields on that line will be null and must be typed manually.
I am trying to write a VBA event where [Cost] is locked when [Cost] is not null, preventing any change; and where [Cost] is not locked when [Cost] is Null, allowing editing.
Private Sub Form_Current()
If IsNull(Me.Cost) = True Then
Me.Cost.Locked = False
Else
Me.Cost.Locked = True
End If
End Sub
The top line is in the combo box and the entire line is populated; Here I want cost to be locked
The second line is not in the combo and the line must be manually entered; Here I want lock to be disabled
Sometimes code must be in multiple events to achieve desired result. Since you will programmatically populate Cost if an item is selected from combobox list, put code in form Current event and combobox AfterUpdate event. Could have a Sub behind form that can be called by both events.
Programmatically setting control's properties will affect ALL instances of control. An alternative is to use Conditional Formatting to dynamically enable/disable a textbox or combobox.
To allow user option to edit manually entered Cost value for a new record adds complication. VBA or Conditional Formatting rule could be conditional - don't disable if focus is on a new record and service item is not in lookup table.

Access allow addings but no edits in certain columns in a subform

I got question if it is possible to allow addings but no edits in certain columns in a subform? I can do this for the whole form, but i can't do this for single columns.
For example:
I want to be able to allow edits in [Type], and in [Omschrijving] I only want to allow adds and no edits.
I can lock certain columns. For example:
Private Sub Form_Load()
Me.Omschrijving.Locked = True
End Sub
But then I'm not able to make any adds. Is there another way to make this possible?
Only lock if not a new record. Use form Current event instead of Load.
If Not Me.NewRecord Then
Me.Omschrijving.Locked = True
End If
Might use Enabled property instead so control shows as unavailable for edit, in which case could use Conditional Formatting for textboxes and comboboxes instead of VBA. Rule something like:
Expression is: Not Forms!formname.NewRecord
Then click the Enable/Disable button so if this condition is met, control is disabled.

Microsoft Access VBA If statement

I have a dropdown menu that has three options "Open, Assigned, Closed" I have three rows in a table in my database, one for openTime, assignedTime, and closedTime.
My dropdown menu is connected to a row in my table called Status which is swapped between the three options "Open, Assigned, Closed". When the ticket is created in my website, it creates an open time so I don't have to worry about that, but when the user selects assigned and closed I would like it to on change send data to the correct cell.
So if the drop down is swapped from open to assigned it already changes the status cell to "Assigned" in my database but I would also like it to change the assignedTime cell's data to the exact time and date. Same for closed.
I think this is simple I'm just a bit confused on the process. Im using this site for info on IF statements
I have my code that creates and adds my date
me.MyDateTimeColumn = now()
I have a few questions
1) In my IF statement how do I say the value of the selection for example if the user selects "Assigned' in the drop down menu how do I say thats the info I want my IF statement looking at?
On the site linked above this is there example for an if statement:
Sub AlertUser(value as Long)
If value = 0 Then
AlertLabel.ForeColor = "Red"
AlertLabel.Font.Bold = True
AlertLabel.Font.Italic = True
End If
End Sub
On this do I need to include the Sub AlertUser(value as Long)(using my own variables) If so what would my sub be?
and does the If value = 0 Then refer to the value of the selected comboBox?
2) Can I insert an else if as I would in other languages, do I need an end else if?
I am using a microsoft access form, and using the VBA code section for this. MY database is in a sql server connected to the form.

MS Access Can't go to specified record because of another control's VB where clause

I have a lookup listbox which is programmed to allow the user to find a specific record/help topic from the list and view it. Now when the list box is used the where clause locks in the record and the first, previous, next, last buttons freeze up and you cannot use them to go to a record. Is there a way to free up the functionality of the buttons to navigate through the records along with the where clause to select.
Here is the code that operates the listbox selections:
Private Sub List35_AfterUpdate()
Dim myTopic As String
myTopic = "Select * from FormsHelpTable where ([ID] = " & Me.List35 & ")"
Me.Form.RecordSource = myTopic
Me.Comment.Requery
End Sub
I believe since the where clause locks in the selection in the box it does not allow navigation from other controls to interfere. What might be a way around this?
You get the runtime error:
You can't go to specified record.
It appears not to be reading the other record in the source table named Help once it updates using the listbox.
Instead of changing the recordset (this is the 'pool' of records which the form could display), you just need to go to the record the user selects from the listbox.
Method 1 (probably the easiest way if your listbox is in the same order as the records of your form)
Use this code:
Private Sub lstSelect_AfterUpdate()
DoCmd.GoToRecord acDataForm, "HelpForm", acGoTo, Me.lstSelect.ListIndex + 1
End Sub
You need to ensure that:
The recordset of the form is ordered the same as the listbox. So, for example, you could order both by ID, or by Title.
Note that the +1 comes from the fact that the ListIndex starts at 0, whereas the record indexes start at 1.
Method 2
Ensure each record's Title is unique (set No Duplicates on this field).
Change your listbox to return the Title of the record, rather than it's ID.
Then use this:
Private Sub lstSelect_AfterUpdate()
Me.Title.SetFocus
DoCmd.FindRecord Me.lstSelect
Me.lstSelect.SetFocus
End Sub
Things to note:
It works by searching the field with focus for the string specified. That's why we have to SetFocus on the Title textbox on our form.
We could use ID instead, (which would mean we could have duplicate titles if we wanted), but then we would have to have an ID control on the form to SetFocus to. You can't hide this control either, because it needs to have focus whilst using FindRecord.
Update: Method 1 with reverse-selection
Add an Event Procedure in the Form_Current event, with this code. Then update the code in the lstSelect_AfterUpdate procedure as shown after.
Private Sub Form_Current()
Me.lstSelect = Me.lstSelect.Column(0, Form.CurrentRecord - 1)
End Sub
Note that, depending on how your lstSelect is set up, it may be Column(1, Form.CurrentRecord - 1) instead. Read on for details!
Private Sub lstSelect_AfterUpdate()
DoCmd.GoToRecord acDataForm, "HelpForm", acGoTo, Me.lstSelect.ListIndex + 1
Me.lstSelect = Me.lstSelect.Column(0, Form.CurrentRecord - 1)
End Sub
Explanation of new lines:
The Form_Current event fires every time we go to a new record. We need to look at the index of the record (ie. the position of it in the recordset), which we get by using Form.CurrentRecord. We then want to make the listbox select that record. However, we can't use me.lstSelect.ListIndex as before, because that is a read-only property (we can access it to read it, but we can't set it).
Therefore, we use me.lstSelect.Column(colNum,rowNum) instead, where we specify a column number and a row number. If your listbox has two columns (eg. ID and Title), we want to choose the second column. The index starts at 0, so we would use a value of 1. If, like my lstSelect, you only have one column (Title) then we use 0. Note: it doesn't matter if a column is hidden (ie. has width 0). It still 'counts'.
The row number is Form.CurrentRecord - 1. Remember that the forms recordset index starts at 1, but the index of our listbox starts at 0; hence the - 1.
So why do we need a duplicate of this new row in the AfterUpdate event? Try and comment it out to see what happens if we don't put it in. It's has to do with the Form_Current event firing after we use the listbox.
I fixed this issue with a union clause in the SQL lookup code. The UNION ALL clause and the following union on the table used in the other part had allowed all the records to be used.

Microsoft Access, auto generate columns in DataSheet subform

I want to create a form in MS Access 2003 that lets the user pick from any existing query, and then have it display the results inside the form (as a sub-form in DataSheet view). The user will then be able to select one or more records and click a button on the parent form to do certain actions based on the selection. I want it to be able to work with any query, with very few limits, and display the full results of the query (all columns). The only requirement I might have is that it include certain fields for certain actions. For example, if I have a "send email" action, the query will require a field named "email", or maybe "to" and "subject".
Changing the DataSource of the DataSheet sub-form at run-time isn't a problem, I've done that before using VBA. Getting the columns displayed to change is the problem.
In a .NET WinForms app this could be done with the "auto generate columns" on a GridView control, or using the GridView.Columns collection directly in code. In VBA I don't see a way to add/remove columns from a DataSheet view. I also don't see a way to auto generate them based on the query. It appears the columns are controlled by the controls placed on the form (in form view), and while it is possible to add/remove controls using VBA, the form would have to be placed in Design View and require exclusive access to the database -- sounds very messy and I would like to avoid the exclusive access part.
Am I missing something? Is there an easy way to do this?
Here's how I would go about it. Create a blank subForm control on your main form. To change the source and the columns just leave the source object blank, then when you set it with code, the columns will reset to whatever source you use. So set it like so:
Private Sub setSource()
Me.subForm.SourceObject = "Query.myQuery"
End Sub
Then to get the selected items, assuming you know what column you want, you would do something like this:
Private Sub getSelected()
Dim rs As Recordset
Dim f As Form
Set f = Me.subForm.Form
Set rs = f.RecordsetClone
Debug.Print f.SelTop
rs.MoveLast
rs.MoveFirst
rs.Move f.SelTop - 1
Debug.Print rs!ID
End Sub
If you don't know the column explicitly you can use this to loop through the columns of the selected item and run some analysis on each name until you determine it's the column you want.
Dim i as Integer
For i = 0 To rs.Fields.Count - 1
Debug.Print rs.Fields(i).Name
Next