Excel VBA For Each Loop giving out of range error - vba

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.

Related

VBA RBG - "Wrong number of arguments or invalid property argument"

I know there are other questions which deal with the "Wrong number of arguments or invalid property assignment", but none which deal with this error being generated on a basic line assigning an RGB colour to a cell interior.
This error is generating on line 6 of the below. I don't understand how this is possible, as RGB clearly has three arguments.
The only thing I can think of is that, earlier today, I wrote a macro in a different (now closed spreadsheet), where I used the initials "rgb" as a variant name. I know that, in R, it's possible to redefine a base function accidentally by replacing it with a UDF, and I'm wondering whether perhaps I've now unwittingly changed "rgb" to be something other than the function in the VBA base code. But that doesn't sound plausible - I've never heard of that happening in VBA, and it's more of a "for dummies" type language which I wouldn't have thought would give users that optionality.
EDIT Yes - this issue is resolved by changing the name of the macro, which is a stupid error. However, I would point out that this error is also happening in a different subroutine, which I have not named in such a stupid fashion. I will need to investigate why it's happening in that sub too.
Option Explicit
Sub RGB()
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ThisWorkbook
Set ws = Sheets("Sheet1")
ws.Range("G20").Interior.Color = RGB(255, 51, 204)
End Sub
In case the comments haven't explained it fully.. you state in your question:
earlier today, I wrote a macro in a different (now closed
spreadsheet), where I used the initials "rgb" as a variant name.
However, in the example you provide, you've actually called the Subroutine you're calling RGB as well. This is the cause of the issue. Renaming it would fix it but while I'm here I can share with you some other points:
This would work:
Option Explicit
Sub Set_G20_RGB()
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ThisWorkbook
Set ws = Sheets("Sheet1") ' should really be Set ws = wb.Sheets("Sheet1")
ws.Range("G20").Interior.Color = RGB(255, 51, 204)
End Sub
However, to make it a little more useful, you might want to use something like:
Option Explicit
Sub Set_RGB(clr_rng As Range, red_value As Integer, grn_value As Integer, blu_value As Integer)
clr_rng.Interior.Color = RGB(red_value, grn_value, blu_value)
End Sub
Which could be called like so:
Set_RGB ThisWorkbook.Sheets("Sheet1").Range("G20"), 255, 51, 204
or..
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ThisWorkbook
Set ws = wb.Sheets("Sheet1")
Set_RGB ws.Range("G20"), 255, 51, 204

Excel VBA macro to copy certain columns to another Workbook

I need to copy certain columns of one spreadsheet to another spreadsheet.
In order to do so, I have a macro:
Sub Submit()
Dim sourceColumn As Range, targetColumn As Range
Set sourceColumn =
Workbooks("Submission_Form.xlsm").Worksheets("RGSheet").Columns("A")
Set myData = Workbooks.Open("I:\Projects\...\Macros\RG.csv")
Worksheets(1).Select
Worksheets(1).Range("A1").Select
Set targetColumn = Workbooks("RG.csv").Worksheets(1).Columns("A")
sourceColumn.Copy Destination:=targetColumn
End Sub
However, when the cursor hits targetColumn, it gives error:
Run-time error '9':
Subscript out of range
For the sake of simplicity, I have put RG.csv in the same folder as Submission_Form.xlsm. So I am really confused why is it giving error.
I would also like to know how to handle if the RG.csv is located in another directory.
The error is probably because Submission_Form.xlsm isn't opened(?). Your code looks a little inconsistent. Maybe just open both source and destination, and copy the column. Something like this?
Option Explicit
Sub Submit()
Dim vSourceWorkbook As Workbook
Dim vDestinationWorkbook As Workbook
Set vSourceWorkbook = Workbooks.Open("Submission_Form.xlsm")
Set vDestinationWorkbook = Workbooks.Open("I:\Projects\...\Macros\RG.csv")
vSourceWorkbook.Worksheets("RGSheet").Range("A:A").Copy Destination:=vDestinationWorkbook.Worksheets(1).Range("A:A")
End Sub

Excel vba variable not defined when using range variable

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.

Store COPY of a worksheet in worksheet variable

What I want to achieve:
I want to assign copy of a worksheet to variable, for later use.
What I tried and results
First : The code below works fine. Something like this I would like to achieve, but using worksheet.copy.
Sub DuplicateSheetRenameFirst()
Dim wsDuplicate As Worksheet
Set wsDuplicate = Worksheets.Add
wsDuplicate.Name = "Duplicate"
End Sub
Second : Using the copy method, creates a worksheet in current workbook, but generates a Runtime error 424 - Object required.
Sub DuplicateSheetRenameSecond()
Dim wsDuplicate As Worksheet
Set wsDuplicate = Worksheets("Sheet1").Copy(after:=Worksheets(Worksheets.Count))
'above line : runtime error 424 object required, but the sheet is created
wsDuplicate.Name = "Duplicate"
End Sub
Third : Creates a worksheet in new workbook (so creates book, then sheet), but still generates the same Runtime error 424 - Object required.
Sub DuplicateSheetRenameThird()
Dim wsDuplicate As Worksheet
Set wsDuplicate = Worksheets("Sheet1").Copy
'above line : runtime error 424 object required, but the sheet is created in new workbook
wsDuplicate.Name = "Duplicate"
End Sub
Workaround : I can modify any of the second or third way to at first copy the sheet and then set the variable to activesheet, but I was wandering if there is a one step way of doing this. I'm not sure if this would work all the time, since the activesheet may not be the one just copied, maybe.
The Question:
Is there a simple (one step) way to store the copy of a worksheet in a variable? Preferably without errors or without filtering the error with error handler.
This is maybe ok?
Sub copySheet()
Dim ws As Excel.Worksheet
Excel.ThisWorkbook.Sheets("Sheet1").Copy After:=Sheets(1)
Set ws = Excel.ThisWorkbook.ActiveSheet
End Sub
It is unfortunate that in this case you need to use an Active... object. Generally it is good practice to avoid Active... objects.
You cannot do this though as the method .copy is not returning an object of the worksheet class:
Sub copySheet()
Dim ws As Excel.Worksheet
Set ws = Excel.ThisWorkbook.Sheets("Sheet1").Copy(After:=Sheets(1))
End Sub
Some further explanation is in this previous post:
Why does Worksheet.Copy not return a reference to the new workbook created
In MSDN it is not altogether obvious that the method returns nothing:
https://msdn.microsoft.com/EN-US/library/office/ff837784.aspx
...but in your friend Excel's Object Explorer it is more obvious. If it returned a worksheet object then by the arrow would read:
Sub Copy([Before], [After]) as Worksheet

How to add a new spreadsheet with VBA-Code, using VBA

I am creating a macro and part of the macros function is to make VBA create a new spreadsheet. Because of the nature of distribution the name will change. I need to add code to this spreadsheet. Is there anyway I can do this?
Jook has already explained how it works. I will take it a step further.
The syntax of adding a worksheet is
expression.Add(Before, After, Count, Type)
If you check inbuilt Excel's help then you can see what Before, After, Count, Type stands for
FROM EXCEL"S HELP
Parameters (All 4 parameters are Optional)
Before - An object that specifies the sheet before which the new sheet is added.
After - An object that specifies the sheet after which the new sheet is added.
Count - The number of sheets to be added. The default value is one.
Type - Specifies the sheet type. Can be one of the following XlSheetType constants: xlWorksheet, xlChart, xlExcel4MacroSheet, or xlExcel4IntlMacroSheet. If you are inserting a sheet based on an existing template, specify the path to the template. The default value is xlWorksheet.
Once the sheet is created then you need to use .insertlines to create the relevant procedure and to also embed the code that you want to run.
NOTE - IMP: If you want the code to embed code in the VBA project, you need to ensure that you have "Trust Access to the VBA Project Object Model" selected. See snapshot.
Here is an example where I am creating a sheet and then embedding a Worksheet_SelectionChange Code which will display a message "Hello World"
CODE - TRIED AND TESTED
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim nLines As Long
Dim VBP As Object, VBC As Object, CM As Object
Dim strProcName As String
Set ws = Worksheets.Add
Set VBP = ThisWorkbook.VBProject
Set VBC = VBP.VBComponents(ws.Name)
Set CM = VBC.CodeModule
strProcName = "Worksheet_SelectionChange"
With ThisWorkbook.VBProject.VBComponents( _
ThisWorkbook.Worksheets(ws.Name).CodeName).CodeModule
.InsertLines Line:=.CreateEventProc("SelectionChange", "Worksheet") + 1, _
String:=vbCrLf & _
" Msgbox ""Hello World!"""
End With
End Sub
This is how the new sheet code area looks once you run the above code.
the following code will add you a spreadsheet.
Public Sub Workbook_Add()
Dim wks As Worksheet
Set wks = ThisWorkbook.Worksheets.Add(, , 1, xlWorksheet)
With wks
'set codename of wks
ThisWorkbook.VBProject.VBComponents(.CodeName).Name = "tblWhatever"
'set tablename of wks
.Name = "whatever"
'add code (untested demo)
'ThisWorkbook.VBProject.VBComponents(.CodeName).CodeModule.InsertLines 1, "Option Explicit"
'add code (as of example from excel-help)
'Application.VBE.CodePanes(1).CodeModule.InsertLines 1, "Option Explicit"
End With
End Sub
If you need to add VBA-Code to this specific spreadsheet, you should further inspect the VBProject object - look for CodeModule and then i.e. InsertLines.
A further hint for you - I would try to use the CodeNames of your tables. It is less likely to be changed - BUT it might be not that comfortable to use in your code at first. I had to get used to it, but for me it has many advantages against using a tables name.
Hope this helps ;)
The default .Add method adds a sheet at the start of the list. Often you want to add it at the end before adding the code lines, as explained by Siddarth Rout. To do that anywhere you can use:
ActiveWorkbook.Worksheets.ADD After:=ActiveWorkbook.Sheets(ActiveWorkbook.Worksheets.Count)
It is easier to read if you have defined and set WB:
Dim WB as Excel.workbook
Set WB = ActiveWorkbook
WB.Sheets.ADD After:=WB.Sheets(WB.Sheets.Count)
Set VBC = ActiveSheet 'If using in Siddarth Rout's code above
Sheets and Worksheets are interchangeable, as illustrated.