Creating a loop with an IF variable -- Run-time error '1004' - excel

I'm trying to create a loop based on data in Column L. Data in Column L is formatted as Text and contains dates. If a match is found, the entire Row has to be highlighted in yellow.
Sub Forn()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets(1)
Dim strSearchText As String
strSearchText = Format(DateAdd("m", 2, Now()), "yyyymm")
Dim rngSearchArea As Range
Set rngSearchArea = ws.Range(Range("L10"), ws.Range("L" & ws.Range("L:L").Cells.Count).End(xlUp))
Dim strFirstFound As String
Dim rngCurrentFound As Range
Set rngCurrentFound = ws.Range("L10")
Set rngCurrentFound = rngSearchArea.Find(What:=strSearchText, After:=rngCurrentFound, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, _
MatchCase:=True, SearchFormat:=False)
If rngCurrentFound Is Nothing Then
MsgBox "INGEN TREFF"
Exit Sub
End If
rngCurrentFound.Resize(1, 16).Offset(0, -11).Interior.ColorIndex = 6
strFirstFound = rngCurrentFound.Address
Dim rngSource As Range
Dim rngNextFound As Range
Do
Set rngNextFound = rngSearchArea.FindNext(rngCurrentFound)
If rngNextFound.Row > rngCurrentFound.Row Then
rngCurrentFound.Resize(1, 16).Offset(0, -11).Interior.ColorIndex = 6
Else
Set rngSource = ws.Range(rngCurrentFound, ws.UsedRange.Cells(ws.UsedRange.Cells.Count))
End If
Set rngCurrentFound = rngSearchArea.FindNext(rngCurrentFound)
Loop While rngCurrentFound.Address <> strFirstFound
End Sub
I'm getting Run-time error '1004':
Method 'Range' of object '_Worksheet' failed.
This exact same code worked for me yesterday and I'm at a complete loss as to what needs to be changed here.
UPD: the error is caused by launching the Macro from PERSONAL.XLSB --
Set ws = ThisWorkbook.Worksheets(1)
no longer works as needed.

Using ThisWorkbook in a macro tells VBA that you want to access the workbook where the code is stored. If you move your code to the Personal.xlsb, it will access Personal.xlsb and it's sheets - and that's probably not what you want.
You put a macro in the Personal usually to have it available all the time, e.g. via a Keyboard shortcut.
If you want the code to work on the currently visible workbook, replace ThisWorkbook simply by ActiveWorkbook - but you need to ensure that it makes sense to run the macro on that workbook.
If you want to execute it always on the same workbook, it makes no sense to have it in the personal - just keep it in the workbook itself.
If you want to select the workbook first, add a fileopen-dialog to your code, open the workbook using Workbooks.Open and use the workbook-reference returned by the open-command.

Related

VBA Code runs properly but Run-time error '1004' still pops up

I'm learning VBA and I'm trying to create a workbook wherein in one sheet (sheet2) it would do the calculation then once the calculation is finished the items in sheet2, I would be able to press a commandbutton with the macro of copying the cells in the other sheet (sheet1). I am successful so far in copying over the data however every time the commandbutton is pressed, the error message
'Run-time error'1004': Application-defined or object-defined error'
would pop up. When the debug option is selected it points to line 4 & 5. I searched all over the internet regarding this issue and I haven't stumbled upon any situation like this. I've followed this https://www.youtube.com/watch?v=Z62yORhPr3Q and it's 5th method I'm running with. The code that I have is:
Private Sub CommandButton1_Click()
Dim Part As Range
For Each Part In Range(Range("Q4"), Range("Q4").End(xlDown))
Sheets("VStock").Range(Part.Value).Value = _
Sheets("Calc").Range(Part.Offset(0, 1).Value).Value
Next Part
End Sub
Any help would be appreciated
Thanks!
Suggestion not to loop the entire column and set the Ranges before the main task of "copy/paste".
In your case the ranges are set up incorrectly
Sheets("VStock").Range(Part.Value).Value = _
Sheets("Calc").Range(Part.Offset(0, 1).Value).Value
.Range should Look into the location of cells, example: .Range("Q4:Q144").Value
in your case, Range ends up with .Range(*theValue*).Value
Correct code Example:
Private Sub CommandButton1_Click()
Dim ws1 As Worksheet: Set ws1 = Sheets("Calc")
Dim ws2 As Worksheet: Set ws2 = Sheets("VStock")
Dim SourceRange, dbRange As Range
Dim lRow as Long
lRow = ws1.Range("Q" & ws1.Rows.Count).End(xlUp).Row
If lRow <= 4 Then
MsgBox ("No data to copy")
Exit Sub
End If
Set SourceRange = ws1.Range("Q4:Q" & lRow) ' Calc
Set dbRange = ws2.Range("Q4:Q" & lRow) ' VStock
dbRange.Value = SourceRange.Offset(0, 1).Value
End Sub

Match function in VBA gives compile error

I have a work book with two Worksheets. '2020-2021' Worksheet has some unique numbers in its Column D. Result of Match should come to 'Arrears' Worksheet. C2 cell in 'Arrears' has a number which I want to Match in Column D in 2020-2021. Entered the following code.
Range("C3").Value = WorksheetFunction.Match(Range("c2").value,Range('2020-2021'!d11:d206),0)
Gives Compile Error
Qualify (Use Variables)
If you feel like learning something, study the first two versions.
If not, pick one of the solutions in the third version.
Qualify; what does that even mean?
Related to this case, e.g. Range("C3") is not qualified. We don't know for sure where it refers to (belongs). It is short for ActiveSheet.Range("C3") which means that if we select Sheet1 it will refer to C3 on Sheet1, if we select Sheet2 it will refer to C3 on Sheet2 etc.
But if we use Worksheets("Sheet1").Range("C3") we have qualified the range and which ever worksheet we select, it will always refer to C3 on worksheet Sheet1 (Not 100% true because...).
Similarly to the range case, we are saying that the worksheet in Worksheets("Sheet1").Range("C3") is not qualified. The expression is actually short for ActiveWorkbook.Worksheets("Sheet1").Range("C3").
To qualify it, we can do Workbooks("Test.xlsm").Worksheets("Sheet1").Range("C3"). Now we are saying that the range is fully qualified, as is the worksheet. This might often seem unpractical, so ThisWorkbook 'comes to the rescue'.
If you need to refer to the workbook containing this code, just use ThisWorkbook. You don't care if it is called Test.xlsm or Last Years Official Inventory Report whatever.xlsm... just use ThisWorkbook.
Related to our case, we can then fully qualify our range using:
ThisWorkbook.Worksheets("Arrears").Range("C3")
Application.Match vs WorksheetFunction.Match
Sub qualifyAP()
' Define workbook.
Dim wb As Workbook
Set wb = ThisWorkbook ' The workbook containing this code.
' Define worksheets.
Dim src As Worksheet
Set src = wb.Worksheets("2020-2021")
Dim tgt As Worksheet
Set tgt = wb.Worksheets("Arrears")
' Use the Application version of Match.
Dim Result As Variant ' can hold any datatype incl. error value.
Result = Application.Match(tgt.Range("C2").Value, src.Range("D11:D206"), 0)
If Not IsError(Result) Then
tgt.Range("C3").Value = Result
'MsgBox "Data found and transferred."
Else
MsgBox "Data not found. Nothing done."
End If
End Sub
Sub qualifyWF()
' Define workbook.
Dim wb As Workbook
Set wb = ThisWorkbook ' The workbook containing this code.
' Define worksheets.
Dim src As Worksheet
Set src = wb.Worksheets("2020-2021")
Dim tgt As Worksheet
Set tgt = wb.Worksheets("Arrears")
' Use the WorksheetFunction version of Match.
On Error Resume Next
tgt.Range("C3").Value = WorksheetFunction.Match(tgt.Range("C2").Value, _
src.Range("D11:D206"), _
0)
If Err.Number = 0 Then
'MsgBox "Data found and transferred."
Else
MsgBox "Data not found. Nothing done."
End If
On Error GoTo 0
End Sub
Sub qualifyQF()
Worksheets("Arrears").Range("C3").Value = WorksheetFunction _
.Match(Worksheets("Arrears").Range("C2").Value, _
Worksheets("2020-2021").Range("D11:D206"), _
0)
' or:
With Worksheets("Arrears")
.Range("C3").Value = WorksheetFunction _
.Match(.Range("C2").Value, _
Worksheets("2020-2021").Range("D11:D206"), _
0)
End With
' or even:
With Worksheets("Arrears").Range("C3")
.Value = WorksheetFunction _
.Match(.Offset(-1).Value, _
Worksheets("2020-2021").Range("D11:D206"), _
0)
End With
End Sub

Range.Find Function

Using the Range.Find Method doesn't work for the file name.
The Range DocPresent is always "Nothing"
I am processing multiple Excel Sheets and want to track which ones I already processed. To make sure I don't process the Sheet again when I rerun the Macro
Dim wbname1 As String
wbname1 = ActiveWorkbook.Name
Range("A1").End(xlDown).Offset(1, 0) = wbname1
Dim DocPresent As Range
Set DocPresent = Range("A1:A1000").Find(What:=wbname1)
I am expecting the range to return the correct range if it finds the respective cell.
Note that Range("A1").End(xlDown) might end up below A1000 but your .Find is only looking before A1000.
So either use the whole column Range("A:A").Find… or find the last used cell Range("A1", Cells(Rows.Count, "A").End(xlUp)).Find…
And specify a workbook and worksheet for all your ranges!
Dim wbname1 As String
wbname1 = ActiveWorkbook.Name
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("MySheet")
ws.Range("A1").End(xlDown).Offset(1, 0) = wbname1
Dim DocPresent As Range
Set DocPresent = ws.Range("A1", ws.Cells(ws.Rows.Count, "A").End(xlUp)).Find(What:=wbname1, LookAt:=xlWhole)
Note that ThisWorkbook points to the workbook this code is running in. But ActiveWorkbook points to the workbook that has focus (is on top) at the moment the code is running. ActiveWorkbook can easily change by a user's click but ThisWorkbook is always the same.
Also note that the Range.Find method has a LookAt parameter that should always be specified xlWhole or xlPart. Otherwise VBA uses the one that was used last either by VBA or by user interface. So you never know which one VBA is going to use, therefore always specify it.
According to the comment below you should check if your Find method was successfull before you use DocPresent so you don't run into an error:
If Not DocPresent Is Nothing Then
'do your stuff using DocPresent
Else
MsgBox "'" & wbname1 & "' was not found.", vbCritical
Exit Sub
End If

specific columns copy from one excel to another excel based on column header name

I want to copy the columns from one excel to another excel based on the column header name. i have two excel file called "Source" and "Destination" as shown below in the image:
Source.xls
Destination.xls
i wanted to copy all the columns from source file and paste into to in the destination excel file based on the header file i.e to the yellow shaded columns .Because there are some formula defined in the destination file as shown and it calculates the values from the source file column.
I have tried the basic copy and paste columns. Though it works , it requires lot of manual interventions.
sample piece of code:
src.Range("A:A").Copy Destination:=trg.Range("A1")
src.Range("B:B").Copy Destination:=trg.Range("E1")
src.Range("C:C").Copy Destination:=trg.Range("I1")
i would expect something like to lookup the column header name from source file and destination file and if the names are matched , then it will paste the whole columns in the destination file. As i am very new to excel , can anyone help to solve this through VBA scripts
Please try this.
Option Explicit
Public Sub SpecificColCopy()
Dim Wbs As Workbook
Dim Wbd As Workbook
Dim Wbm As Workbook
Dim RealLastRow As Long
Dim SourceCol As Long
Dim Cell As Range
Dim sourceWS As Worksheet, targetWS As Worksheet
Dim MacroWS As Worksheet
Dim SourceHeaderRow As Long: SourceHeaderRow = 1
Dim SourceCell As Range
Dim TargetHeader As Range
Application.DisplayAlerts = False
On Error Resume Next
Set Wbm = ThisWorkbook
Set MacroWS = Wbm.Worksheets("Sheet1")
Set Wbs = Workbooks.Open("C:\mydirb\Source.xlsx") 'workbook needs to be closed state
Set sourceWS = Wbs.Worksheets("Sheet1")
Set Wbd = Workbooks.Open("C:\mydirb\Destination.xlsx") ''workbook needs to be closed state
Set targetWS = Wbd.Worksheets("Sheet1")
Set TargetHeader = targetWS.Range("A1:N1")
On Error GoTo 0
sourceWS.Activate
For Each Cell In TargetHeader
If Cell.Value <> "" Then
Set SourceCell = Rows(SourceHeaderRow).Find _
(Cell.Value, LookIn:=xlValues, LookAt:=xlWhole)
If Not SourceCell Is Nothing Then
SourceCol = SourceCell.Column
RealLastRow = Columns(SourceCol).Find("*", LookIn:=xlValues, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
If RealLastRow > SourceHeaderRow Then
Range(Cells(SourceHeaderRow + 1, SourceCol), Cells(RealLastRow, _
SourceCol)).Copy
targetWS.Cells(2, Cell.Column).PasteSpecial xlPasteValues
End If
End If
End If
Next
MacroWS.Activate
Wbs.Save
Wbd.Save
Wbs.Close
Wbd.Close
Application.DisplayAlerts = True
End Sub
[![Souce_destination][1]][1]

Making a loop to execute same code multiple times

I need some help to create a loop from my code
The code has two main functions:
Copy and paste general data to another workbook
Copy and paste employee data to another workbook
I want to make a loop of my code (code is shown below). I can make this code 15 times and it will work but I think that a loop is better. I don't have any experience with loops.
So when I press a button on my sheet it copies the general data and opens a other workbook, then it goes back tot he main workbook and copies the employee data and paste them in the other workbook.
The workbook that needs to be opened is found in range F82:F96, so first F82 then F83... and so on, until it reaches F96 and then the code must stop.
The general data is always found in row 15 & 16.
The employee data is found with the same string as the workbook that must be opened. The row after the string must me copied and paste in the other workbook. So for example (G82:DI82).
What I have
I made a code that works for 1 employee in cell(F82) the code below opens the workbook of this employee then copies the general data then find the right column and row to paste. Then I paste the data then it goes back tot he main workbook and copies the data which belongs to he employee (G82:DI82) an paste this data in the other workbook. Then it saves closes the opened workbook. The main workbook stays open.
What I expect
I need a loop to repeat the code. So first the employee which is in (F82) then the employee which in (F83) and so on.
The code:
Private Sub mUpdate_Click()
Dim General As Range
Dim employe1hours As Range
Dim employepaste As Range
Dim employepastehours As Range
Dim CurrentweekColumn As Range
Dim Currentweekpaste As Range
Dim employepath As String
Dim employe1 As String
Dim rowstr As String
Dim Foundrow As Range
Dim Currentweek As String
employepath = "J:\Planning\Medewerkers\"
Currentweek = Range("B7").Value
employe1 = Range("F82").Value
rowstr = Range("A2").Value
With ActiveWorkbook.Sheets("Planning").Range("14:14")
Set CurrentweekColumn = .find(what:=Currentweek, LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
End With
Set General = ActiveWorkbook.Sheets("Planning").Range(Cells(15, CurrentweekColumn.Column), Cells(16, CurrentweekColumn.Offset(0, 106).Column))
General.Copy
Workbooks.Open (employepath & employe1 & ".xlsm")
With ActiveWorkbook.Sheets("Blad1").Range("14:14")
Set Currentweekpaste = .find(what:=Currentweek, LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
End With
With ActiveWorkbook.Sheets("Blad1").Range("A:A")
Set Foundrow = .find(what:=rowstr, LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
End With
Set employepaste = ActiveWorkbook.Sheets("Blad1").Range(Cells(Foundrow.Row, Currentweekpaste.Column).Address)
employepaste.PasteSpecial Paste:=xlPasteFormats
employepaste.PasteSpecial Paste:=xlPasteValues
Workbooks(rowstr & ".xlsm").Activate
Set employe1hours = ActiveWorkbook.Sheets("Planning").Range(Cells(82, CurrentweekColumn.Column), Cells(82, CurrentweekColumn.Offset(0, 106).Column))
employe1hours.Copy
Workbooks(employe1 & ".xlsm").Activate
Set employepastehours = ActiveWorkbook.Sheets("Blad1").Range(Cells(Foundrow.Offset(2, 0).Row, Currentweekpaste.Column).Address)
employepastehours.PasteSpecial Paste:=xlPasteValues
ActiveWorkbook.Save
ActiveWorkbook.Close
Since we cannot do all the work for you, this should give you an idea how the loop could look like:
Option Explicit
Public Sub MyUpdateProcedure()
Dim Employees As Range 'define the range of employees
Set Employees = ThisWorkbook.Worksheets("SheetName").Range("F82:F96")
Dim CurrentWorkbook As Workbook
Const EmployePath As String = "J:\Planning\Medewerkers\"
Dim Employe As Range
For Each Employe In Employees 'loop throug all employees
'open the workbook
Set CurrentWorkbook = Workbooks.Open(EmployePath & Employe.Value & ".xlsm")
With CurrentWorkbook.Sheets("Blad1")
'your stuff here
End With
'your other stuff here
'save and close workbook
CurrentWorkbook.Close SaveChanges:=True
Next Employe
End Sub
Note that you have to avoid ActiveWorkbook and instead set the opened workbook into a variable like Set CurrentWorkbook = Workbooks.Open that you can easily use then.
Also make sure that all your Range(…) objects have a workbook/worksheet specified like ThisWorkbook.Worksheets("SheetName").Range(…) otherwise Excel guesses which worksheet you mean.
Also be aware of errors:
Set CurrentWorkbook = Workbooks.Open(EmployePath & Employe.Value & ".xlsm")
will throw an error if the workbook does not exist so you might want to catch it:
'open the workbook
Set CurrentWorkbook = Nothing 'initialize since we are in a loop!
On Error Resume Next 'next line throws an error if file not found so catch it
Set CurrentWorkbook = Workbooks.Open(EmployePath & Employe.Value & ".xlsm")
On Error GoTo 0 'always re-activate error reporting!
If Not CurrentWorkbook Is Nothing Then
'file for employee was found
With CurrentWorkbook.Sheets("Blad1")
'your stuff here
End With
'your other stuff here
'save and close workbook
CurrentWorkbook.Close SaveChanges:=True
Else
'file for employee was not found
End If

Resources