Excel Error Handling for range object - excel

I'm working on an Excel user form where the user can input a range. For example, they can put in "B5" and "B20".
I'm trying to do error handling to prevent the user from putting in an incorrect range. For Example, "asdf" and "fdsa".
The following code fails:
Private Sub cmdSend_Click()
Dim beginTerm As String
Dim endTerm As String
beginTerm = TermsBegin.Text
endTerm = TermsEnd.Text
If (IsError(Worksheets("Account Information").Range(beginTerm + ":" + endTerm)) = True) Then
MsgBox "Cell Range is invalid."
Exit Sub
End If
End Sub
I also tried the following:
Private Sub cmdSend_Click()
Dim beginTerm As String
Dim endTerm As String
beginTerm = TermsBegin.Text
endTerm = TermsEnd.Text
Dim myRange As Range
myRange = Worksheets("Account Information").Range(beginTerm + ":" + endTerm)
On Error GoTo ErrHandler
On Error GoTo 0
'other code ...
ErrHandler:
MsgBox "Cell Range is invalid."
Exit Sub
End Sub
My question is how can I handle the case that it fails?
Thanks!

You have to put
On Error GoTo ErrHandler
before the line that could throw the error.

If you need to get a range from a user, I would recommend using Application.InputBox with a Type = 8. This allows the user to select a range from the worksheet.
Check this out:
http://www.ozgrid.com/VBA/inputbox.htm
Also, if you are using a userform, you can also add a command button that will call the Application.InputBox to allow a user to select a range.
Quick example:
Private Sub CommandButton1_Click()
Dim r As Range
On Error Resume Next
Set r = Application.InputBox(Prompt:= _
"Please select a range with your Mouse to be bolded.", _
Title:="SPECIFY RANGE", Type:=8)
If Not r Is Nothing Then MsgBox r.Address
On Error GoTo 0
End Sub

Related

The cancel button doesn't work for this code [duplicate]

I have the following piece of code:
dim selectRange as Range
Set selectRange = Application.InputBox("Select your range", "Hello", , , , , , 8)
When a user chooses Cancel the InputBox prompt, it returns error of Object not set.
I have tried to use a Variant variable type but I can't handle it. In case of cancelling, it returns False, meanwhile in case of selecting a range, it returns Range of InputBox.
How can I avoid this error?
This is a problem when selection a range with an inputbox. Excel returns an error before the range is returned, and it carries this error on when you press cancel.
You should therefore actively handle this error. If you don't want anything to happen when you press cancel, you can just use the code like this:
Sub SetRange()
Dim selectRange As Range
On Error Resume Next
Set selectRange = Application.InputBox("Select your range", "Hello", , , , , , 8)
Err.Clear
On Error GoTo 0
End Sub
While this question is a bit older I still want to show the proper way to do it without errors. You can do it either to it via function or with a sub.
Your main procedure is something like this:
Sub test()
Dim MyRange As Range
testSub Application.InputBox("dada", , , , , , , 8), MyRange 'doing via Sub
Set MyRange = testFunc(Application.InputBox("dada", , , , , , , 8)) ' doing via function
If MyRange Is Nothing Then
Debug.Print "The InputBox has been canceled."
Else
Debug.Print "The range " & MyRange.Address & " was selected."
End If
End Sub
the Sub-way (funny) would be:
Sub testSub(ByVal a As Variant, ByRef b As Range)
If TypeOf a Is Range Then Set b = a
End Sub
And the function would look like:
Function testFunc(ByVal a As Variant) As Range
If TypeOf a Is Range Then Set testFunc = a
End Function
Now simply use the way you like and delete the unused line.
If calling a sub or a function you do not need to Set the parameter. That said, it doesn't matter if the InputBox returns an object or not. All you need to do, is to check if the parameter is the object you want or not and then act accordingly to it.
EDIT
Another smart way is using the same behavior with a collection like this:
Sub test()
Dim MyRange As Range
Dim MyCol As New Collection
MyCol.Add Application.InputBox("dada", , , , , , , 8)
If TypeOf MyCol(1) Is Range Then Set MyRange = MyCol(1)
Set MyCol = New Collection
If MyRange Is Nothing Then
Debug.Print "The inputbox has been canceled"
Else
Debug.Print "the range " & MyRange.Address & " was selected"
End If
End Sub
If you still have any questions, just ask ;)
I'm late to the party here but this was the only place I could find that explained why I was having trouble just checking my variable for nothing. As explained in the accepted answer, the vbCancel on a range object isn't handled the same way as a string object. The error must be caught with an error handler.
I hate error handlers. So I segregated it to its own function
Private Function GetUserInputRange() As Range
'This is segregated because of how excel handles cancelling a range input
Dim userAnswer As Range
On Error GoTo inputerror
Set userAnswer = Application.InputBox("Please select a single column to parse", "Column Parser", Type:=8)
Set GetUserInputRange = userAnswer
Exit Function
inputerror:
Set GetUserInputRange = Nothing
End Function
Now in my main sub I can
dim someRange as range
set someRange = GetUserInputRange
if someRange is Nothing Then Exit Sub
Anyhow this is not the same as the accepted answer because it allows the user to only handle this error with a specific error handler and not need to resume next or have the rest of the procedure handled the same way. In case anyone ends up here like I did.
I have found that checking for the "Object required" error that you mentioned is one way of handling a cancel.
On Error Resume Next
dim selectRange as Range
' InputBox will prevent invalid ranges from being submitted when set to Type:=8.
Set selectRange = Application.InputBox("Select your range", "Hello", , , , , , 8)
' Check for cancel: "Object required".
If Err.Number = 424 Then
' Cancel.
Exit Sub
End If
On Error GoTo 0
I went with a cleaner solution:
Dim InputValue As Range
On Error Resume Next
Set InputValue = Application.InputBox("Select Range","Obtain Range", Type:=8)
Err.Clear
If InputValue Is Nothing Then
GoTo ExitApp:
End If
This will clear the error message and catch the "nothing" value returned to InputValue. Usefully, this doesn't interrupt a submission of no information, which Excel just loops back to requesting input automatically, but the user may need to add additional error handling for bad data entry.
Down code, add:
ExitApp:
Exit Sub
For exiting, which can be usefully shared between multiple input cancel handlers.
If I use Dirks second answer inside a for loop and I want to exit my sub, it is not enough to execute an Exit Sub inside his IF statement
I found that if I use Exit Sub standalone inside a for loop, I will not exit my sub in all cases, however, in most cases only exit the for loop.
Here you have Dirks code
EDIT
Another smart way is using the same behavior with a collection like
this:
Sub test()
Dim MyRange As Range
Dim MyCol As New Collection
MyCol.Add Application.InputBox("dada", , , , , , , 8)
If TypeOf MyCol(1) Is Range Then Set MyRange = MyCol(1)
Set MyCol = New Collection
If MyRange Is Nothing Then
Debug.Print "The input box has been canceled"
Else
Debug.Print "the range " & MyRange.Address & " was selected"
End If
End Sub
If you still have any questions, just ask ;)
Here is what I made to work as a example:
Sub test()
Dim i as Integer
Dim boolExit as Boolean
Dim MyRange As Range
Dim MyCol As New Collection
boolExit = False
For i = 1 To 5 Then
MyCol.Add Application.InputBox("dada", , , , , , , 8)
If TypeOf MyCol(1) Is Range Then Set MyRange = MyCol(1)
Set MyCol = New Collection
If MyRange Is Nothing Then
Debug.Print "The inputbox has been canceled"
boolExit = True
Exit Sub
Else
Debug.Print "the range " & MyRange.Address & " was selected"
End If
Next i
If boolExit = True Then Exit Sub 'Checks if Sub should be exited
Debug.Print "Program completed"
End Sub
If you press cancel at anytime in the five runs, the Sub is shutdown with the above code and you will never see Program completed printed.
However if you remove boolExit from the above, the code after the For loop is still being run if you press cancel in any of the 1+ runs and you will see Program completed even when that is not true.

Is there a way to set one cell on one worksheet to equal one cell on another worksheet based on the value of a specific cell?

So I have a dropdown to select the year; 2015, 2016, 2017, etc, but based on which year is selected, I want to populate cells from a specific worksheet. So for example if 2015 is selected, cell K3 in the current worksheet equals cell E12 from the 2015 worksheet. Any help would be greatly appreciated, thanks!
Edit:
So far I have the following VBA code:
Option Explicit
Sub Worksheet_Change(ByVal Target As Range)
If Range("J2") = "2016" Then
Range("K3") = ActiveWorkbook.Worksheets("2016").Range("E12")
Else
Range("K3") = "0"
End If
End Sub
...but keep getting this error:
Run-time error '1004':
Method 'Range' of object '_Worksheet' failed
...and then Excel restarts.
A Drop-Down Worksheet Change
In the initial solution, when writing to the destination cell, the event would get re-triggered. Although it would finish with the If Intersect... line, I consider it as unacceptable (wrong). Study the following solution how this is avoided.
To see (prove) the difference, you could add e.g. the line MsgBox "Entering Change Event" at the beginning of each code which would show that the wrong solution shows the message box twice on each change in the drop-down cell.
Corrected and Improved
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Const sAddress As String = "E12" ' Source Cell (read from)
Const dddAddress As String = "J2" ' Destination Drop-Down Cell
Const dAddress As String = "K3" ' Destination Cell (written to)
Const dValNoWorksheet As Long = 0 ' source worksheet not found
Const dValBlank As Long = 0 ' source cell blank i.e. [Empty],[=""],['],...)
Dim dddCell As Range: Set dddCell = Range(dddAddress)
' This will prevent the succeeding code to run if there was no change
' in the drop-down cell.
If Intersect(Target, dddCell) Is Nothing Then Exit Sub ' not ddd cell
' 'Me' is the worksheet containing this code, while 'Me.Parent' is
' its workbook which is also 'ThisWorbook'.
On Error Resume Next ' defer error trapping
Dim sws As Worksheet: Set sws = Me.Parent.Worksheets(CStr(dddCell.Value))
On Error GoTo 0 ' enable error trapping ('Err.Number = 0')
' The following line prevents triggering the event again when writing
' to the destination cell ('dCell').
Application.EnableEvents = False
' Immediately after the previous line start an error-handling routine
' to prevent exiting the procedure with events disabled. Its flow
' is self-explanatory but study it carefully.
On Error GoTo ClearError ' enable error trapping
' Now you do your thing. If something goes wrong, the error handler
' will make make sure that the procedure will exit only after enabling
' events.
Dim dCell As Range: Set dCell = Range(dAddress)
If sws Is Nothing Then ' worksheet doesn't exist
dCell.Value = dValNoWorksheet
Else ' worksheet exists
Dim sCell As Range: Set sCell = sws.Range(sAddress)
If Len(CStr(sCell.Value)) = 0 Then ' blank
dCell.Value = dValBlank
Else ' not blank
dCell.Value = sCell.Value
End If
End If
SafeExit:
' Be careful, if an error occurs here, it will trigger an endless loop,
' since the error handler is still active.
Application.EnableEvents = True
Exit Sub
ClearError:
Debug.Print "Run-time error '" & Err.Number & "': " & Err.Description
Resume SafeExit ' the error handler stays active('Err.Number = 0')
End Sub
Wrong
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Range("J2")) Is Nothing Then Exit Sub ' not dd cell
On Error Resume Next
Dim ws As Worksheet: Set ws = Me.Parent.Worksheets(CStr(Range("J2").Value))
On Error GoTo 0
If ws Is Nothing Then ' worksheet doesn't exist
Range("K3").Value = 0
Else ' worksheet exists
If Len(CStr(ws.Range("E12").Value)) = 0 Then ' blank
Range("K3").Value = 0
Else ' not blank
Range("K3").Value = ws.Range("E12").Value
End If
End If
End Sub

How to handle blank/Invalid data for RefEdit control in VBA userform

I am using a Excel VBA userform to change the font case as below picture. When RefEdit control have correct Range, then it is working fine. But if I click "Apply" button keeping RefEdit blank/ only Space/ any word(invalid Range), Userform disappear without showing any error notification.
For Uppercase code:-
Sub UpperCaseFont()
For Each x In Range(CaseRefEdit.Value)
If Not IsEmpty(x.Value) Then
x.Value = UCase(x.Value)
End If
Next
MsgBox "Done"
End Sub
LowerCase code:-
Sub LowerCaseFont()
For Each x In Range(CaseRefEdit.Value)
If Not IsEmpty(x.Value) Then
x.Value = LCase(x.Value)
End If
Next
MsgBox "Done"
End Sub
Propercase code:-
Sub ProperCaseFont()
For Each x In Range(CaseRefEdit.Value)
If Not IsEmpty(x.Value) Then
x.Value = WorksheetFunction.Proper(x.Value)
End If
Next
End Sub
CommandButton code:-
Private Sub CaseApplyCommandButton_Click()
If UpperCase = True Then Call UpperCaseFont
If LowerCase = True Then Call LowerCaseFont
If ProperCase = True Then Call ProperCaseFont
For that reason, I have tried to modified as below, But still i am facing the problem that if RefEdit is blank and I click on "Apply" button then userform disappear and also found that other all userform start unknown problem to initialize.
Private Sub CaseApplyCommandButton_Click()
'Font Case
Dim Rng As Range
On Error Resume Next
Set Rng = Range(Me.CaseRefEdit.Value)
MsgBox Rng
On Error GoTo 0
If Rng Is Nothing Then
MsgBox "Select the Cells to change the case"
Else
If UpperCase = True Then Call UpperCaseFont
If LowerCase = True Then Call LowerCaseFont
If ProperCase = True Then Call ProperCaseFont
End If
End Sub
I have found that problem is started when I add below code:-
Private Sub CaseRefEdit_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Range(CaseRefEdit.Value).Select
End Sub
As per my understanding when RefEdit is not giving any range for input any number or word or keeping blank, then userform disappear. Any solution for this?
On the second question.
The [if IsError (range ("Hello") then ...] expression first evaluates the range ("Hello"), and if it is invalid, an error occurs before calling the function. Therefore, it is better to pass the address of the range to the IsError function, and calculate the range inside the function and determine its correctness.
Function IsError(addr As String) As Boolean
Dim rng As Range
On Error Resume Next
Set rng = Range(addr)
IsError = rng Is Nothing
End Function
Sub test1()
If IsError("%$%W34") Then
Debug.Print "Range is invalid"
Else
Debug.Print "Range is correct"
End If
End Sub
my problem is solved as below. Thanks #Алексей Р.
Private Sub CaseRefEdit_Exit(ByVal Cancel As MSForms.ReturnBoolean)
On error resume next
Range(CaseRefEdit.Value).Select
End Sub
Anyone know, how to check Range("etc")/ Range(123) is valid or not? Like-
If IsError(range("etc")) then
...
else
....
end if
You may use On Error statement, for example:
Function testRNG(addr As String) As Range ' returns correct Range object or Nothing otherwise
' initially testRNG = Nothing
On Error Resume Next
Set testRNG = Range(addr) ' if the address is correct, testRNG returns Range, otherwise an error occurs, the expression is not evaluated and testRNG remains Nothing
End Function
Sub foo()
Dim addr As String
addr = "W12"
Set Rng = testRNG(addr)
If Rng Is Nothing Then
Debug.Print "Address " & addr & " is wrong"
Else
Debug.Print "Range " & Rng.Address & " is correct"
End If
End Sub

excel dropdown with address as result

A normal data validation dropdown in Excel results in the selected value being put into the cell. In my case though, I am referencing another list in my sheet whose elements can change. My goal is to make those changes apply to already selected dropdown items.
Example:
Referenced list in dropdown (sheet "List"):
A
B
C
User selects A from the dropdown in sheet "Selection":
A
Now the user changes A to Y in sheet "List":
Y
B
C
The user's selection in sheet "Selection" still shows A, but it should now show Y:
A
Is this possible in any way? Can I e.g. make the dropdown result in an address to the value, instead of the value itself?
Thanks!
There unfortunately isn't any way to do this with a formula or build-in function (that I'm aware of)
Here is something simple you could apply and work with:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target(1, 1), Range("A1:A3")) Is Nothing Then
ActiveWorkbook.Sheets("Selection").Range("A1").Value = Target(1, 1)
End If
End Sub
Assuming Range("A1:A3") is the list you are refering to. Paste this under your List sheet.
Drop Down feat. Worksheet Change Event
To 'copy' your setup, in worksheet List I have created a name
Drop1 which refers to the column range containing the values. Then
I have created a Validation Drop Down in B2 in worksheet
Selection and chose the name (Drop1) as the list.
Change the constants (Const) to fit your needs.
Module1
Option Explicit
Public strListSheet As String
Public strListRange As String
Public vntList As Variant
Sub Drop(rngList As Range)
Const cDropSheet As String = "Selection"
Const cDropRange As String = "B2"
Dim rng As Range
Dim vntNew As Variant
Dim vntVal As Variant
Dim Nor As Long
Dim i As Long
Set rng = ThisWorkbook.Worksheets(cDropSheet).Range(cDropRange)
vntVal = rng
vntNew = rngList
Nor = UBound(vntList)
For i = 1 To Nor
If vntList(i, 1) = vntVal Then
If vntVal <> vntNew(i, 1) Then
rng = vntNew(i, 1)
End If
Exit For
End If
Next
vntList = vntNew
End Sub
Sub Initialize()
Const strDrop as string = "Drop1"
Dim str1 As String
Dim lngInStr As Long
' Prepare
str1 = Names(strDrop).RefersTo
lngInStr = InStr(1, str1, "!")
' Write Public Variables
strListRange = Right(str1, Len(str1) - lngInStr)
strListSheet = WorksheetFunction.Substitute(WorksheetFunction _
.Substitute(Left(str1, lngInStr - 1), "=", ""), "'", "")
vntList = Worksheets(strListSheet).Range(strListRange)
End Sub
ThisWorkbook
Option Explicit
Private Sub Workbook_Open()
Initialize
End Sub
List (Worksheet)
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo ErrInit
If Target.Cells.Count = 1 Then
Dim rngList As Range
Set rngList = ThisWorkbook.Worksheets(strListSheet) _
.Range(strListRange)
If Not Intersect(Target, rngList) Is Nothing Then
Drop rngList
End If
End If
Exit Sub
ErrInit:
MsgBox "An unexpected error occurred. Error '" & Err.Number & "':" _
& Err.Description, vbCritical, "Error"
On Error GoTo 0
Initialize
End Sub

Handle cancellation of InputBox to select range

I have the following piece of code:
dim selectRange as Range
Set selectRange = Application.InputBox("Select your range", "Hello", , , , , , 8)
When a user chooses Cancel the InputBox prompt, it returns error of Object not set.
I have tried to use a Variant variable type but I can't handle it. In case of cancelling, it returns False, meanwhile in case of selecting a range, it returns Range of InputBox.
How can I avoid this error?
This is a problem when selection a range with an inputbox. Excel returns an error before the range is returned, and it carries this error on when you press cancel.
You should therefore actively handle this error. If you don't want anything to happen when you press cancel, you can just use the code like this:
Sub SetRange()
Dim selectRange As Range
On Error Resume Next
Set selectRange = Application.InputBox("Select your range", "Hello", , , , , , 8)
Err.Clear
On Error GoTo 0
End Sub
While this question is a bit older I still want to show the proper way to do it without errors. You can do it either to it via function or with a sub.
Your main procedure is something like this:
Sub test()
Dim MyRange As Range
testSub Application.InputBox("dada", , , , , , , 8), MyRange 'doing via Sub
Set MyRange = testFunc(Application.InputBox("dada", , , , , , , 8)) ' doing via function
If MyRange Is Nothing Then
Debug.Print "The InputBox has been canceled."
Else
Debug.Print "The range " & MyRange.Address & " was selected."
End If
End Sub
the Sub-way (funny) would be:
Sub testSub(ByVal a As Variant, ByRef b As Range)
If TypeOf a Is Range Then Set b = a
End Sub
And the function would look like:
Function testFunc(ByVal a As Variant) As Range
If TypeOf a Is Range Then Set testFunc = a
End Function
Now simply use the way you like and delete the unused line.
If calling a sub or a function you do not need to Set the parameter. That said, it doesn't matter if the InputBox returns an object or not. All you need to do, is to check if the parameter is the object you want or not and then act accordingly to it.
EDIT
Another smart way is using the same behavior with a collection like this:
Sub test()
Dim MyRange As Range
Dim MyCol As New Collection
MyCol.Add Application.InputBox("dada", , , , , , , 8)
If TypeOf MyCol(1) Is Range Then Set MyRange = MyCol(1)
Set MyCol = New Collection
If MyRange Is Nothing Then
Debug.Print "The inputbox has been canceled"
Else
Debug.Print "the range " & MyRange.Address & " was selected"
End If
End Sub
If you still have any questions, just ask ;)
I'm late to the party here but this was the only place I could find that explained why I was having trouble just checking my variable for nothing. As explained in the accepted answer, the vbCancel on a range object isn't handled the same way as a string object. The error must be caught with an error handler.
I hate error handlers. So I segregated it to its own function
Private Function GetUserInputRange() As Range
'This is segregated because of how excel handles cancelling a range input
Dim userAnswer As Range
On Error GoTo inputerror
Set userAnswer = Application.InputBox("Please select a single column to parse", "Column Parser", Type:=8)
Set GetUserInputRange = userAnswer
Exit Function
inputerror:
Set GetUserInputRange = Nothing
End Function
Now in my main sub I can
dim someRange as range
set someRange = GetUserInputRange
if someRange is Nothing Then Exit Sub
Anyhow this is not the same as the accepted answer because it allows the user to only handle this error with a specific error handler and not need to resume next or have the rest of the procedure handled the same way. In case anyone ends up here like I did.
I have found that checking for the "Object required" error that you mentioned is one way of handling a cancel.
On Error Resume Next
dim selectRange as Range
' InputBox will prevent invalid ranges from being submitted when set to Type:=8.
Set selectRange = Application.InputBox("Select your range", "Hello", , , , , , 8)
' Check for cancel: "Object required".
If Err.Number = 424 Then
' Cancel.
Exit Sub
End If
On Error GoTo 0
I went with a cleaner solution:
Dim InputValue As Range
On Error Resume Next
Set InputValue = Application.InputBox("Select Range","Obtain Range", Type:=8)
Err.Clear
If InputValue Is Nothing Then
GoTo ExitApp:
End If
This will clear the error message and catch the "nothing" value returned to InputValue. Usefully, this doesn't interrupt a submission of no information, which Excel just loops back to requesting input automatically, but the user may need to add additional error handling for bad data entry.
Down code, add:
ExitApp:
Exit Sub
For exiting, which can be usefully shared between multiple input cancel handlers.
If I use Dirks second answer inside a for loop and I want to exit my sub, it is not enough to execute an Exit Sub inside his IF statement
I found that if I use Exit Sub standalone inside a for loop, I will not exit my sub in all cases, however, in most cases only exit the for loop.
Here you have Dirks code
EDIT
Another smart way is using the same behavior with a collection like
this:
Sub test()
Dim MyRange As Range
Dim MyCol As New Collection
MyCol.Add Application.InputBox("dada", , , , , , , 8)
If TypeOf MyCol(1) Is Range Then Set MyRange = MyCol(1)
Set MyCol = New Collection
If MyRange Is Nothing Then
Debug.Print "The input box has been canceled"
Else
Debug.Print "the range " & MyRange.Address & " was selected"
End If
End Sub
If you still have any questions, just ask ;)
Here is what I made to work as a example:
Sub test()
Dim i as Integer
Dim boolExit as Boolean
Dim MyRange As Range
Dim MyCol As New Collection
boolExit = False
For i = 1 To 5 Then
MyCol.Add Application.InputBox("dada", , , , , , , 8)
If TypeOf MyCol(1) Is Range Then Set MyRange = MyCol(1)
Set MyCol = New Collection
If MyRange Is Nothing Then
Debug.Print "The inputbox has been canceled"
boolExit = True
Exit Sub
Else
Debug.Print "the range " & MyRange.Address & " was selected"
End If
Next i
If boolExit = True Then Exit Sub 'Checks if Sub should be exited
Debug.Print "Program completed"
End Sub
If you press cancel at anytime in the five runs, the Sub is shutdown with the above code and you will never see Program completed printed.
However if you remove boolExit from the above, the code after the For loop is still being run if you press cancel in any of the 1+ runs and you will see Program completed even when that is not true.

Resources