VBA (Upper) Type Mismatch Error - vba

I am running a bit of VBA to switch an entire Excel worksheet to upper case.
However it trips over and gives a Type Mismatch error and fails half way through.
Sub MyUpperCase()
Application.ScreenUpdating = False
Dim cell As Range
For Each cell In Range("$A$1:" & Range("$A$1").SpecialCells(xlLastCell).Address)
If Len(cell) > 0 Then cell = UCase(cell)
Next cell
Application.ScreenUpdating = True
End Sub
I'm assuming it is tripping over a specific cell however there are hundreds of lines. Is there a way to get it to skip errors

If you want to convert all cells to upper case text (including formulas):
Sub MyUpperCase()
Application.ScreenUpdating = False
Dim cell As Range, v As String
For Each cell In Range("$A$1:" & Range("$A$1").SpecialCells(xlLastCell).Address)
v = cell.Text
If Len(v) > 0 Then cell.Value = UCase(v)
Next cell
Application.ScreenUpdating = True
End Sub
Be aware that all formulas not returning Null will also be converted to Text.

To see what cell (or cells) is the problem, you could try:
On Error Resume Next 'to enable in-line error-catching
For Each cell In Range("$A$1:" & Range("$A$1").SpecialCells(xlLastCell).Address)
If Len(cell) > 0 Then cell = UCase(cell)
If Err.Number > 0 Then
Debug.Print cell.Address
Err.Clear
End If
Next cell
On Error GoTo 0 'Turn off On Error Resume Next
On Error Resume Next is often abused, especially by new VBA programmers. Don't turn it on at the beginning of a sub and never turn it off and never check Err.Number. I find it a very good idea to think of it having a specific scope, and emphasizing that scope by indenting the statements in it, as I have done above. #MacroMan raises a good point that errors shouldn't be simply ignored (which is what happens if you abuse this construct).

Add the following error trapping in the middle of your code:
On Error Resume Next
If Len(cell) > 0 Then cell = UCase(cell)
If Err.Number <> 0 Then
MsgBox "Cell " & cell.Address & " has an error !"
End If
On Error GoTo 0
Note: Your code is fine with Numeric values, it's the #NA and #DIV/0 that's raising the errors when running your original code.

Related

Compile error: label not defined

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.

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 know if cell exist

I searched but could not find the way to do this.
I want to know if this is possible
if ActiveDocument.Range.Tables(1).Cell(i, 2) present
do some stuff
end if
This can work:
Dim mycell as cell
On Error Resume Next 'If an error happens after this point, just move on like nothing happened
Set mycell = ActiveDocument.Range.Tables(1).Cell(1, 1) 'try grabbing a cell in the table
On Error GoTo 0 'If an error happens after this point, do the normal Error message thingy
If mycell Is Nothing Then 'check if we have managed to grab anything
MsgBox "no cell"
Else
MsgBox "got cell"
End If
If you want to test for multiple cells in a loop, don't forget to set mycell=nothing before trying again.
(Instead of the mycell variable way, you could also check to see if an error has happened when you tried to use the cell. You could use If err > 0 Then to do that. But that way is a bit more unstable in my experience.)
Specific answer to OP's specific question:
If .Find.Found Then 'this is custom text search, has nothing to do with specified cell exist.
Set testcell = Nothing
On Error Resume Next
Set testcell = tbl.Cell(i, 6)
On Error GoTo 0
If Not testcell Is Nothing Then
tbl.Cell(i, 2).Merge MergeTo:=tbl.Cell(i, 3)
End If
End If
This means:
If your .find does whatever... then
Try grabbing the cell in question (the 4 rows: Set...Nothing, On error..., Set..., On Error...)
If we could grab the cell, then merge cells
Read up a bit on the error handling in VBA, the On Error statement. In VBA, there is no Try...Catch. This is what we can do instead.
I hope this clears it up.
For reference, I'll post a full code here:
Sub test()
Dim tbl As Table
Dim testcell As Cell
Set tbl = ActiveDocument.Range.Tables(1)
For i = 1 To 6
Set testcell = Nothing
On Error Resume Next
Set testcell = tbl.Cell(i, 6)
On Error GoTo 0
If Not testcell Is Nothing Then
tbl.Cell(i, 2).Merge MergeTo:=tbl.Cell(i, 3)
End If
Next i
End Sub
Posting the solution as a function for reference...
Function cellExists(t As table, i As Integer, j As Integer) As Boolean
On Error Resume Next
Dim c As cell
Set c = t.cell(i, j)
On Error GoTo 0
cellExists = Not c Is Nothing
End Function

VBA: No CellTypeBlanks available

I've got a spreadsheet I'm working on where sometimes my wRange has no blank cells left to use. In this case I want to jump to the end of the macro. I'm currently using this:
On Error Resume Next
wRange.SpecialCells(xlCellTypeBlanks) = "0"
On Error GoTo -1
to deal with the error I get if there are no blank cells left after my other changes.
I'm planning on using a flag like
If wRange.SpecialCells(xlCellTypeBlanks) is Blank Then
Boolean emptycells = FALSE
End If
Is there a better way to go about doing this? And if not, how do I go about coding this?
Thank you.
You can do it like that:
Dim blanks As Range
On Error Resume Next
Set blanks = wRange.SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If blanks Is Nothing Then
emptyCells = False
End If
mielk's answer is perfectly fine, but from reading your question it sounds like the only reason you are even using the emptyCells boolean is to go to the end of macro. So I would not even bother with it and would instead modify mielk's answer in the following way:
Whateveryoursubsnameis()
Dim rngBlanks As Range
On Error Resume Next
Set rngBlanks = wRange.SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If blanks Is Nothing Then
GoTo MacroEnd
End If
(rest of your macro's code)
MacroEnd:
End Sub

Range & If Statement using multiple sheets

I have several Sheets involved but I'll have Sheet 2 Active. When I'm on "Sheet 2" I need to know when cell ("C14") becomes active with an IF statement I'm guessing. Once it becomes active, I then need to know if the string in cell ("B2") on Sheet 1 = "Fighter" then I want to insert "some wording regarding the fighter here" in cell ("C14") on Sheet 2. IF it's not "Fighter"then is it "Mage"? If so then insert "some wording regarding the mage here".
This is short hand for example.
if cell C14 on Sheet 2 is active then
check cell B2 on Sheet1. If the text = "Fighter"? Then
insert "You are brave and use a sword" into cell C14 Sheet2
if it's not equal to Fighter then is it = "Mage"? Then
insert "You cast spells" in cell C14 sheet2
etc..
I need to know how to code this in VBA. I've spent hours searching and trying various code but can't seem to get it right. Thanks ahead of time for your help.
Try something like this:
'The way you check which cell is active is by using an
'Event like this one. This goes into the Sheet2 code module
'which you can get to by right clicking on the sheet's tab and
'selecting View Code.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim rng_Source As Excel.Range
Dim rng_Target As Excel.Range
On Error GoTo ErrorHandler
'Setting the cells that you're interested in as
'ranges will help minimise typo errors.
Set rng_Target = ThisWorkbook.Sheets("Sheet2").Range("C14")
Set rng_Source = ThisWorkbook.Sheets("Sheet1").Range("B2")
'Target is a range that specifies the new
'selection. Check its address against rng_Target
'which we defined above.
If Target.Address <> rng_Target.Address Then
Exit Sub
End If
'If you don't want case sensitivity, convert to upper case.
If UCase(rng_Source.Value) = "FIGHTER" Then
rng_Target.Value = "some wording regarding the fighter here"
ElseIf UCase(rng_Source.Value) = "MAGE" Then
rng_Target.Value = "You cast spells"
'You get the idea.
End If
ExitPoint:
On Error Resume Next
'Clean up
Set rng_Source = Nothing
Set rng_Target = Nothing
On Error GoTo 0
Exit Sub
ErrorHandler:
MsgBox "Error " & Err.Number & vbCrLf _
& Err.Description
Resume ExitPoint
End Sub
I do agree with the comments that you should always post the code that you've already tried (which you subsequently did), but this is a relatively trivial one and this just clears it out of the way and may be of use to somebody else as well in the future.
Try this ;)
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
On Error GoTo errH
Dim rng1 As Range
Set rng1 = ThisWorkbook.Worksheets(1).Range("B2")
If Not Intersect(Target, Me.Range("C14")) Is Nothing Then
Application.EnableEvents = False
If rng1.Value2 = "Mage" Then
Target.Value = "OMG This is MAGE!!! Run run run away!!!"
ElseIf rng1.Value2 = "Fighter" Then
Target.Value = "Fighter? :/ Was hoping for something better"
MsgBox "Fighter? :/ Was hoping for something better"
rng1.Value2 = "Mage"
Target.Value = "Mage. Now This is better ;)"
Else
Target.Value = "No, we haven't discussed it."
End If
Application.EnableEvents = True
End If
Exit Sub
errH:
MsgBox ("Error number: " & Err.Number & "Description: " & Err.Description)
Application.EnableEvents = True
End Sub