Set variable that is constant for all Subs - excel

I have several Sub's in my Module. I would like to set variable that I can use in all Subs below. How to do that?
Let's say variable is a text from ThisWorkbook.Worksheets("Sheet1").Range("E1").Value and its name should be FileNameINVREQ
How to implement that in the code? I have tried:
Option Explicit
Const FileNameINVREQ As String = ThisWorkbook.Worksheets("Sheet1").Range("E1").Value
Private Sub CreateNewINVREQtoMFiles()
...
' PD Name Or title.
oPVNew.PropertyDef = 0
oPVNew.TypedValue.SetValue MFDatatypeText, FileNameINVREQ
oPVsNew.Add -1, oPVNew
...
End Sub
Private Sub CreateINVREQtoMFiles()
...
oFile.SourceFilePath = Environ("Temp") & "\" & FileNameINVREQ & ".docx"
oFile.Title = FileNameINVREQ
oFile.extension = "docx"
oFiles.Add 0, oFile
...
End Sub

A constant means it cannot be changed. For a variable, taking data from a cell, accessible from everywhere a public function without arguments would do the job:
Public Function FileNameINVREQ() As Variant
FileNameINVREQ = ThisWorkbook.Worksheets("Sheet1").Range("E1").Value
End Function

Pulling a value from a worksheet is technically not a constant (since the value could change) so you'll need to use a variable instead. However, while you can declare variables as global, you can't set them outside of a sub or function.
My suggestion would be to move both the declaration and setting the value to its own subroutine that you reference when you need to know the value.
Global FileNameINVREQ as string
Sub FileName()
FileNameINVREQ = ThisWorkbook.Worksheets("Sheet1").Range("E1").Value
End Sub
Going a step further, you could scrap it as a variable entirely and just change that FileName sub to a function! Hopefully one of these solutions works for you!

Related

Excel vba function with specific part of a path as variable

I have a function in excel that gives hour of last modification using path , only one part of the path changes exp:
\c:\xcl\report\sudtrack\20200324\dossier22
the part is 20200324
i want to do something like that : function('20200324') the code will place it in the path
path="\\c:\xcl\report\sudtrack\" & 20200324 &"\dossier22"
my current code
Function End_hour(path As String)
End_hour = Format(FileDateTime(path), "hh:mm:ss")
End Function
i want to do something like that : function('20200324') the code will place it in the path
No need to use use a function. You can directly do a Replace. Just set up a base string as shown below and do the replace.
Option Explicit
Sub Sample()
Dim myPath As String
myPath = "\\c:\xcl\report\sudtrack\HOUROFLASTMOD\dossier22"
MsgBox Replace(myPath, "HOUROFLASTMOD", "20200324")
End Sub
Note: I have used HOUROFLASTMOD. You can change it to whatever string you want.
If you still want to use a function then try this
Option Explicit
Sub Sample()
MsgBox ReturnNewPath("20200324")
End Sub
Function ReturnNewPath(TimeString As String)
Dim myPath As String
myPath = "\\c:\xcl\report\sudtrack\HOUROFLASTMOD\dossier22"
ReturnNewPath = Replace(myPath, "HOUROFLASTMOD", TimeString)
End Function

Call constant using literals in runtime

I have declared constants like the below in the module,
Public Const strFolderA1 = "C:\ABCD\One"
Public Const strFolderA2 = "C:\ABCD\two"
I am trying to call this in a loop,
For i = 1 To 3
strFile = Dir(strFolderA & i & "\" & filenm)
Loop
The above Dir code is wrong, but I want to call the constant based on the looping integer.
Could someone help?
Please let me know if the question is not clear.
VBA does not provide any method for concatenating a string to be used as a dynamic variable name. You could create a string constant with a delimiter then split it before use.
Option Explicit
Public Const strFolderA As String = "C:\ABCD\One|C:\ABCD\Two|C:\ABCD\Three"
Sub abcs()
Dim i As Long, fldrs As Variant
fldrs = Split(strFolderA, "|")
For i = LBound(fldrs) To UBound(fldrs)
Debug.Print fldrs(i)
Next i
End Sub

vba sub insert text string into class object reference

I'm pretty new to this, so I'm sorry if I screw up any of the lingo. Thanks a bunch for anybody's help or thoughts.
I have the following wrong code:
Sub ExampleSub(text As String)
ClassObject." & text & "_attribute = 1
End Sub
So if I call ExampleSub("cheese"), I would like it to set ClassObject.cheese_attribute equal to 1.
Any thoughts? I'm not even sure it's possible.
Thanks so much!
Here is another method that might work. Use a scripting dictionary object as one of the classobject's Properties. The Dictionary Object is pretty neat, storing elements in key/value pairs, where the key is a string and the value can be any other type (object, range, Workbook, integer, variant/array, etc.)
So you can use the dictionary object to contain all of these named attributes. In your class module, add code like:
Private pAttributes as Object
Sub Class_Initialize()
'## Initialize this object to avoid a 91 error
Set pAttributes = CreateObject("Scripting.Dictionary")
End Sub
Public Property Get Attributes() As Object
Set Attributes = pAttributes
End Property
Public Property Let Attributes(lAttributes As Object)
Set pAttributes = lAttributes
End Property
Then, in your code you can simply do:
Sub ExampleSub(text As String)
ClassObject.Attributes(text) = 1
End Sub
Calling a dictionary key automatically adds the item if it doesn't already exist, but if you wanted more control you could do:
Sub AnotherExample(text as String)
If ClassObject.Attributes.Exists(text) Then
MsgBox text & " already exists!", vbInformation
Else:
ClassObject.Attributes(text) = 1
End If
End Sub

Variables and constants across multiple vba macros in same module & workbook

After a lot of small sub() writing in the same Excel workbook, I realised that I often used same part code, variables and constants. Thus I decided to write funcions() for the code, and declare variables & constant/static as Public outside functions and sub. I am very new to vba declarations and this is not so easy. Let me give you one summary of what i want to achieve. I have writen all funcions and sub in one module under the module directory of the workbook.
Option Explicit
Public ToDate As String ' variable I use in many sub and functions
Public MyPath As String ' variable I use in many sub and functions
Public NameOfWorker As Variant ' constant I use in many sub and functions
Public Salary As Double ' constant I use in many sub and functions
NameOfWorker = Cells(14, 19) ' !!! PB : 14 is highlighed with error : incorrect instruction outside a procedure
Salary = Cells(20, 7).Value '!!! same as above
How and where shall I declare such constants/statics ? Shall I write a "special" procedure to declare all these variables and constants ? I tried many way to declare them with no success.
Public Static NameOfWorker = Cells(14, 19) As String ' not working
''''''
Public Static nameOfWorker As String
NameOfWorker = Cells(14, 19) ' not working
''' etc etc
Thank you for help.
EDIT : after more reading, I found one solution this way:
Public Const MY_PATH = "Y:\path\to\directory\"
Public Const WORKERNAME = "14, 19"
Not so bad :-)
You could create a new module called something like DataHelper which looks like this:
Private NameOfWorker As String
Private AgeOfWorker As Long
Private SetupComplete As Boolean
Public Function GetNameOfWorker()
If NameOfWorker = "" Then
NameOfWorker = Sheets("SomeSheet").Cells(14, 19)
End If
GetNameOfWorker = NameOfWorker
End Function
Public Function GetAgeOfWorker()
...
End Function
Now in any other code you can retreive the value:
Sub SomeMethod()
Cells(1, 1).Value = DataHelper.GetNameOfWorker()
End Sub
...and you never have to worry if it's been set.
Good question!
I would Dim the globals above all the subs in the module, but initialize the globals at a convenient spot within some sub. For example:
Public NameOfWorker As String
Public AgeOfWorker As Long
Public SetupComplete As Boolean
Sub MAIN()
If SetupComplete Then
Else
NameOfWorker = Sheets("Sheet1").Range("B9")
AgeOfWorker = Sheets("Sheet1").Range("B10")
SetupComplete = True
MsgBox "Global variable set up complete!"
End If
End Sub

How do I declare a global variable in VBA?

I wrote the following code:
Function find_results_idle()
Public iRaw As Integer
Public iColumn As Integer
iRaw = 1
iColumn = 1
And I get the error message:
"invalid attribute in Sub or Function"
Do you know what I did wrong?
I tried to use Global instead of Public, but got the same problem.
I tried to declare the function itself as `Public, but that also did no good.
What do I need to do to create the global variable?
You need to declare the variables outside the function:
Public iRaw As Integer
Public iColumn As Integer
Function find_results_idle()
iRaw = 1
iColumn = 1
This is a question about scope.
If you only want the variables to last the lifetime of the function, use Dim (short for Dimension) inside the function or sub to declare the variables:
Function AddSomeNumbers() As Integer
Dim intA As Integer
Dim intB As Integer
intA = 2
intB = 3
AddSomeNumbers = intA + intB
End Function
'intA and intB are no longer available since the function ended
A global variable (as SLaks pointed out) is declared outside of the function using the Public keyword. This variable will be available during the life of your running application. In the case of Excel, this means the variables will be available as long as that particular Excel workbook is open.
Public intA As Integer
Private intB As Integer
Function AddSomeNumbers() As Integer
intA = 2
intB = 3
AddSomeNumbers = intA + intB
End Function
'intA and intB are still both available. However, because intA is public, '
'it can also be referenced from code in other modules. Because intB is private,'
'it will be hidden from other modules.
You can also have variables that are only accessible within a particular module (or class) by declaring them with the Private keyword.
If you're building a big application and feel a need to use global variables, I would recommend creating a separate module just for your global variables. This should help you keep track of them in one place.
To use global variables, Insert New Module from VBA Project UI and declare variables using Global
Global iRaw As Integer
Global iColumn As Integer
The question is really about scope, as the other guy put it.
In short, consider this "module":
Public Var1 As variant 'Var1 can be used in all
'modules, class modules and userforms of
'thisworkbook and will preserve any values
'assigned to it until either the workbook
'is closed or the project is reset.
Dim Var2 As Variant 'Var2 and Var3 can be used anywhere on the
Private Var3 As Variant ''current module and will preserve any values
''they're assigned until either the workbook
''is closed or the project is reset.
Sub MySub() 'Var4 can only be used within the procedure MySub
Dim Var4 as Variant ''and will only store values until the procedure
End Sub ''ends.
Sub MyOtherSub() 'You can even declare another Var4 within a
Dim Var4 as Variant ''different procedure without generating an
End Sub ''error (only possible confusion).
You can check out this MSDN reference for more on variable declaration and this other Stack Overflow Question for more on how variables go out of scope.
Two other quick things:
Be organized when using workbook level variables, so your code doesn't get confusing. Prefer Functions (with proper data types) or passing arguments ByRef.
If you want a variable to preserve its value between calls, you can use the Static statement.
If this function is in a module/class, you could just write them outside of the function, so it has Global Scope. Global Scope means the variable can be accessed by another function in the same module/class (if you use dim as declaration statement, use public if you want the variables can be accessed by all function in all modules) :
Dim iRaw As Integer
Dim iColumn As Integer
Function find_results_idle()
iRaw = 1
iColumn = 1
End Function
Function this_can_access_global()
iRaw = 2
iColumn = 2
End Function
Also you can use -
Private Const SrlNumber As Integer = 910
Private Sub Workbook_Open()
If SrlNumber > 900 Then
MsgBox "This serial number is valid"
Else
MsgBox "This serial number is not valid"
End If
End Sub
Its tested on office 2010
The best way I find is to assign a property to the Workbook
It's scope remains valid as long as the workbook is open
Public WhenOpened As Date
Private Sub Workbook_Open()
ThisWorkbook.WhenOpened = Now()
End Sub
Create a public integer in the General Declaration.
Then in your function you can increase its value each time.
See example (function to save attachements of an email as CSV).
Public Numerator As Integer
Public Sub saveAttachtoDisk(itm As Outlook.MailItem)
Dim objAtt As Outlook.Attachment
Dim saveFolder As String
Dim FileName As String
saveFolder = "c:\temp\"
For Each objAtt In itm.Attachments
FileName = objAtt.DisplayName & "_" & Numerator & "_" & Format(Now, "yyyy-mm-dd H-mm-ss") & ".CSV"
objAtt.SaveAsFile saveFolder & "\" & FileName
Numerator = Numerator + 1
Set objAtt = Nothing
Next
End Sub
A good way to create Public/Global variables is to treat the Form like a class object and declare properties and use Public Property Get [variable] to access property/method. Also you might need to reference or pass a Reference to the instantiated Form module. You will get errors if you call methods to forms/reports that are closed.
Example: pass Me.Form.Module.Parent into sub/function not inside form.
Option Compare Database
Option Explicit
''***********************************''
' Name: Date: Created Date Author: Name
' Current Version: 1.0
' Called by:
''***********************************''
' Notes: Explain Who what when why...
' This code Example requires properties to be filled in
''***********************************''
' Global Variables
Public GlobalData As Variant
''***********************************''
' Private Variables
Private ObjectReference As Object
Private ExampleVariable As Variant
Private ExampleData As Variant
''***********************************''
' Public properties
Public Property Get ObjectVariable() As Object
Set ObjectVariable = ObjectReference
End Property
Public Property Get Variable1() As Variant
'Recommend using variants to avoid data errors
Variable1 = ExampleVariable
End property
''***********************************''
' Public Functions that return values
Public Function DataReturn (Input As Variant) As Variant
DataReturn = ExampleData + Input
End Function
''***********************************''
' Public Sub Routines
Public Sub GlobalMethod()
'call local Functions/Subs outside of form
Me.Form.Refresh
End Sub
''***********************************''
' Private Functions/Subs used not visible outside
''***********************************''
End Code
So in the other module you would be able to access:
Public Sub Method1(objForm as Object)
'read/write data value
objForm.GlobalData
'Get object reference (need to add Public Property Set to change reference object)
objForm.ObjectVariable
'read only (needs Public property Let to change value)
objForm.Variable1
'Gets result of function with input
objForm.DataReturn([Input])
'runs sub/function from outside of normal scope
objForm.GlobalMethod
End Sub
If you use Late Binding like I do always check for Null values and objects that are Nothing before attempting to do any processing.

Resources