Compile error: label not defined - vba

I have a code that looks for something from the master sheet in column D such as "1x Daily" or "2x Month" (as well as others). If the cell matches a Sheet name, it gets pasted into that sheet. The problem is each row from the Master sheet is unique and therefore cannot be repeated on each sheet. Every time I run the code, it adds the rows again, so I end up with something like this
Coubourn, Stephen|A|201|Q4hours
Eudy, Donna |A|202|Q4hours
Potts, Betty |A|203|Q4hours
Coubourn, Stephen|A|201|Q4hours
Eudy, Donna |A|202|Q4hours
Potts, Betty |A|203|Q4hours
Coubourn, Stephen|A|201|Q4hours
Eudy, Donna |A|202|Q4hours
Potts, Betty |A|203|Q4hours
Below is what I have so far for this code I am trying to make, however, it isnt working. Im receiving the error message "Compile error, label not defined" on the line that says "On Error GoTo SetFirst"
Dim cell As Range
Dim cmt As Comment
Dim bolFound As Boolean
Dim sheetNames() As String
Dim lngItem As Long, lngLastRow As Long
Dim sht As Worksheet, shtMaster As Worksheet
Dim MatchRow As Variant
Set shtMaster = ThisWorkbook.Worksheets("Master Vitals Data")
ReDim sheetNames(0)
For Each sht In ThisWorkbook.Worksheets
If sht.Name <> shtMaster.Name Then
sheetNames(UBound(sheetNames)) = sht.Name
ReDim Preserve sheetNames(UBound(sheetNames) + 1)
End If
Next sht
ReDim Preserve sheetNames(UBound(sheetNames) - 1)
For Each cell In shtMaster.Range("D1:D" & shtMaster.Cells(shtMaster.Rows.Count, "D").End(xlUp).Row)
bolFound = False
MatchRow = Application.Match(cell.Offset(, -3).Value, sht.Range("A:A"), 0)
If Not IsError(MatchRow) Then
shtMaster.Rows(cell.Row).EntireRow.Copy Destination:=sht.Cells(MatchRow, 1)
Else
On Error GoTo SetFirst
lngLastRow = sht.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row + 1
On Error GoTo 0
shtMaster.Rows(cell.Row).EntireRow.Copy Destination:=sht.Cells(lngLastRow, 1)
End If
If bolFound = False Then
For Each cmt In shtMaster.Comments
If cmt.Parent.Address = cell.Address Then cmt.Delete
Next cmt
cell.AddComment "no sheet found for this row"
ActiveSheet.EnableCalculation = False
ActiveSheet.EnableCalculation = True
End If
Set sht = Nothing
Next
End Sub

On Error GoTo SetFirst
This instruction tells the VBA runtime, in case of an error, to jump straight to the SetFirst subroutine to handle the error.
When you compile the code, VBA sees that there's a conditional jump to that SetFirst label, but there's no such label to jump to, so VBA can't resolve SetFirst and compilation fails.
Not sure what your intent is, but things would typically look something like this:
Exit Sub
SetFirst: '<<<<<<<< that's your line label
Debug.Print "Error " & Err.Number & ": " & Err.Description
Err.Clear
'comment-out or remove before distributing:
Stop
Resume 'step through (F8) here to jump back to error-causing instruction
End Sub
Line labels / subroutines are locally scoped, meaning you can't GoTo-jump to a line label that's located in another procedure. If you have SetFirst in another procedure and intend to jump there in case of an error, you have some serious spaghettification in process.

Related

VBA Code to Autofill

Have a column H with alphanumeric characters. Some cells in this column have the content (RAM) followed by 5 digits starting from 00000 to 99999.
If cell H219 has the content (RAM) 23596 then i have to fill cell A219 with a comment "completed".
This has to be done for all cells with the content "(RAM) followed by 5 digits"
Sub Macro16_B()
' ' Macro16_B Macro ' '
intRowCount = Worksheets("Reconciliation").UsedRange.Rows.Count
For i = 11 To intRowCount
If InStr(Range("H" & i).Value, "(RAM 00000-99999") Then
Range("A" & i).Value = "Completed"
End If
Next i
End Sub
A non-VBA answer could be (if the cell doesn't have extra text other than (RAM) & 5 numbers):
=IFERROR(IF(LEN(VALUE(TRIM(SUBSTITUTE(H1,"(RAM)",""))))=5,"completed",""),"")
My VBA answer would be:
Sub Test()
Dim rLastCell As Range
Dim rCell As Range
With Worksheets("Reconciliation")
Set rLastCell = .Columns(8).Find("*", , , , xlByColumns, xlPrevious)
If Not rLastCell Is Nothing Then
For Each rCell In .Range(.Cells(1, 8), rLastCell)
If rCell Like "*(RAM) #####*" Then
rCell.Offset(, -7) = "complete"
End If
Next rCell
End If
End With
End Sub
Cheers #Excelosaurus for heads up on the * would've forgotten it as well. :)
One way is to use the Like operator. The precise format of your string is not clear so you may have to amend (and assuming case insensitive). # represents a single number; the * represents zero or more characters.
Sub Macro16_B()
Dim intRowCount As Long, i As Long
' ' Macro16_B Macro ' '
intRowCount = Worksheets("Reconciliation").UsedRange.Rows.Count
For i = 11 To intRowCount
If Range("H" & i).Value Like "(RAM) #####*" Then
Range("A" & i).Value = "Completed"
End If
Next i
End Sub
Well, there are already 2 good answers, but allow me to paste my code here for good measure, the goal being to submerge #user2574 with code that can be re-used in his/her next endeavors:
Sub Macro16_B()
'In the search spec below, * stands for anything, and # for a digit.
'Remove the * characters if you expect the content to be limited to "(RAM #####)" only.
Const SEARCH_SPEC As String = "*(RAM #####)*"
Dim bScreenUpdating As Boolean
Dim bEnableEvents As Boolean
'Keep track of some settings.
bScreenUpdating = Application.ScreenUpdating
bEnableEvents = Application.EnableEvents
On Error GoTo errHandler
'Prevent Excel from updating the screen in real-time,
'and disable events to prevent unwanted side effects.
Application.ScreenUpdating = False
Application.EnableEvents = False
'Down with business...
Dim scanRange As Excel.Range
Dim cell As Excel.Range
Dim content As String
Dim ramOffset As Long
With ThisWorkbook.Worksheets("Reconciliation").Columns("H")
Set scanRange = .Worksheet.Range(.Cells(11), .Cells(.Cells.Count).End(xlUp))
End With
For Each cell In scanRange
content = CStr(cell.Value2)
If content Like SEARCH_SPEC Then
cell.EntireRow.Columns("A").Value = "Completed"
End If
Next
Recover:
On Error Resume Next
'Restore the settings as they were upon entering this sub.
Application.ScreenUpdating = bScreenUpdating
Application.EnableEvents = bEnableEvents
Exit Sub
errHandler:
MsgBox Err.Description, vbExclamation + vbOKOnly, "Error"
Resume Recover
End Sub

Excel VBA error handler not working for 'run-time error 13: type mismatch'

I am running the sub below for an Excel file containing about 10 worksheets, each containing a pivottable linked to the same data source. I have two versions of the 'Market' and 'Region' fields in my data (i.e. 'Market (SC)', 'Market (AN)', 'Region (SC)', 'Region (AN)'), and need to be able to switch between them easily. I set up the code to first bring the corresponding slicers to the front (they are superimposed so that will hide the other), then loop through each pivottable and swap the other 'Market' and 'Region' fields (maintaining the same position, etc.).
Since I'm using the property ".SourceName" to identify the field, the loop runs into an error when the "Values" PivotField is compared to my string. I've put in "On Error Goto next_fld" to tell it to skip to the next field when this occurs, but this only works for 8 of the 10 worksheets -- for the other two I get the error "Run-time error '13' Type Mismatch" and the debug screen highlights the " *** " line. If I use "On Error Resume Next", it assumes that the If statement was True and carries out a lot of unwanted actions (messes up various PivotTables).
I'm self-taught and do not have a complete understanding of the error handler, but from the resources I've come across to fix this error, the handler should be taking care of this (which it does work for 8/10 worksheets).
Here is my code:
Sub SwapMktRegFields()
Dim ws As Worksheet, shp As Shape
Dim i As Integer
Dim target As String, repl As String
target = Sheet5.Range("E3").value
'Identify current field, use other as repl(acement)
Select Case target
'AN slicers selected
Case Is = "AN"
target = "(AN)"
repl = "(SC)"
Sheet5.Range("E3").value = "SC"
'SC slicers selected
Case Is = "SC"
target = "(SC)"
repl = "(AN)"
Sheet5.Range("E3").value = "AN"
End Select
'Bring replacement slicers to front (some are in shape groups)
For Each ws In ThisWorkbook.Worksheets
For Each shp In ws.Shapes
Select Case shp.Type
Case Is = msoGroup
For i = 1 To shp.GroupItems.Count
If shp.GroupItems(i).Name Like "Market " & target & "*" Or shp.GroupItems(i).Name Like "Region " & target & "*" Then shp.GroupItems(i).ZOrder msoSendToBack
Next i
Case Else
If shp.Name Like "Market " & target & "*" Or shp.Name Like "Region " & target & "*" Then shp.ZOrder msoSendToBack
End Select
Next shp
Next ws
'Replace old PivotFields with replacement PivotFields
Dim pvt As PivotTable
Dim fld As PivotField
Dim orient As Long, pos As Long
' MY ERROR HANDLER
On Error GoTo next_fld
For Each ws In ThisWorkbook.Worksheets
For Each pvt In ws.PivotTables
For Each fld In pvt.PivotFields
' *** ERROR ON NEXT LINE WHEN fld IS 'VALUES'
If fld.SourceName = "Market " & target And fld.Orientation <> xlHidden Then
orient = fld.Orientation
pos = fld.Position
fld.Orientation = xlHidden
With pvt.PivotFields("Market " & repl)
.Orientation = orient
.Position = pos
End With
ElseIf fld.SourceName = "Region " & target And fld.Orientation <> xlHidden Then
orient = fld.Orientation
pos = fld.Position
fld.Orientation = xlHidden
With pvt.PivotFields("Region " & repl)
.Orientation = orient
.Position = pos
End With
End If
next_fld:
Next fld
Next pvt
Next ws
'A custom function to clear filters and re-apply a default
ResetPivotFilters
End Sub
The weirdest part is that the error is EXACTLY THE SAME as the other 8 sheets that work with this code. If I remove the error handler completely, I get the exact same pop-up and line highlighted for the other sheets... Any suggestions would be greatly appreciated! Thanks
Tim, this was very helpful and answered my question. I updated the end of my code to the following:
ResetPivotFilters
Exit Sub
err_handler:
Resume next_fld
End Sub
and updated my error handling enabling line to "On Error Goto err_handler". Working now. Thank you!

Subtract two ranges and clear the contents from result

I'm trying to subtract RangeA - RangeA+offset to get a new range. After this i need to clear all the values within it. My problem is that the variable columnrange is empty and i'm unable to realize what i'm doing wrong.
Dim rng1 As String
Dim rangeA As Range
Dim columnrange As Range
Dim clearrange As Range
rng1 = TextBoxA.Value
If Not IsNull(RangeboxA.Value) Then
On Error Resume Next
Set rangeA = Sheets("Plan1").Range(RangeboxA.Value)
rangeA.Select
Selection.Copy
rangeA.Offset(0, rng1).Select
ActiveSheet.Paste
columnrange = rangeA.Resize(rangeA.Rows.Count, rangeA.Columns.Count + rng1).Value
columnrange.Select
On Error Resume Next
If rangeA Is Nothing Then MsgBox "Verificar informação A"
End If
This code moves a user-defined range by a user-defined amount.
Sub RemoveRangeOverlap()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Plan1")
Dim rngOffset As Integer
Dim rangeA As Range, rangeB As Range
Dim cellRange() As String
On Error GoTo ErrHandle
rngOffset = CInt(TextBoxA.Value)
If RangeBoxA.Value <> "" Then
Set rangeA = ws.Range(RangeBoxA.Value) 'Set old range
cellRange = Split(CStr(RangeBoxA.Value), ":") 'Set start/ending cells
ReDim Preserve cellRange(LBound(cellRange) To UBound(cellRange))
Set rangeB = ws.Range(ws.Range(cellRange(0)).Offset(0, rngOffset), _
ws.Range(cellRange(1)).Offset(0, rngOffset)) 'set new range
rangeA.Copy rangeB 'copy new range
Application.CutCopyMode = xlCopy 'remove marching ants
If rangeA.Columns.Count <= rngOffset Then 'remove old values
rangeA.Clear
Else: ws.Range(ws.Range(cellRange(0)), _
ws.Range(cellRange(1)).Offset(0, rngOffset - rangeA.Columns.Count)).Clear
End If
Else: MsgBox "Missing target range input.", vbCritical, "Insufficient Data"
End If
ErrHandle:
If Err.Number = 438 Then
MsgBox "Invalid range format in range input box." & vbNewLine & _
"Proper range format example: A1:A1", vbCritical, "Error 438"
ElseIf Err.Number = 13 Then
MsgBox "Only numbers may be input as the range offset amount", _
vbCritical, "Error 13: Type Mis-match"
ElseIf Err.Number = 5 Then Exit Sub
Else: Err.Raise Err.Number
End If
End Sub
How the code works:
The first thing we have set up is information control from user-defined values. To accomplish this (which can also be done with If Then statements to prevent the errors from ever occurring in the first place) I've included an error handling line at the end. We know what 3 errors we expect to get depending on what the user provides us with.
Error 438 will occur if the user tries to set RangeBoxA's value as a non-range value.
Error 13 will occur if the user tries to input anything that isn't a number as the offset value.
Error 5 will occur because I'm bad at error handling and I'm not sure why it's occuring.. It loops my error statement at the end after whichever error is thrown (being a non-vba error).
Next we split up the range supplied by the user into two 'cells'. Using this we can apply some simple math to show where the copy destination will be as well as delete the proper amount of old range values.
If the number of columns is greater than the user supplied offset, then the new and old ranges will overlap. Some simple math will remove the old cells while preserving the new one's
If the number of columns is less than the user supplied offset, delete all of the old cells because they won't be overlapping.
Let me know if this works for you.

How to prevent dropdown from executing when source list is changed programmatically

I have an activeX dropdown form on my spreadsheet which executes code on _Change. My code modifies the dropdowns list source (adding or deleting items). Whenever this happens, the _Change is called again.
I have various workarounds, all of which were some version of changing the list source, but with no success. The reason none of this has worked is because clearing or altering the .ListFillRange actually triggers the _Change event again.
How do I prevent the _Changeevent from getting called if I want to add or delete items in the .ListFillRange
UPDATE w EnableEvents set to false:
Public Sub SetRangeForDropdown()
On Error Resume Next
Application.EnableEvents = False
'Get new List of employees from Employee sheet
Dim rng1 As Range
With wsDB_employee
Set rng1 = .Range("A2:B" & .Range("A10000").End(xlUp).Row)
End With
With wsStage
.Cells.Clear
rng1.Copy .Range(.Cells(1, 1), .Cells(rng1.Rows.Count, 2))
End With
'Set range for dropdown on employee sheet
Dim rng2 As Range
Set rng2 = wsStage.Range("A1:B" & wsStage.Range("A10000").End(xlUp).Row)
'Update employee list named formula
ActiveWorkbook.Names.Add Name:="nfEmployeeList", RefersTo:=rng2
Dim str As String
str = rng2.Parent.Name & "!" & rng2.Address 'Source path for list fill range
wsMA.cmbEmployeeSelection.ListFillRange = str
Application.EnableEvents = True
End Sub
Apperantly EnableEvents does not work for ActiveX controls.
Thank you Microsoft for making life just a little bit more complicated!
Just found this: "Application.EnableEvents=False/True ONLY applies to Sheet and Workbook Events, not ActiveX Control Events" from here enter link description here
You can disable the events in the SetRangeForDropdown and then enable them back.
So, write the following at the start:
Application.EnableEvents = False
And the following at the end:
Application.EnableEvents = true
it's always a good habit to make (nearly) sure that events handling is always brought back, like follows:
Public Sub SetRangeForDropdown()
'...your code
On Error GoTo ExitSub
Application.EnableEvents = False
wsMA.cmbEmployeeSelection.ListFillRange = rng2
'Update employee list named formula
ActiveWorkbook.Names.Add name:="nfEmployeeList", RefersTo:=rng2
ExitSub:
Application.EnableEvents = True
End Sub
Furthermore, avoid On Error Resume Next unless you really need it
I have solved the problem by adding a global variable that prevents the _Change event from firing. Here is that code:
Private Sub cmbEmployeeSelection_Change()
If bNOTRUN = False Then 'Check if ActiveX event should fire or not
modEmployeeDB.SaveEmployeeData 'Save currently selected employee data
modEmployeeDB.DBSoll_To_WorkerInfo 'Get called employee data
End If
End Sub
And this is the module as modified... note the simple Boolean variable that I added:
Public Sub SetRangeForDropdown()
On Error GoTo SetRangeForDropdown_Error
bNOTRUN = True 'Global Variable that when True prevents Active X from firing
'Get new List of employees from Employee sheet
Dim rng1 As Range
With wsDB_employee
Set rng1 = .Range("A2:B" & .Range("A10000").End(xlUp).Row)
End With
With wsStage
.Cells.Clear
rng1.Copy .Range(.Cells(1, 1), .Cells(rng1.Rows.Count, 2))
End With
'Set range for dropdown on employee sheet
Dim rng2 As Range
Set rng2 = wsStage.Range("A1:B" & wsStage.Range("A10000").End(xlUp).Row)
'Update employee list named formula
ActiveWorkbook.Names.Add Name:="nfEmployeeList", RefersTo:=rng2
Dim str As String
str = rng2.Parent.Name & "!" & rng2.Address 'Source path for list fill range
wsMA.cmbEmployeeSelection.ListFillRange = str
bNOTRUN = False
On Error GoTo 0
Exit Sub
SetRangeForDropdown_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure SetRangeForDropdown of Sub modEmployeeDB"
bNOTRUN = False
End Sub

Find value in column and change cell to left with an if statment

This VBA script should take the value in the cell A37 and check if its in the C column of another worksheet. When the number is found the column to the left should be changed to 0. If it is already 0 then a message box will inform the user and if the number does not exist another message box will inform them of this.
This is the VBA I am using to accomplish this. However, every time I try to run it there is a "compile error: Next without For"
Update This issue now is that I need to activate the cell that the fcell is in before doing an Active.cell offset
Sub Cancelled()
Dim x As Long
Dim regRange As Range
Dim fcell As Range
x = ThisWorkbook.Sheets("Welcome").Range("A37").Value
Set regRange = ThisWorkbook.Sheets("Registration").Range("C:C")
For Each fcell In regRange.Cells
If fcell.Value = x Then
ActiveCell.Offset(0, -1).Select
If ActiveCell.Value = 1 Then
ActiveCell.Value = 0
MsgBox "Changed to zero"
Exit Sub
Else
MsgBox "That registration number is already cancelled"
Exit Sub
End If
End If
Next fcell
MsgBox "That number does not exist"
End Sub
Edit for new question: No need to use Select and ActiveCell
If fcell.Value = x Then
If fcell.Offset(0,-1).Value = 1 Then
fcell.Offset(0,-1).Value = 0
...
Edit 2: A further suggestion: You could also use the Range.Find method. This will throw an error if nothing is found so you have to catch that:
On Error Resume Next 'If an error occurs, continue with the next line
Set fcell = regRange.Find(x)
On Error GoTo 0 'disable the error handler
If fcell Is Nothing Then 'If Find failed
MsgBox "That number does not exist"
Else
'do your stuff with fcell here
End If
Hope this is not too late to answer your question:
Sub Cancelled()
Dim x As Long
Dim regRange As Range
Dim fcell As Range
x = ThisWorkbook.Sheets("Welcome").Range("A7").Value
Set regRange = ThisWorkbook.Sheets("Registration").Range("C:C")
For Each fcell In regRange.Cells
If fcell.Value = x Then
If fcell.Offset(0, -1).Value = 1 Then
fcell.Offset(0, -1).Value = 0
MsgBox "Changed to zero"
Else
MsgBox "That registration number is already cancelled"
End If
Exit Sub
End If
Next fcell
MsgBox "That number does not exist"
End Sub
Instead of
Set regRange = ThisWorkbook.Sheets("Registration").Range("C:C")
its better to get the last row in Column C and then set your range as:
Dim lastRow As Long
lastRow = ThisWorkbook.Sheets("Registration").Cells(Rows.Count, "C").End(xlUp).Row
Set regRange = ThisWorkbook.Sheets("Registration").Range("C1:C" & lastRow)