Used named ranges in VBA - vba

from1,from2,from3,to1,to2,to3 are all pre-defined named ranges. They all have the same dimension. I'm just trying to replace all the to's with all the from's.
The following code keeps giving me a type mismatch error on this line
ThisWorkbook.Names(to_ranges(i)) = ThisWorkbook.Names(from_ranges(i))
Could someone help? Thank you!
Sub named_ranges()
Dim from_ranges() As Variant, to_ranges() As Variant
from_ranges() = Array("from_1", "from_2", "from_3")
to_ranges() = Array("to_1", "to_2", "to_3")
Dim i As Integer
For i = 0 To UBound(from_ranges)
ThisWorkbook.Names(to_ranges(i)) = ThisWorkbook.Names(from_ranges(i))
Next i
End Sub

When you define a named range you define it's scope (worksheet or workbook). So:
Range(to_ranges(i)) = Range(from_ranges(i))
Will probably work just fine as the default scope for a named range is "Workbook".
That being said, you can use the .Names object here as well, you just need to get it's .RefersToRange property otherwise you aren't copying a range, instead you are copying the default property of the Name object which is its "RefersToRange" which is just a string.
Essentially you are doing:
Names(to_ranges(i)).RefersToRange = Names(from_ranges(i)).RefersToRange
Which is incorrect.
Instead (and this is total overkill compared to the first example above):
Range(Names(to_ranges(i)).RefersToRange).Value = Range(Names(from_ranges(i)).RefersToRange).Value
And... ultimately this doesn't solve your initial concern of Name scopes (workbook vs worksheet) as the RefersToRange will be scoped as it was was defined and may still end up hitting your ActiveSheet if it improperly scoped AND left unqualified here.

Related

Returning the address of a vlookup function in vba

I've looked through all guides I can find on this subject but not a single one solves my problem.
I want to find the cell address of this vlookup function:
vlookadd = Application.Lookup(partno, Sheet3.Range("A5:B46"), 2, False)
(Currently dimmed as variant incase that needs to be changed)
I want to find the address of the value found and make it equal a variable so something like this:
batch1add = vlookadd.Address
The value found by the lookup function works fine but the address always comes up empty after trying lots of different possible solutions
as well as using find
cells(worksheetfunction.match(partno,range("a5:a46"),0)+4,2).address
The plus 4 is due to the start row of the range being 5, for example a match in row 5 will return 1.
Per the comments, using Find and an offset should be just fine.
Function getAddress(itemToFind As Variant, lookupRange As Range, columnOffset As Integer)
getAddress = lookupRange.Find(What:=itemToFind).Offset(0, columnOffset).address
End Function
Sub Example()
Dim batch1add As String
Set batch1add = getAddress(partno, Sheet3.Range("A5:B46"), 2)
End Sub
As PEH advised in the prior answer's comments: Incorporating some error handling would be wise, as both implementations assume the value exists whenever they're called.

defining code on vba excel to simplify code writing process

I am attempting to reduce the amount of clutter on my code by creating "shortcuts" if you will
For instance, I always have to type
ThisWorkBook.ActiveSheet.Range
Is there a way for me to define the above to create a less wordy macro? I have tried convert to range and string and the former returns an error (but I could still get intellisense recognize and attempt to autofill) while the string version doesnt work.
Just like in any programming language, you can use variables to store data
For example:
Dim myrange As Range: Set myrange = Sheets("Sheet1").Range("B5")
Alternatively, if you will be working with the same object multiple times, you can use the With keyword
For example. instead of writing you want to work with table every time on every new line you can do
With Sheets("Sheet1").ListObjects("Table1")
.ListRows.Add
.ListColumns(2).Range(3) = "Hello World!"
' ... and so on
End With
Also, please on a sidenote: Avoid using Select/ActiveSheet/ActiveWorkbook and so on!
More info on how to here
You can create functions or customized properties, which are always evaluated when called
Property Get pARng As Range
Set pARng = ThisWorkBook.ActiveSheet.Range
End Property
Function fARng As Range
Set fARng = ThisWorkBook.ActiveSheet.Range
End Function
'Usage
Sub xxx
'...
pARng.Rows(1).Activate
'Same as ThisWorkBook.ActiveSheet.Range.Rows(1).Activate
fARng.Rows(1).Activate
'using function instead achieves same result
End Sub

VBA, Excel, use Range to fill 2D-Array [duplicate]

This question already has answers here:
Why am I having issues assigning a Range to an Array of Variants
(3 answers)
Closed 7 years ago.
I do not understand this behaviour:
Sub tuEs()
Dim A() As Variant
A = Range("A1:A10") ' works
Dim B() As Variant
B = ActiveSheet.Range("A1:A10") ' Type mismatch
End Sub
The first version works the 2nd version does not. Why? What is the difference?
The way to go with this is by adding the ".value" at the end of the range. This is usually a good idea to make things very explicit (the reason you can omit this is because value is the default property for the range object)
I added all the values to watches to see what was going on and apparently there is a problem of Excel not been able to effectively ( and implicitly ) cast the object on the fly. Note in the picture how the expression that is failing "ActiveSheet.Range("A1:A10") is of type: Variant/Object/Range; the transition from Variant to object is most likely causing the issue.
A way to force it to cast correctly would be to split the process in two parts the first one casts to range and the second one casts to a variant array. Look at my example
Also notice that if you declare the variable as variant alone and not an array of variants (dim E and not dim E()) it will get it because the it will adapt to what is needed.
Sub tuEs()
'Works
Dim A() As Variant
A = Range("A1:A10")
' Type missmatch
Dim B() As Variant
B = ActiveSheet.Range("A1:A10")
' Fix to make it cast properly
Dim C() As Variant
Dim r As Range
Set r = ActiveSheet.Range("A1:A10")
C = r
' Best of all options
Dim d As Variant
d = ActiveSheet.Range("A1:A10").Value
End Sub
Hope this makes is somewhat clear.
This is indeed a mystery! But this works (no need to declare an array of variant objects, just a variant). As to why it doesn't work in your code as stated, I am afraid I can't answer.
Dim B As Variant ' instead of Dim B() as Variant
B = ActiveSheet.Range("A1:A10")
At first I thought it to be a syntax issue - some hidden ambiguity that caused the interpreter to respond differently to the different statements. But to my dismay the following code works flawlessly:
Dim B() as Variant
B = Application.Range("A1:A10")
As it is syntatically identical to the crashing line in the question, the only possible conclusion, AFAIK is that the implementations of Range in the Worksheet and in the Application classes return different types of objects even if they contain, in essence, the same information. Most casts will render the same results, but for some implementation quirk, only the Application version can be cast to an array of variants. This conclusion is backed by the fact that inspecting the results of expressions Range("A1:A10") and ActiveSheet.Range("A1:A10") in debug mode result in different type informations - "Object/Range" in the first case and "Variant/Object/Range" in the second.
If this is true, the exact reason for the difference (if not an accident at all) is probably known only by the coders or other folks at MS. I am curious if this is consistent thru different versions of Office..

VBA UDF fails to call Range.Precedents property

I am trying to write a simple UDF, which is supposed to loop through each of the cells of a given_row, and pick up those cells which do not have any precedent ranges, and add up the values.
Here is the code:
Public Function TotalActualDeductions(given_row As Integer) As Integer
Total_Actual_Deduction = 0
For present_column = 4 To 153
Set precedent_range = Nothing
If Cells(2, present_column) = "TDS (Replace computed figure when actually deducted)" Then
On Error Resume Next
Set precedent_range = Cells(given_row, present_column).Precedents
If precedent_range Is Nothing Then
Total_Actual_Deduction = Total_Actual_Deduction + Cells(given_row, present_column)
End If
End If
Next
TotalActualDeductions = Total_Actual_Deduction
End Function
If I try to run it by modifying the top declaration, from:
Public Function TotalActualDeductions(given_row As Integer) As Integer
to:
Public Function TotalActualDeductions()
given_row = 4
then it runs successfully, and as expected. It picks up exactly those cells which match the criteria, and all is good.
However, when I try to run this as a proper UDF from the worksheet, it does not work. Apparently, excel treats those cells which have no precedents, as though they have precedents, when I call the function from the worksheet.
I don't know why this happens, or if the range.precedents property is supposed to behave like this.
How can this be fixed?
After a lot of searching, I encountered this:
When called from an Excel VBA UDF, Range.Precedents returns the range and not its precedents. Is there a workaround?
Apparently, "any call to .Precedents in a call stack that includes a UDF gets handled differntly".
So, what I did was use Range.Formula Like "=[a-zA-Z]" , because it satisfied my simple purpose. It is in no way an ideal alternative to the range.precedents property.
Foe a more detailed explanation, please visit that link.

Make a string equal to what a named range refers to?

I have a named range called tempPrintArea
it refers to ="A1:J59"
I created it with VBA and the scope became local. I don't know if the scope matters.
I used this line to create the named range:
wks.Names.Add Name:="tempPrintArea", RefersTo:="A1:J59"
Now I want to set the value of a string to "A1:J59". I've tried the following:
Dim test As String
test = Range("tempPrintArea").RefersTo
but I get the error message Method 'Range' out of object '_Gloabl' failed
What can I change in these code lines to get this working?
When you're using
wks.Names.Add Name:="tempPrintArea", RefersTo:="A1:J59"
code doesn't create named range that refers to A1:J59, instead code creates named range with text "A1:J59".
For creating named range use this one instead:
wks.Names.Add Name:="tempPrintArea", RefersTo:=wks.Range("A1:J59")
and then
Dim test As String
test = wks.Range("tempPrintArea").Address(False, False) ' returns A1:J59