Excel vba variable not defined when using range variable - vba

I have function testFunc that takes Range as an argument, loops thorugh its cells and edits them. I have sub testSub that tests two cases: first is when I pass the current workbook's range to testFunc through: 1. variable Range 2. just as an argument testFunct(...Range("A1:A16")).
The second case is when I open another workbook and do the same - pass one of its worksheets range to the testFunc directly or via variable.
Function testFunc(aCol As Range)
Dim i As Integer
i = 0
For Each cell In aCol
MsgBox (cell.Value)
cell.Value = i
i = i + 1
Next
testFunc = i
End Function
Sub testSub()
Dim origWorkbook As Workbook
Set origWorkbook = ActiveWorkbook
Dim aRange As Range
Set aRange = ThisWorkbook.Sheets("sheet 1").Range("A1:A16")
Dim dataWorkbook As Workbook
Set dataWorkbook = Application.Workbooks.Open("Y:\vba\test_reserves\test_data\0503317-3_FO_001-2582480.XLS")
Dim incomesNamesRange As Range
Set incomesNamesRange = dataWorkbook.Worksheets("sheet 1").Range("A1:A20")
' origWorkbook.Worksheets("sheet 1").Cells(1, 5) = testFunc(dataWorkbook.Sheets("1").Range("A1:A20"))
origWorkbook.Worksheets("Ëèñò2").Cells(1, 50) = testFunc(incomesNamesRange)
' testFunc aRange
'origWorkbook.Worksheets("sheet 1").Cells(1, 5) = testFunc(aRange) '<---good
' origWorkbook.Worksheets("sheet 1").Cells(1, 5) = testFunc(ThisWorkbook.Sheets("sheet 1").Range("A1:A16"))
End Sub
The problem is, as I indicated with comments, when I open a foreign workbook and pass its range through a variable it gives an error variable not definedFor Each cell In aCol`, while all other cases (including passing range variable of the current workbook) work fine.
I need testFunc to stay a Function, because it's a simplfied example of some code from bigger program which needs to take a returned value from a function. And I need to store that Range in a variable too, to minimize time of the execution.
EDIT: As pointed out in the comments, I replaced Cells(1,5) with origWorkbook.Worksheet("shee t1").Cells(1,5) and fixed variable name, but the original mistake changed to variable not defined. I edited the title and body of the question.

The default name for the worksheet shouldn't have a space in it.
Set incomesNamesRange = dataWorkbook.Worksheets("sheet 1").Range("A1:A20")
Change this to:
Set incomesNamesRange = dataWorkbook.Worksheets("Sheet1").Range("A1:A20")
And see if that fixes it.

Related

Excel VBA For Each Loop giving out of range error

I have 2 workbooks open, and I am trying to copy one range of cells from one workbook into the other workbook based on a condition. The program keeps on breaking at the first For Each loop with the
Subscript out of range
error and I am lost as to why.
I looked at other threads here, and they said that the error comes from not having an Open workbook. I implemented that, and it still gives me this error.
I am new to VBA. Any ideas?
Sub TransferCells()
Dim aggrange As Range
Dim AnalyticalCell As Range
Dim BatchCell As Range
Dim analyticalwb, batchwb As Excel.Workbook
Dim SEHPLC, CultureDay As Worksheet
Set analyticalwb = Workbooks.Open("\\ntucsmafps06.na.jn.com\Hom$\APachall\Ta Big Data\Cas tical Results (4).xlsm")
Set batchwb = Workbooks.Open("\\nctusmafp0s6.na.jn.com\Hom$\APachall\Ta Big Data\20180420_Fed Batch All Data_0.xlsx")
For Each AnalyticalCell In analyticalwb.Worksheets("SE-HPLC").Range("A1:A87")
For Each BatchCell In batchwb.Worksheets("Sheet3").Range("A2:A125271")
If AnalyticalCell.Value = BatchCell.Value Then
Set aggrange = Range(ActiveCell.Offset(0, 11), ActiveCell.Offset(0, 13))
aggrange.Copy (Destination = Application.Workbooks("20180420_Fed Batch All Data_0.xlsx").Worksheets("Sheet3").Range(ActiveCell.Offset(0, 3), ActiveCell.Offset(0, 5)))
End If
Next BatchCell
Next AnalyticalCell
End Sub
Change the problematic code to the following. There are 2 errors there:
With Worksheets(ActiveCell.Parent.Name)
aggrange.Copy Destination:=Application.Workbooks("20180420_Fed Batch All Data_0.xlsx").Worksheets("Sheet3").Range(.Cells(ActiveCell.Offset(0, 3)), .Cells(ActiveCell.Offset(0, 5)))
End With
Destination is a named parameter, thus it should be passed with := and not with =;
To pass a range, based on two cells, you need to pass:
Range(.Cells(ActiveCell.Offset(0, 3)), .Cells(ActiveCell.Offset(0, 5))) and not Range(). Range() takes string as arguments.
Further ideas - the Dim should be done per variable. In other languages (C++, etc) it is ok, in vba it is a bit problematic:
Dim analyticalwb As Excel.Workbook, batchwb As Excel.Workbook
Dim SEHPLC As Worksheet, CultureDay As Worksheet
How to avoid using Select in Excel VBA
Write Option Explicit on the top of the Module and see whether it compiles.

Excel VBA .Find Function changing values in selection

Heya this is probably simple but I cannot figure out what is wrong.
I am trying to do .find for a specific date and change that selection to a user input date.
I have a userform to select a date from a combobox (date1_cbo). The combobox source is linked to dates on a worksheet (Backend). There is a textbox below for writing the new date to change it to (date1_txt). I keep getting an error
object variable or with block variable not set.
I have tried a few options without any luck here is my code:
Dim selection As Range
Dim check As Boolean
'input box validation
check = IsDate(date1_txt.Value)
If check = True Then
'find cell matching combobox
With Worksheets("Backend").Range("A1:A500")
Set selection = .Find(date1_cbo.Value) 'this is the problem
selection.Value = date1_txt.Value
End With
Else
End If
Interestingly .Find returns the range or Nothing. however because the combobox is linked to the cells I am searching through this should never return nothing... I dont understand why the error is occurring.
a variable named as 'selection' is bad coding practice but totally legal. Don't use such names for the sake of clarity.
Error 91 is caused when you are trying to read a property( .value) from null object. your selection variable is null cause date formats on the sheet and combobox are different.
Just convert to date before attempting to find it in sheet.
Set selection = .Find(CDate(date1_cbo.Value)) '/ once again, selection is valid but bad name for variable.
You are using a variable named Selection. VBA uses it as well. Rename your variable to anything else, rewrite your code and it should work. Even Selection1 is quite ok:
Public Sub TestMe()
Dim selection1 As Range
With Worksheets(1).Range("A1:A500")
Set selection1 = .Find("vi")
End With
If Not selection Is Nothing Then
selection1.Value = "some other value"
End If
End Sub
To change multiple values with Find() as here - A1:A10, then some possibility is to do it like this:
Public Sub TestMe()
Dim myRng As Range
With Worksheets(1).Range("A1:A500")
.Range("A1:A10") = "vi"
Set myRng = .Find("vi")
If Not myRng Is Nothing Then
Do Until myRng Is Nothing
myRng.Value = "New value"
Set myRng = .Find("vi")
Loop
End If
End With
End Sub
It is a bit slow, as far as it loops every time and it can be improved, if the range is united and replaced at once.

Can I create a Jump table in VBA for Excel?

I wrote a simple translator / parser to process an EDI (830) document using multiple Select Case statements to determine the code to be executed. I’m opening a file in binary mode and splitting the document into individual lines, then each line is split into the various elements where the first element of every line has a unique segment identifier.
My code works perfectly as written. However, Select Case requires checking every Case until a match is found or the Case Else is executed. I’ve sequenced the Case statements in such a manner that the segments that appear most frequently (as in the case of loops), are placed first to minimize the number of "checks before code is actually executed.
Rather than using multiple Select Cases, I would prefer to determine an index for the segment identifier and simply call the appropriate routine using that index. I’ve used jump tables in C and Assembler and anticipated similar functionality may be possible in VBA.
You can do jump tables in VBA by using the Application.Run method to call the appropriate routine by name. The following code demonstrates how it works:
Public Sub JumpTableDemo()
Dim avarIdentifiers() As Variant
avarIdentifiers = Array("Segment1", "Segment2")
Dim varIdentifier As Variant
For Each varIdentifier In avarIdentifiers
Run "Do_" & varIdentifier
Next varIdentifier
End Sub
Public Sub Do_Segment1()
Debug.Print "Segment1"
End Sub
Public Sub Do_Segment2()
Debug.Print "Segment2"
End Sub
You can do this in Excel VBA, following the example below:
The example assumes you have split your EDI document into two columns, one with the 'processing instruction' and one with the data that instruction will process.
The jump table is to the right i.e. a distinct list of the 'processing instructions' plus a name of a Sub-routine to run for each instruction.
The code is:
Option Explicit
Sub JumpTable()
Dim wsf As WorksheetFunction
Dim ws As Worksheet
Dim rngData As Range '<-- data from your file
Dim rngCell As Range '<-- current "instruction"
Dim rngJump As Range '<-- table of values and sub to run for value
Dim strJumpSub As String
Dim strJumpData As String
Set wsf = Application.WorksheetFunction '<-- just a coding shortcut
Set ws = ThisWorkbook.Worksheets("Sheet1") '<-- change to your worksheet
Set rngData = ws.Range("A2:A17") '<-- change to your range
Set rngJump = ws.Range("E2:F4") '<-- change to your circumstances
For Each rngCell In rngData
strJumpSub = wsf.VLookup(rngCell.Value, rngJump, 2, False) '<-- lookup the sub
strJumpData = rngCell.Offset(0, 1).Value '<-- get the data
Application.Run strJumpSub, strJumpData '<-- call the sub with the data
Next rngCell
End Sub
Sub do_foo(strData As String)
Debug.Print strData
End Sub
Sub do_bar(strData As String)
Debug.Print strData
End Sub
Sub do_baz(strData As String)
Debug.Print strData
End Sub
Make sure that you have written a Sub for each entry in the jump table.

Object Required Error VBA Function

I've started to use Macros this weekend (I tend to pick up quickly in regards to computers). So far I've been able to get by with searching for answers when I have questions, but my understanding is so limited I'm to a point where I'm no longer understanding the answers. I am writing a function using VBA for Excel. I'd like the function to result in a range, that can then be used as a variable for another function later. This is the code that I have:
Function StartingCell() As Range
Dim cNum As Integer
Dim R As Integer
Dim C As Variant
C = InputBox("Starting Column:")
R = InputBox("Starting Row:")
cNum = Range(C & 1).Column
Cells(R, cNum).Select
The code up to here works. It selects the cell and all is well in the world.
Set StartingCell = Range(Cell.Address)
End Function
I suppose I have no idea how to save this location as the StartingCell(). I used the same code as I had seen in another very similar situation with the "= Range(Cell.Address)." But that's not working here. Any ideas? Do I need to give more information for help? Thanks for your input!
Edit: I forgot to add that I'm using the InputBox to select the starting cell because I will be reusing this code with multiple data sets and will need to put each data set in a different location, each time this will follow the same population pattern.
Thank you A.S.H & Shai Rado
I've updated the code to:
Function selectQuadrant() As Range
Dim myRange As Range
Set myRange = Application.InputBox(Prompt:="Enter a range: ", Type:=8)
Set selectQuadrant = myRange
End Function
This is working well. (It appears that text is supposed to show "Enter a range:" but it only showed "Input" for the InputBox. Possibly this could be because I'm on a Mac?
Anyhow. I was able to call the function and set it to a new variable in my other code. But I'm doing something similar to set a long (for a color) so I can select cells of a certain color within a range but I'm getting all kinds of Object errors here as well. I really don't understand it. (And I think I'm dealing with more issues because, being on a mac, I don't have the typical window to edit my macros. Just me, basically a text box and the internet.
So. Here also is the Function for the Color and the Sub that is using the functions. (I've edited both so much I'm not sure where I started or where the error is.)
I'm using the functions and setting the variables to equal the function results.
Sub SelectQuadrantAndPlanets()
Dim quadrant As Range
Dim planetColor As Long
Set quadrant = selectQuadrant()
Set planetColor = selectPlanetColor() '<This is the row that highlights as an error
Call selectAllPlanets(quadrant, planetColor)
End Sub
This is the function I'm using to select the color that I want to highlight within my range
I would alternately be ok with using the interior color from a range that I select, but I didn't know how to set the interior color as the variable so instead I went with the 1, 2 or 3 in the input box.
Function selectPlanetColor() As Long
Dim Color As Integer
Color = InputBox("What Color" _
& vbNewLine & "1 = Large Planets" _
& vbNewLine & "2 = Medium Planets" _
& vbNewLine & "3 = Small Planets")
Dim LargePlanet As Long
Dim MediumPLanet As Long
Dim smallPlanet As Long
LargePlanet = 5475797
MediumPlanet = 9620956
smallPlanet = 12893591
If Color = 1 Then
selectPlanetColor = LargePlanet
Else
If Color = 2 Then
selectPlanetColor = MediumPlanet
Else
If Color = 3 Then
selectPlanetColor = smallPlanet
End If
End If
End If
End Function
Any help would be amazing. I've been able to do the pieces individually but now drawing them all together into one sub that calls on them is not working out well for me. Thank you VBA community :)
It's much simpler. Just
Set StartingCell = Cells(R, C)
after getting the inputs, then End Function.
The magic of the Cells method is it accepts, for its second parameter, both a number or a character. That is:
Cells(3, 4) <=> Cells(3, "D")
and
Cells(1, 28) <=> Cells(3, "AB")
One more thing, you can prompt the user directly to enter a range, with just one input box, like this:
Dim myRange as Range
Set myRange = Application.InputBox(Prompt:="Enter a range: ", Type:=8)
The Type:=8 specifies the input prompted for is a Range.
Last thing, since you are in the learning process of VBA, avoid as much as possible:
using the Select and Activate stuff
using unqualified ranges. This refers to anywhere the methods Cells(..) or Range(..) appear without a dot . before them. That usually leads to some random issues, because they refer to the ActiveSheet, which means the behavior of the routine will depend on what is the active worksheet at the moment they run. Avoid this and always refer explicitly from which sheet you define the range.
Continuing your line of thought of selecting the Range bu Selecting the Column and Row using the InputBox, use the Application.InputBox and add the Type at the end to restrict the options of the user to the type you want (Type:= 1 >> String, Type:= 2 >> Number).
Function StartingCell Code
Function StartingCell() As Range
Dim cNum As Integer
Dim R As Integer
Dim C As Variant
C = Application.InputBox(prompt:="Starting Column:", Type:=2) '<-- type 2 inidcates a String
R = Application.InputBox(prompt:="Starting Row:", Type:=1) '<-- type 1 inidcates a Number
Set StartingCell = Range(Cells(R, C), Cells(R, C))
End Function
Sub TestFunc Code (to test the function)
Sub TestFunc()
Dim StartCell As Range
Dim StartCellAddress As String
Set StartCell = StartingCell '<-- set the Range address to a variable (using the function)
StartCellAddress = StartCell.Address '<-- read the Range address to a String
End Sub

Different Results with Different PCs: Run Time Error 91 Object Variable or With Block Not Set

I run the code below in two different PCs while get two different result: one works fine, another reminds "run time error 91 object variable or with block not set". Can anybody help me out?
Function FindArchiveFile() As String
FindArchiveFile = Application.Intersect(Worksheets("Filelist").UsedRange, _
Worksheets("Filelist").Range("B:B")).Find( _
CDate(WorksheetFunction.Large(Workshee‌​ts("Filelist").Range("B:B"), 2))).Offset(0, -1).Value
Worksheets("Setting").Range("LastDate").Value = _
Application.Intersect(Worksheets("Filelist").UsedRange, _
Worksheets("Filelist").Range("B:B")).Find( _
CDate(WorksheetFunction.Large(Workshee‌ts("Filelist").Range("B:B"), 2))).Value
End Function
I've revised your function to make it more human-readable. This should work with some caveats.
If you are calling this function from a worksheet, it is unlikely to work.
This is because a workhseet function can generally only return a value to the calling cell. It cannot otherwise manipulate the worksheet objects. This function is trying to set a value in a named range "LastDate" and this is likely to fail. It may fail silently on this line and still return the value to the calling cell.
This function when called from a worksheet will likely raise a Circular Reference Error
When called from a subroutine, this function appears to work, or at least it does not return an error for me.
Sub Test()
'Use this to test the function
MsgBox FindArchiveFile
Worksheets("Setting").Range("LastDate").Value = FindArchiveFile
End Sub
Function FindArchiveFile() As String
Dim ws As Worksheet
Dim rngB As Range
Dim rngInt As Range
Dim foundVal As String
Set ws = Worksheets("Filelist")
Set rngB = ws.Range("B:B")
Set rngInt = Application.Intersect(ws.UsedRange, rngB)
foundVal = rngInt.Find( _
CDate(WorksheetFunction.Large(rngB, 2))).Offset(0, -1).Value
'## I comment the next line out and put it in the calling subroutine, since
' the function returns a value, use the function properly.
'Worksheets("Setting").Range("LastDate").Value = foundVal
FindArchiveFile = IIf(foundVal = vbNullString, "Not Found", foundVal)
End Function