I used the following VBA Code in The Form (General)
Public Function GetUserName() As String
GetUserName = CreateObject("WScript.Network").UserName
End Function
The Control source = User_Name
Default Value = GetUserName()
The Problem -
The username is correctly Pulled in the form, however it is not being saved in the Control Source i.e in the Table. Even after I save and close the form.
I need the form to capture and save the Username every time someone makes changes to a record.
Please Help I am new to MS Access
It looks like you are assigning the user name to the control source. Access does not work like this. The control source is supposed to contain a column name.
Create a table having columns you can use to store things. Then set the form's Record Source property to this table name at design time in the properties window. Then set the Control Source of a text box to the column name where you want to store data or add objects to the form using the fields list.
Iin the form load event you can assign a user name to this textbox with
me!theTextBoxName = GetUserName()
You can also do this with an unbound textbox, but this name will not be stored when you close the form.
But as #June7 points out, you have probably done this already. In this case you should open the form with
DoCmd.OpenForm "theFormName", DataMode:=acFormAdd
... to create a new record.
Related
I am completely new to VBA. I have been told to add records to a table by using a form and a Save button and given some very basic instructions. While I have achieved this with inline query, I have been told to follow some strict methods like usage of QueryDef/QueryDefs and .Parameters.
So far I am trying a very basic project, just to grasp the concepts, but I am unable to add any record to an empty table. In case the table is not empty(I manually enter a record), whenever I click the Save button for saving newer records, the number of records added are somehow doubling with each instance. For example, when I Save for the 1st time, 1 record is added, 2nd time 2 records of the same type is added, 3rd time 4 are added and so on.
The table(tbl_test) has 2 fields --> ID(primary key), Source(Long Text) and Reg No (Number).
The query(qry_test) is made with the Append feature and I have been told to add expressions which makes the code like this -
INSERT INTO tbl_test ( Source, [Reg No] )
SELECT [strSource] AS Expr1, [lngRegNo] AS Expr2
FROM tbl_test;
The form has 2 fields for Source(txt_Source) and Reg No(txt_RegNo) which have blank Record Sources (Unbound). The Save button has the following Event Procedure -
Private Sub btn_save_Click()
Dim qdf As QueryDef
Set qdf = CurrentDb.QueryDefs("qry_test")
qdf.Parameters("strSource") = Me.txt_Source
qdf.Parameters("lngRegNo") = Me.txt_RegNo
qdf.Execute
End Sub
I have zero knowledge about VBA and would gladly accept ANY help. It would be great if I get any sort of source code that will explain to all the details about saving records from forms and editing them using these querydef, parameter and recordset stuff.
Welcome to StackOverflow!
If you are using a form to collect data for records that are stored in a table, running a saved append query by QueryDefs to do this is, in my opinion, not the best method.
Whilst an append query does add new records to an existing table, I would tend to use an append query where I've got multiple established records that I want to add to an existing table.
If I'm setting up a data entry form that is designed to collect new data for new records 1-at-a-time, an append query doesn't really suit this purpose.
Instead, there are a number of features built in to the design of MS-Access forms to help collect data and save it to a table. This is because forms are very much intended to be set up so that users can interact with records from a table in a controlled, user-friendly way rather than interact directly with the table object itself.
The first and most important feature of a form in this context is probably the form's record source property. When you create a new form, go in to design view for the form and open the form's property sheet (F4 key). In the "Data" tab of the form's property sheet you'll find the record source property:
The record source essentially connects your form with a set of records, whether those be records in a table object, a query object or an sql query string.
In your case it would be better, in my opinion, to bind your tbl_Test table to your form by referring to it in your form's record source:
It will seem like nothing has happened to your form, but if you now open the "Add Existing Fields" panel (alt + F8), you'll notice that the fields associated with your tbl_Test table are available to you:
Drag them to the detail section of your form...
Then put your form in to Form View:
Essentially what you and your users are seeing is the first blank record in your tbl_Test, but displayed on a form instead.
Entering data in these fields on the form...
...will put that data in to the table we specified in the form's record source...
So hopefully you can see that setting the form's record source property to that of your table, is much cleaner than trying to get an append query to collect data from your form and deliver it your table.
At this point you're probably asking a few questions:
When I have filled in the fields for a record on my form, how do I save that record?
More can be said about this, but for brevity, I'd recommend using a command button for running some vba to save the record; similar to what you've done, but utilising the form's Dirty property instead using an append query:
Here's the click event VBA for my save button example:
Private Sub cmdSave_Click()
If Me.Dirty Then
Me.Dirty = False
End If
End Sub
Me.Dirty is a Boolean (True or False) setting for the form; essentially it is automatically set to True when a user changes something on the form. To save those changes, the Me.Dirty setting will have to be set to False.
Me.Dirty is a bit like the swing gate on a sheep pen. When a shepherd puts a sheep (data) in the pen (form) they will open the gate to the pen. The open gate is like the form's Me.Dirty being set to True. To lock the sheep (data) in, the gate needs to be closed, or in the case of forms, the Me.Dirty property needs to be set to False. The VBA above essentially checks to see if the gate was opened and if it was to close it.
How do I move to a new record in the form once I have saved the current one?
Again, I'd give the user a command button to do this and run some VBA on its click event:
Here's the VBA for moving to a new record:
Private Sub cmdNew_Click()
DoCmd.GoToRecord , , acNewRec
End Sub
Summary
There is a lot more to consider than what I've outlined here, such as:
validating data before it is saved
checking other form events (such as close) to ensure data entry is not lost
navigating to an existing record
But hopefully what I've given you here is at least pointing you in a better direction. Best of luck!
Access is optimized for bound forms. Unbound forms are for special cases only.
Should you prefer unbound forms (could be for many reasons), Access isn't worth the trouble, and you should turn to Visual Studio and WinForms.
In either case, browse for a beginner's tutorial.
If you want to use an unbound for or unbound controls you can create the SQL string in the procedure:
Dim mysql as String
mysql = "INSERT INTO tbl_test ( [source], [reg_No]) VALUES (Me.txt_Source, Me.txt_RegNo)
DoCmd.RunSQL mysql
I'm trying to set up a simple form in MS access to add a new record to a table full of contact information. Each time I add a new record using the form, I want an ID number field to increment by one against whatever the highest value in the ID field is. The code I have right now seems to be working:
Private Sub Contact_ID_Click()
Dim newContactID As Double
newContactID = DMax("[Contact_ID]", "Contacts") + 1
Contact_ID = newContactID
End Sub
The problem is that every time I start the database, open up the form in form view and click on the Contact_ID field to increment it, I get the following error message:
"The expression On Click you entered as the event property setting produced the following error: Object or class does not support the set of events."
I go to design view, open up the code, and then as soon as I switch back to Form view it's working again. I'd like it to work when the form is opened from scratch as others might be using this form and wouldn't know what to do. Any idea what's causing this?
So I have this Access 2010 database into which users must login. The username they use is saved as a global variable. I then have a form which updates a table when they enter data and click a "save" button. I am trying to set one of the comboboxes (user) that is currently linked to a column in the table to be filtered on the global variable so that each person can only enter data under their own username. Is this possible? Does anyody know how to code this? I'm a complete newbie to Access and VBA and would appreciate any help
Greets
Me
In the form_load() function of that form you should fill the combobox with the global variable. To be sure they can't edit you should disable the combobox as well.
Private Sub Form_Load()
Me.myComboBoxName = gMyGlobalVariableName
Me.myComboBoxName.enabled = false
End Sub
However I'm assuming that the combobox has two columns (id and username) of which the first one is hidden and the primary key of some table where you store all the usernames. The gMyGlobalVariableName should have stored the id, not the username itself.
You can set the row source of the combo in the load event of the form to include only the relevant rows.
Me.TheCombo.RowSource = _
"SELECT UserColumn, Etc FROM TheTable WHERE UserColumn ='" _
& TheVariable & "'"
You may also wish to ensure that the form only contains the relevant records, however, the fact that you have a save button, suggests an unbound form. In Access, save buttons are largely redundant because the default is to save a record and stopping saves is the difficult bit.
I wonder why you do not use their windows log-in user name?
I have a database with information about visitors to our department. Here is my setup: A user selects a visitor name from a listbox. Access assigns the values from that visitor's record to temporary variables and opens an unbound form where those variables are the default values in the text field. When a user changes a value in a textbox, an After_Update event uses SQL to update the corresponding field in that visitor's record and assigns the new value to the temporary variable.
After_Update example:
Dim strRUN As String
strRUN = updateVisitorOnDirty(Me.txtVisitorTravelMethod, "VisitorTravelMethod", 1)
HideWarnings (strRUN)
TempVars!strVisitorTravelMethod = Nz(Me.txtVisitorTravelMethod.Value, "")
"updateVisitorOnDirty" is a function that returns SQL to update a field (specified in second argument) in the table with visitor information with the first argument. (The number at the end is says it's a string.) "HideWarnings" turns warnings off, executes the SQL, and then turns warnings back on.
My problem:
When a user clears a textbox, the After_Update event makes the textbox revert to it's previous value.
I thought at first that maybe the unbound textbox was reverting to its default value when it was cleared, but I put a breakpoint in the sub that fires during After_Update:
If I change a value in mytextbox from a to b, debug.print shows the value of mytextbox as b. If I change a value in mytextbox from a to (blank, or empty string), debug.print shows the value of mytextbox to still equal a.
My workaround has been to include a little "x" near the textbox that the user can click to 1)clear the textbox, 2)update the temporary variable, and 3)update the table. It works fine, but it seems like there should be a better way. Help?
Please let me know if you need any other information or if I should otherwise re-word this. I come here all the time for answers, but this is the first time I've actually submitted my own question. Thank you!
(I edited this to make the code show up correctly...didn't leave a line before.)
I figured out that the unbound textboxes were reverting to their default value when a user tried to make them blank. To stop them from doing this, I put this in the AfterUpdate of the textboxes:
Call ResetDefault(Me.textbox1.Text, Me.textbox1)
And defined the function:
Public Sub ResetDefault(ByVal strChange As String, ByRef txtCurrent As TextBox)
If Nz(strChange, "") = "" Then txtCurrent.DefaultValue = ""
End Sub
That is, if a user cleared a textbox, the default value of that textbox was set to "", allowing the textbox to actually go blank.
I think the best approach is to scrap the after_update event on your text boxes and instead either put a save button on your unbound form so that all updates are written in one pass, or capture the forms closing event and update your table then.
This is the advantage of using unbound forms, you do not have to comit data until you are absolutely ready to, but with using an after_update event you are almost mimic-ing the behaviour of a bound form.
I have made an Access 2007 db. I will be writing some basic vba for the appropriate event of a form so that a modal form is displayed when the original form is opened. This isn't difficult, but that form will have a drop down box of IDs from a particular table. The user will select an ID, but I want the selected ID from this form to go back to the parent form. E.g.:
Car form opened
Event is fired to open a modal form
IDs for a FK to cars has to be selected from a combobox (eg ID of driver - for simplicity, lets assume one car can have many drivers but not vice versa so 1:n only)
There is a button to confirm the selection. On clicking this button, the form closes, and the selected Driver ID is automatically inserted into a DriverID textbox on the car form (probably will be read only).
The last step I am not sure about. How can that be done in VBA?
This is one of the worst Access threads I've ever seen on StackOverflow.com, because every answer is wrong in at least some crucial aspect -- not a single one of them would actually run if you pasted them into VBA in an Access database.
The key principles here:
Open the dialog form modally (with the acDialog arguments)
Don't close it when the value has been confirmed, but instead set it's .Visible property to False.
Then in the calling form, read the value out of the hidden form, and then close it.
Something like this:
DoCmd.OpenForm "dlgPickDriver", , , , , acDialog
If IsLoaded("dlgPickDriver") Then
Me!DriverID = Forms!dlgPickDriver!cmbDriver
DoCmd.Close acForm, "dlgPickDriver"
End If
[IsLoaded is a Microsoft-provided function; I posted it here on StackOverflow recently, but would assume that the vast majority of Access developers writing VBA would have been using it forever]
I would recommend against having code that runs in the dialog form poke the data into the parent form because it's then impossible to use the dialog form in multiple locations. Having the dialog form know as little as possible about the context in which it's called is good programming practice. On the other hand, it's true the calling form needs to know the control name it's getting the value from, but that's a more sensible context than the other way around, in my opinion.
To gain 'access' (get it?!) to controls on separate running forms you can use the following:
Forms("AnOpenFormName").Controls("ControlName") = value
Edit: I used the wrong brackets AMG!
You could write a function that will display the form modally and then return the user selected value as a return value of it (similar to msgbox/inputbox).
EDIT: You could write a function such as following.
Function GetUserSelectedCarID() as string
dim myPopupForm as Form
set myPopupForm = new Form
myPopupForm.Show vbModal
GetUserSelectedCarID = myPopupForm.UserSelectedCar
End Function
UserSelectedCar is a property that stored the user selection on the popup form.
EDIT2: You could also add a property on popup form to see if the user clicked OK or Cancel.
It will return blank from the above function, if user clicked Cancel.
All of the above answers are good. I especially like the third way of wrapping this kind of functionlity into reusable function calls. The only thing I would add is do not CLOSE the modal form...otherwise you cannot get the selected value. Instead do me.visible=false.
So you do somethiing like this.
Public Function GetCArKey as Integer
dim intReturn as integer
docmd.openform "MyModalForm",,,,,,acdialog
'(the click event of the okay button of this form does me.visible=false...clicking Cancel will close the form.)
if isloaded("MyModalForm") then
intReturn=Forms("MyModalForm").Controls("ControlName").Value
end if
GetCarKey=intReturn
End Function
It would seem much easier to me to create a global variable in a module (eg Public gi_Value as Integer) and then set this in the child form. The value can then be read anywhere.