How to populate an append only long text data type field - ms-access

I use a form to update/insert a database in Access 2016.
I found Access has an option to record version of a field value change if data type of this field is long text and append only property is set to yes. I decided to concat all the values of a single record and save to this long text (history) field.
Now I have added an invisible textbox control to that form. The value of this field i.e. "history" will be populated when an event occurs (on unload from form current record) and that invisible textbox control value is set running a function.
So now I need to know which event should I address to populate history field?
I tried several events but all say conflict!

This seems like a last changed date kind of problem. I have has success with using the form's before update event for this. E.g.:
Private Sub Form_BeforeUpdate(Cancel As Integer)
With Me
.LastChangedDate = Now()
End With
End Sub
If you are having trouble accessing the history from the control you could set a vba variable to it using the Current event of the form. Be careful, the Current Event fires for many reasons and the code has to defend itself from running except when you want.
I frequently test many conditions and switch settings so the Current event does not crash or worse. Trial and error needed.
For example, you could record the key of the record whose history you have saved for later and test to see if it has changed before saving it again. Also, I make sure that initialization of the OPEN and LOAD events are complete along with any other initialization necessary before I allow the Current event to do anything significant.
Good luck.

Related

MSACCESS, how to edit a record after insert using the "after insert" trigger

MS Office 365 ProPlus, Access 2007 - 2016
I'm trying/failing to change the value of a field in a table after it is inserted using the "after insert" trigger. Something like this...
EditRecord
SetField
Name orig_id
Value = [mytable].[id]
End EditRecord
This doesn't seem to work.
USysApplicationLog gives...
SourceObject = mytable.AfterInsert
DataMacro InstanceID = {489D5697-5247-44A8-AE3C-3773A25F72E5}
Error Number = -20335
Category = Execution
Object Type = Macro
Description = EditRecord failed because the default alias represents a record which is read only.
The field is not read only. After the fact I can edit it just fine. I don't know what the "default alias" is nor what that even means.
If the trigger can't do this, can you think of another way to accomplish the same thing ?
You don't want to use the AfterInsert, since then the record is already saved, and tucked away nicely, and everything you need to change in that record is assumed to have been done. In fact, the default context will cause the record in question to be read only. You CAN get around this by pulling the record again, (looking up a record), but if you modify it again then all of the triggers for that record will fire again.
So I ONLY suggest you use this event to sum() or add/edit OTHER tables, but not the record that was just edited and saved.
If you need/want to update this current record, then move your "edit" or "modify" code to the "BeforeChange". This event not only lets you edit/modify right before the save (and thus preventing endless loops in which the update triggers fire again and again), but the CURRENT record is in full context, and you don't even need any "edit record" command, since you have the fresh un-saved record right in context. You thus can use SetField without the need for EditRecord.
So, the AfterInsert is really too late here, and if you could modify the record in that event, you will cause the AfteUpdate event to fire again if you do use a workaround.
Now, if you use BeforeChange, it will fire for both insert and edits (change). So, if your code really only needs to run when inserting, you can check this status by using
If [isinsert] = True then
Edit
Also, it looks like your code is attempting to save (capture) the previous value, and if it is, then you can use:
[old].[id]
Of course this does not make too much sense for "id", since that is usually an autonumber PK column, but for grabbing other values during an update in the BeforeChange event, you can certainly test + inspect the previous (old) values.

MS Access 2007 - controlling UI behaviour after attempt to insert duplicate record

Creating a simple UI using MS Access, hoping to do minimal actual coding (actually helping a friend who is not a coder).
Simplified requirement: Single table, primary key is phone number, lots of other non-mandatory fields. Display a form allowing just the phone number to be entered, if a record with that key exists display the full record, if a record with that key does not exist bring up an form allowing the other fields to be entered for this phone number and hence create a new record.
Q1: Any simple way to achieve this kind of function? Example?
We've got some of this going with a standard form, can execute code if insertion fails, but a standard dialogue box is displayed warning about the duplciate key violation.
Q2: How can we trap that attempted insertion, avoid having the dialogue come up?
You will have to get your hands dirty and write some code to get this outcome. A starting point would be something like this presto code. Post back if you get stuck on any of the parts.
If fCheckIfRecordExists(lYourKey)=True then
Docmd.OpenForm “frmEditExistingRecord”
Else
Docmd.OpenForm “frmEnterNewRecord”
End if
Public function fCheckIfRecordExists (lYourKey as Long) as Boolean
‘Code to check if a record exists, simple method is to use dLookup or a count SQL statement with the criteria as the key you are trying to find
End function
EDIT:
First things first make a form with 1 text box called txtPhone_number and a command button called cmdSearch.
Next put this bit of code in the module behind the form
Public Function fDoes_record_exist(strPhone_number As String) As Boolean
If DCount("Phone_number", "tblYour_table", "Phone_number=" & strPhone_number) > 0 Then
fDoes_record_exist = True
Else
fDoes_record_exist = False
End If
End Function
Next you need to put some code behind the click event of the command button. This code can be expanded on to check for a valid phone number later if you want
If fDoes_record_exist(Me.txtPhone_number) = True Then
DoCmd.OpenForm "frmShow_existing_record"
Else
DoCmd.OpenForm "frmEnter_new_record"
End If
That should set you on your way nicely but post back if you run into problems
Here is an overview of the process with Access logic:
You need an unboud control labelled Phone in the form header, where user will be able to enter the phone number to search. You need to use the After_Update event of that control to trigger your search. There will be a second Phone control, bound this time, in the Detail section of the form for effective data entry/update.
Use the Form_Error event to intercept the error message when user tries to save a duplicate key, in order to display a nice message, and eventually Cancel his changes.
The advice from Kevin Ross to use VB Code is clearly one approach, and I think is appropropriate if we anticipate less trivial requirements in future. However I'm in a situation where I'm helping someone with zero coding background and hence if possible I'd prefer to let them use simple Macros rather than full-scale VB.
As it happens the functionality I require can be implemented with just Macros, and it depends on the suggestion from iDevelop.
The outline of the solution I used:
Create an InitialEntry form with no association to any particular table, it has:
a data entry field for the telephone number
a read-only text box where I can display a message
a button labelled Add
a button labelled Show
I write three macros:
A macro AlreadyExists that displays a message saying "We already that one"
A macro NewEntry that opens a data entry form for my table, in Add mode, and which copies the phone number from InitialEntry!TelephoneNumber
A macro TestForExisting this uses a condition
DCount("*","MyTable","[PhoneNumber] = [FormPhoneNumber] " ) > 0
to control whether to execute AlreadyExists, and a similar test to control whether to call NewEntry.
While this is not as efficient as VB, it does seem to be understandable by a non-coder, so at least we can implement our application.

MS Access 2003/2007 - Passing data through a variable on unbound forms vs. a hidden text box

Ok so I hope the title of the question matches what I about to ask, but here is what I am trying to get at:
So I have an access database that uses a number of unbound forms, and the purpose of the forms are to collect data and save to various tables with VBA click events using SQL statements (INSERT or UPDATE based on whether the ID of the record is present on the form in a hidden text box). When entering a new record (via INSERT), I get the row number with
MyRow = db.openrecordset("SELECT ##Identity")(0) 'thanks David
So you maybe getting the picture. If I have another form that relates to the first form in terms of the record, I just open a recordset and pass that value to another hidden text box.
So my question is, is there a better way to do this regarding passing that value (or just using that value) using a variable instead of this awkward method. So I realize a lot of folks are going to go with the obvious answer of, "Why not just make your forms bound instead of all this code"...and I am sure that is a valid answer, however I inherited this database which was already put together like this, and re-structuring it would be a daunting task.
Any and all advice, or learning resources are greatly appreciated, as they always are!
I use unbound controls on forms for all these kinds of values. The current solution of using an unbound form is sounder than using global or form level variables. If I recall the details correctly while debugging code and you hit the stop button you lose all global or form level variables. Or if the user hits an unhandled error.
Have you looked at OpenArgs?
DoCmd.OpenForm "Form1", , , , , , "Hello"

MSAccess 2003 - VBA for passing a value from one form to another

So how can I pass a value from one form to another? For example: The user select's an organization from a list and this opens up a trip form that allows a user to enter various information regarding the trip. At one place I would like to add another little pop up form where they can enter contact information (just a name and phone for POC) of the organization they are visiting.
So when that initial form opened from the selection screen it has two IDs that are simply hidden in text boxes (one being the tripID, and the other being the OrgID), so how do I pass these to the second little pop up form so that the contact information has the relative IDs with it.
Thanks.
The best approach in these cases is not to attempted to pass a bunch of variables. It is too much code, and is inflexible. For example, if you need to pass two values, what happens over the years when that requirement grows to 5 values? Trying to maintain and pass a whole whack of values is too much coding work.
Keep in mind that each form in ms-access is really a class object that you can manipulate in code. So, use a object approach here and you find you not only write less code, but your code will be more clean, more modular, no need for global vars, and code you write can often be re-used between different forms.
Here is how:
In general when one form launches another form in the 2nd form in the forms on-open event (in fact, you can even use as late as the on-load event) you can pick up a reference to the PREVIOUS form object. In other words, you can use a object approach here.
At the forms module level, for form I declare a form object as:
Option Compare Database
Option Explicit
dim frmPrevious as form
Then, in the forms on-load event, we go:
Set frmPrevious = Screen.ActiveForm
Now, any code in our form can FREELY use code, events, even varibles declared as public from that previous form in code.
So, if you want to force a disk write of the previous form, and re-load of data.
frmPrevious.Refresh
If you want to set the ID value, then go:
frmPrevious!ID = some value
And, note that you can even declare form previous as a PUBLIC variable for that form, and thus if you two forms deep, you could go:
frmPrevious.frmPrevious!ID = some value
So, simply declare a forms object in EACH forms code module (or at lest the ones where you need to use values in code). The above means any code has a ready made reference to the previous form object. Functions declared as public in a form will become a METHOD of the form, and can be run like:
frmPrevious.MyCustomRefresh
or even things like some option to force the previous form to generate and setup a invoice number:
frmPrevous.SetInvoice
or
frmPrevious.SetProjectStatusOn
So not only can you shuffle values and data back and forth, but you can easily execute features and functions that you build in code for the prevous form.
In fact as a coding standard, MOST of my forms have a public function called MyRefresh.
Note that the beauty of this approach is that you can thus read + use + set values from that previous form. This allows your code to not only receive values, but also set values in that previous form. So this approach is bi-directional. You can shuffle data and values back and forth between the forms. The other advantage here is you NOT restricted to just variables, but can use fields, control values (events, properties) etc.
This approach means that much of the previous form is now at your fingertips.
So don’t try to pass a whole whack of variables. Pass a reference to the form and you have a nice ready made object at your fingertips and it makes this type of coding problem a breeze.
The usual way would be to reference the textboxes in the initial form from the popup form, like this:
Forms!frmInitialForm!tripID
Forms!frmInitialForm!OrgID
However, this tightly binds the popup form to the initial form, so that it cannot be used anywhere else in the application.
A better approach is to use OpenArgs:
DoCmd.OpenForm "frmPopup", OpenArgs:=Me.tripID & ", " & me.OrgID
This places your two values into a string, which is passed to the popup form. You can then parse the two values out of the OpenArgs using the Split function.
For more info about passing parameters using OpenArgs, see:
http://www.fmsinc.com/free/NewTips/Access/accesstip13.asp
This one could help
MS Access: passing parameters from one access form to another

How to print dynamic forms in Microsoft Access?

I have an Access form where each record has some info that is computed on the fly. I'm using the Form_Current() event; each time a record is selected, I compute some information and change some form controls to reflect it, based on the record's ID.
I want to print a bunch of these records. However, in this situation the Form_Current() event isn't being triggered and the printed records lack that dynamic information.
Any ideas?
Make a query that computes the information you need as the source of your report. You can use vba functions if needed for complex calculations.
In a comment, Luis Oliveira asked:
My function was in the Form itself,
which is why I couldn't call it from
the SQL query, I suppose?
By default, functions in a form are private. If made public they can only be called when the form is open, as in Forms!MyForm.PublicFunction(). I would advise against that. Instead, move the function to a public module (which may require revisions to remove references to form controls/fields).