TempVars; Why and What? (1 Viewer)

zeroaccess

Active member
Local time
Today, 01:18
Joined
Jan 30, 2020
Messages
671
Hi. This looks like, without testing it, a circular reference.
Code:
CurrentUserID = TempVars(CurrentUserID).Value
To your issue though, are you saying you can't do this?
Code:
Me.txtComment.Locked = TempVars("TempVarName") <> Forms!frmInspection.txtUserID
If not, what error message do you get?
It just doesn't work like a normal variable, unless I'm doing something wrong.

TempVars(CurrentUserID) is the name of a specific TempVar so not a circular reference. I'm setting a new variable and telling it what the value is, basically, so that I can use it in this procedure.

If you try:

NGINX:
    Me.txtComment.Locked = (TempVars(CurrentUserID).Value <> Forms!frmInspection.txtUserID)

You get "variable not defined"
 

theDBguy

I’m here to help
Staff member
Local time
Yesterday, 23:18
Joined
Oct 29, 2018
Messages
21,358
Hi. Sorry, if I'm a little confused. Re: "circular reference," your code above declares the same variable name as the name of a TempVar? Besides, the syntax for reading a TempVar is by delimiting the name with double quotes, like I showed you above. To clarify your situation, what is the value in CurrentUserID at the time you execute this? TempVars(CurrentUserID).Value
 

zeroaccess

Active member
Local time
Today, 01:18
Joined
Jan 30, 2020
Messages
671
Hi. Sorry, if I'm a little confused. Re: "circular reference," your code above declares the same variable name as the name of a TempVar? Besides, the syntax for reading a TempVar is by delimiting the name with double quotes, like I showed you above. To clarify your situation, what is the value in CurrentUserID at the time you execute this? TempVars(CurrentUserID).Value
Sorry - I missed your code.

I tried your syntax and it does indeed work. I knew I had to be doing something wrong. Thanks!

CurrentUserID is going to be a number like 1, 5, 10, which is the PK of the user. It is the "UserID" PK table value.
 

theDBguy

I’m here to help
Staff member
Local time
Yesterday, 23:18
Joined
Oct 29, 2018
Messages
21,358
Sorry - I missed your code.

I tried your syntax and it does indeed work. I knew I had to be doing something wrong. Thanks!
Okay. Glad to hear you got it sorted out. Good luck with your project.
 

cheekybuddha

AWF VIP
Local time
Today, 06:18
Joined
Jul 21, 2014
Messages
2,237
Code:
Private Sub Form_Load()

    On Error Resume Next

    Dim CurrentUserID As Integer
        
    CurrentUserID = TempVars(CurrentUserID).Value

At this point CurrentUserID = 0. You are accessing the TempVars using an index as opposed to a (string) key, so you are setting your variable to whatever value is held in the first TempVar, which I guess is not what you want to do!

The On Error Resume Next isn't doing you any favours here.
 

Solo712

Registered User.
Local time
Today, 02:18
Joined
Oct 19, 2012
Messages
828
Like Colin, I have generally avoided Tempvars, in preference to global variables. I have however changed my standard in favour of "system" parameter variables kept in a table. Here are the benefits of the approach:

  • It groups variables for easier retrieval and control.
  • It simplifies the access to, and manipulation of, global project management data. It requires no bulk loading or saving of data (as the implementation of a set of globals from a table would). Data can be read from, and written into, the table at any time during the execution of a program. It allows wholesale deletions of items marked as temps or resets to “empty” state by section.
  • It adds security and code stability; data will not be lost when an Access program is reset. The library VBA code protects the individual items from accidental deletes and overwrites. Changes to the data are audited, with the program collecting the name of the user, the time of the change and the action taken.
  • It is flexible. It allows individual items to be deleted or reassigned to a different group. Deleted items are preserved in the table for as long as the program admin deems it useful.
  • It is persistent: storing data in a table assures its availability from one session to another (as that would be desired in general program settings, history and schedules), in that the setup is more durable than TempVars. The items may be destroyed if they are temps, or have their contents reset in closing out a session. But the constants/variables stay on, providing a steady reference without the need of additional checks for their presence.
  • The implementation (as MS Access Reference library) allows the settings and standards to be shared among a number of programs.
Here is a demo I posted here a couple of years back.
 

zeroaccess

Active member
Local time
Today, 01:18
Joined
Jan 30, 2020
Messages
671
Code:
Private Sub Form_Load()

    On Error Resume Next

    Dim CurrentUserID As Integer
     
    CurrentUserID = TempVars(CurrentUserID).Value

At this point CurrentUserID = 0. You are accessing the TempVars using an index as opposed to a (string) key, so you are setting your variable to whatever value is held in the first TempVar, which I guess is not what you want to do!

The On Error Resume Next isn't doing you any favours here.
To be clear, this works fine. The TempVar CurrentUserID does not = 0 because it was set at Login and remains throughout the session because it is a global variable.

I understand the On Error Resume Next is probably considered lazy coding, but it was needed because I included the Comments field on my record list query - Comments: IIf([Comment] Is Not Null,Replace([Comment],[Comment],"View"))

View Comment.png


And if you click to open and view the comment, you get an error saying that it can't find the form to do the user check - because the form it isn't loaded. So I just needed it to pick up and move on if that's the case. I created this part of the DB much earlier in the process and have learned a few things since then.

Looking back at it now, I could probably do an IF or a Select Case with Screen.Activeform to determine which of those two checks to do based on the current form you're on. It wouldn't really gain you any CPU cycles, though.
 
Last edited:

zeroaccess

Active member
Local time
Today, 01:18
Joined
Jan 30, 2020
Messages
671
Like Colin, I have generally avoided Tempvars, in preference to global variables. I have however changed my standard in favour of "system" parameter variables kept in a table. Here are the benefits of the approach:

  • It groups variables for easier retrieval and control.
  • It simplifies the access to, and manipulation of, global project management data. It requires no bulk loading or saving of data (as the implementation of a set of globals from a table would). Data can be read from, and written into, the table at any time during the execution of a program. It allows wholesale deletions of items marked as temps or resets to “empty” state by section.
  • It adds security and code stability; data will not be lost when an Access program is reset. The library VBA code protects the individual items from accidental deletes and overwrites. Changes to the data are audited, with the program collecting the name of the user, the time of the change and the action taken.
  • It is flexible. It allows individual items to be deleted or reassigned to a different group. Deleted items are preserved in the table for as long as the program admin deems it useful.
  • It is persistent: storing data in a table assures its availability from one session to another (as that would be desired in general program settings, history and schedules), in that the setup is more durable than TempVars. The items may be destroyed if they are temps, or have their contents reset in closing out a session. But the constants/variables stay on, providing a steady reference without the need of additional checks for their presence.
  • The implementation (as MS Access Reference library) allows the settings and standards to be shared among a number of programs.
Here is a demo I posted here a couple of years back.
This makes a lot of sense for program settings. I suppose for UserID login, it would not be necessary. I will keep this in mind if I ever implement user settings. However, speaking of durability, that means a back end table needs to be created for every user's settings, because their front end is going to be wiped out with every update.
 

cheekybuddha

AWF VIP
Local time
Today, 06:18
Joined
Jul 21, 2014
Messages
2,237
>> To be clear, this works fine. The TempVar CurrentUserID does not = 0 <<

CurrentUserID in the code you've shown is an integer variable in the local scope.

At the point you try to set it, and access it's value at the index of the TempVars collection its value is zero, the default value for an integer variable upon declaration.

>> because it was set at Login <<
How have you set this TempVar (ie what code have you used?)
 

zeroaccess

Active member
Local time
Today, 01:18
Joined
Jan 30, 2020
Messages
671
>> To be clear, this works fine. The TempVar CurrentUserID does not = 0 <<

CurrentUserID in the code you've shown is an integer variable in the local scope.

At the point you try to set it, and access it's value at the index of the TempVars collection its value is zero, the default value for an integer variable upon declaration.

>> because it was set at Login <<
How have you set this TempVar (ie what code have you used?)
Please see my first post in the thread.
 

cheekybuddha

AWF VIP
Local time
Today, 06:18
Joined
Jul 21, 2014
Messages
2,237
You didn't show in that code how you set the TempVar.

But anyway, you are missing my point.

In Post#19 you write:
Code:
Private Sub Form_Load()

    On Error Resume Next

    Dim CurrentUserID As Integer
      
    CurrentUserID = TempVars(CurrentUserID).Value
  
    Me.txtComment.Locked = (CurrentUserID <> Forms!frmInspection.txtUserID)
    Me.txtComment.Locked = (CurrentUserID <> Forms!frmInspectionList.cboInspector)

If IsNull(Me.Recordset("Comment")) Then
Me.txtComment.SetFocus
End If
End Sub
And you ask why with TempVars that you "can't figure out how to just use them directly."

In the above code CurrentUserID = 0 when you try and set the value of CurrentUserID. Even if you have a public variable called 'CurrentUserID' with a value set before the value will still 0 since a variable in the local scope will take precedence.

So you are effectively doing: CurrentUserID = TempVars(0).Value - which is OK if the first TempVar set since your app opens happens to be the UserID, but if another TempVar was set first then its value will be returned

Also, you never affect the value of the public CurrentUserID

To illustrate what I mean, test this simplistic code in a standard module:
Code:
Option Compare Database
Option Explicit

Public myvar As Integer

Function setMyVar(i As Integer) As Integer
  myvar = i
  setMyVar = myvar
End Function

Function ThisTest() As Integer
  Dim myvar As Integer
  ThisTest = myvar
End Function

Then in the Immediate Window (Ctrl+G):
Code:
?setMyVar(10)
10
?ThisTest
0

hth,

d
 
Last edited:

MajP

You've got your good things, and you've got mine.
Local time
Today, 02:18
Joined
May 21, 2018
Messages
8,463
Temp vars. A total waste of time. "A solution without a problems". Could not said it better.
TempVars always were a solution looking for a problem.

I doubt I would ever use global variables, but most of my dbs have a settings table. One row of data and fields for each setting.

For years before TV everyone built a Settings table with a single row of data, and a single function to pull that value and a function to update the data
Code:
Public Function GetSettings(SettingName As String) As Variant
  GetSettings = DLookup(SettingName, "tblSettings")
End Function
Public Sub SetSettings(SettingName As String, SettingValue As Variant)
  CurrentDb.Execute "Update tblSettings set " & SettingName & " = " & SettingValue
End Sub

I do not get the whole tempvar thing.
Put them in the same category as multi value fields and navigation forms. Take what is understandable and make it confusing.
 
Last edited:

The_Doc_Man

Immoderate Moderator
Staff member
Local time
Today, 01:18
Joined
Feb 28, 2001
Messages
27,001
And to be honest, the registry is nothing but a big settings table anyway. Just structured a bit stranger than ordinary tables.
 

zeroaccess

Active member
Local time
Today, 01:18
Joined
Jan 30, 2020
Messages
671
You didn't show in that code how you set the TempVar.

But anyway, you are missing my point.

In Post#19 you write:
Code:
Private Sub Form_Load()

    On Error Resume Next

    Dim CurrentUserID As Integer
   
    CurrentUserID = TempVars(CurrentUserID).Value

    Me.txtComment.Locked = (CurrentUserID <> Forms!frmInspection.txtUserID)
    Me.txtComment.Locked = (CurrentUserID <> Forms!frmInspectionList.cboInspector)

If IsNull(Me.Recordset("Comment")) Then
Me.txtComment.SetFocus
End If
End Sub
And you ask why with TempVars that you "can't figure out how to just use them directly."

In the above code CurrentUserID = 0 when you try and set the value of CurrentUserID. Even if you have a public variable called 'CurrentUserID' with a value set before the value will still 0 since a variable in the local scope will take precedence.

So you are effectively doing: CurrentUserID = TempVars(0).Value - which is OK if the first TempVar set since your app opens happens to be the UserID, but if another TempVar was set first then its value will be returned

Also, you never affect the value of the public CurrentUserID

To illustrate what I mean, test this simplistic code in a standard module:
Code:
Option Compare Database
Option Explicit

Public myvar As Integer

Function setMyVar(i As Integer) As Integer
  myvar = i
  setMyVar = myvar
End Function

Function ThisTest() As Integer
  Dim myvar As Integer
  ThisTest = myvar
End Function

Then in the Immediate Window (Ctrl+G):
Code:
?setMyVar(10)
10
?ThisTest
0

hth,

d
  1. For the syntax, theDBguy solved this by giving me the correct Syntax to use TempVars directly, see above. The code works either way, but of course I want to learn proper syntax.
  2. As to your comment about the lack of error handling, I added a hidden txtUserID on the form and simply replaced the existing code with:
    NGINX:
        Me.txtComment.Locked = TempVars("CurrentUserID") <> Me.txtUserID
    Now I don't need to get the UserID from any other forms, and I don't need On Error Resume Next.

I'm sorry that I didn't show how I set the TempVar. Here is how I do it:
  1. Startup the program, Login form appears. On Load:
    NGINX:
        DoCmd.ShowToolbar "Ribbon", acToolbarNo
        DoCmd.ApplyFilter , "[LAN ID]='" & fOSUserName & "'"
    fOSUserName is a function by Dev Ashish that uses an API to get the login name of the user. I am filtering the recordset of the Login form, which is my Users table, and which has a LAN ID (what they call it here) for each user that has been granted access. When filtered, txtFirstName greets the user. If it doesn't find you, your name will not appear, and you can't proceed, because:
  2. On Click of the login button, it compares the value of fOSUserName() to the LAN ID of the record, and if that evaluates to true, then:
    NGINX:
        TempVars.Add "CurrentUserID", UserID
    UserID is the primary key and can now be used throughout the database when creating, opening, and editing records. If false, you get a message box saying that you need to contact the Admin for access to the system. It's pretty obvious that it's going to fail if you don't see your name appear. The reason I wait until click of Login to do the actual check instead of just doing it all on load of the form is because I have a couple of things on the Login form that I want to display, including the user's First Name, the version number of the database, and a button that runs the function fOSUserName and outputs it to a message box for troubleshooting if I need to help you get access to the system and you don't know your LAN ID.
So there you have it. Not the only way to skin the cat, but it works exceedingly well.
 

Guus2005

AWF VIP
Local time
Today, 07:18
Joined
Jun 26, 2007
Messages
2,645
Thanks for all your input!

TempVars in summary:

Declaration:
Code:
    Dim tv as TempVars
    TempVars!tv = 22
Is the same as
Code:
    TempVars.add "tv",22
You can also change the variable type by simply storing the other type.
Code:
    TempVars!tv = "Might come in handy"
TempVars!tv = null
   
[TempVars]![tv] = 1
TempVars!tv = 1
TempVars("tv").Value = 1
TempVars.Item("tv") = 1
TempVars.Item(0) = 1
[TempVars].[tv] = 1 'Error, can't use dot, must use bang!

TempVars methods:
Add
Remove
RemoveAll
TempVars Properties:
Application
Count
Parent

Of which most are self explanatory but:
TempVars.Application :unlocks the Application object. Why is it here?
TempVars.Parent :don't know what this does, haven't found any practical use.

(Dis)Advantages:
You can add TempVars on the fly
TempVars collection stores Numeric and Strings but also Nulls
Are *very* persistent, until Access closes.
TempVars are available in queries
TempVars has Application object build in
TempVars are by definition global even when locally declared and initialized.
Often used in Macros
Can't use intellisense when using TempVars in the IDE
Can use a TempVars variable which was never initialized.

Can practically be used by developers who are in the process of developing a form or query and don't want to start the application from the beginning.
When you store critical variables in a TempVar collection they will be available when you start the a form or query from anywhere.
Use TempVars.RemoveAll in the first form (Splash screen/Login Screen/...) and work your way to the Form or Query in development.
TempVars are persistend so when you start the form or query in development all TempVars are available.

But you can also store the variables in a table and read the table when you start a form.
So it's really a solution without a problem...

HTH:D

@Solo712: Thanks for showing that you can use an Access database as a reference in order to use it's code. Didn't know that!

@MajP:
For years before TV everyone built a Settings table with a single row of data, and a single function to pull that value and a function to update the data
I would never make a settings table with a single row of data. But rather a row for each parameter: Less overhead.
 

MajP

You've got your good things, and you've got mine.
Local time
Today, 02:18
Joined
May 21, 2018
Messages
8,463
I would never make a settings table with a single row of data. But rather a row for each parameter: Less overhead
Yes if you are having several hundreds of settings. I have never done anything like that. Most of the stuff I have done is 10-20. There is no practical difference at those sizes.
 

cheekybuddha

AWF VIP
Local time
Today, 06:18
Joined
Jul 21, 2014
Messages
2,237
Code:
    Dim tv as TempVars
    TempVars!tv = 22

Here you do not need the first line (Dim tv As Tempvars)

Unless you want to do:
Code:
    Dim tv as TempVars
    tv!tv = 22

But your tv variable will go out of scope at the end of the procedure.

I completely agree with all those who say that TempVars are completely unnecessary. VBA always had many existing ways to achieve the same end.
 

zeroaccess

Active member
Local time
Today, 01:18
Joined
Jan 30, 2020
Messages
671
Thanks for all your input!

But you can also store the variables in a table and read the table when you start a form.
So it's really a solution without a problem...
Can you review my last post using CurrentRecordID to return a recordset of 1 and show me how you would do that with a table? And then can you comment on which uses fewer resources? Thanks.
 

Guus2005

AWF VIP
Local time
Today, 07:18
Joined
Jun 26, 2007
Messages
2,645
Hi zeroaccess,

The thread you are refering to is marked Solved.
You should respond to that thread if you have questions about it.

I just added my 2 cents.

HTH:D
 

Users who are viewing this thread

Top Bottom