How to check that Excel cell contains REF! error in VBA - vba

I found many discussions on how to do it in Excel, but my goal is to capture REF! error in VBA, not in Excel itself. Is it possible ?

If IsError(cell.Value) Then
If cell.Value = CVErr(xlErrName) Then
...
End If
End If
The original code is wrong and will give a Type Mismatch error if the cell does not contain an error.
If cell.Value = CVErr(xlErrRef) Then
...
End If

Sub CheckRef()
Dim CheckRange As Range, CheckCell As Range
Set CheckRange = [A1:D10] ' as per app
For Each CheckCell In CheckRange
If IsError(CheckCell) And _
CVErr(CheckCell) = CVErr(2023) Then ' 2023 --> xlErrRef
MsgBox ("#REF! in " & CheckCell.AddressLocal)
Exit Sub ' exit after first #REF! found
End If
Next CheckCell
End Sub
example
enter "=1/0" in B2 to create an error different to "#REF!"
enter 1 in B4, B5
enter "=B4+B5" in B7
delete row 4
run Sub CheckRef()

Related

VBA if cell equals certain value make that cell next available cell

I have a sheet called "JE", and in column C (C7:C446) users are able to populate the cells with account codes by two methods:
Double-clicking codes on a separate sheet called acct_codes
Manually enter the codes in column C. When the user manually enters the account code in column C, it is checked and changed to #N/A if it isn't listed in the acct_codes sheet to indicate to the user the code they entered was incorrect.
Column E is an account description column it will show the description associated with the account code in column C.
As it is now, the next available cell is the next blank cell in column C. I would like to make any cell in column E that equals #N/A to be the next available cell, THEN the next blank cell can be the next available cell.
For example if cell E11 has a value of #N/A, then the next time a user navigates to the acct_codes sheet and double-clicks a valid account code, I would like the account code they clicked to overwrite and populate C11.
I am unsure of the syntax to accomplish this and am having a hard time finding good example of this online. If anyone knows of a way I can go about doing this, I'd greatly appreciate it.
Here is the code I have in the acct_codes sheet:
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim acctDesc As Range
Set acctDesc = Range("E7:E446")
If Target.Column = 1 Then
For j = 7 To 447
If Worksheets("JE").Range("C" & j).Value = "" Then
Worksheets("JE").Range("C" & j).Value = ActiveCell.Value
Worksheets("JE").Activate
Exit For
End If
Next j
End If
For Each Cell In acctDesc
If Cell.Value = "#N/A" Then
'Make that next available cell'
'else make next blank cell next available'
End If
Next Cell
Cancel = True
End Sub
EDIT
Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim NextAvailableCell As Range
With ThisWorkbook.Sheets("JE")
Set NextAvailableCell = .Range("C7:C447").Find(What:="#N/A", _
LookAt:=xlWhole, _
LookIn:=xlValues)
If NextAvailableCell Is Nothing Then
Set NextAvailableCell = .Range("C7:C448").End(xlUp).Offset(1, 0)
.Cells(NextAvailableCell.Row, "C").Value = Target.Value
End If
End With
NextAvailableCell.Value = Target.Value
Cancel = True
Call Back_to_JE 'calls a macro that brings user back to main form/sheet "JE"
End Sub
It would be much quicker to use Find
Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim NextAvailableCell As Range
With ThisWorkbook.Sheets("JE")
' Set equal to next "#N/A" cell
Set NextAvailableCell = .Range("C7:C447").Find(What:="#N/A", _
LookAt:=xlWhole, _
LookIn:=xlValues)
' If no "#N/A" cell was found then get last empty cell in column,
' assuming it's above C448
If NextAvailableCell Is Nothing Then
Set NextAvailableCell = .Range("C448").End(xlUp).Offset(1, 0)
End If
End With
' Assign value of double clicked cell
NextAvailableCell.Value = Target.Value
' Make it so that the double clicker doesn't enter the cell
Cancel = True
End Sub
This also avoids activating and selecting, which is good practise.
I'm unsure which cell you want to write to. If you want to search for #N/A in column E instead of column C, simply change that in the .Range(___).Find line. Ditto for the next blank cell in the relevant line.
If you want to write to a specific column, say column E, then use something like
' Inside the With block for ThisWorkbook.Sheets("JE")
.Cells(NextAvailableCell.Row, "E").Value = Target.Value

Use VLookup to see if selected cell is in a range?

I've seen how to say "Is cell x in range y" but since I'm using VLookup I'm not sure how to reconcile the two.
Basically, the code below does a lookup on a table that contains tips and then displays them in a specified cell. It works great. What I would like to do is specify an entire range of cells in the lookup table, then if the user selects any cell within that range the tip is displayed. As it stands, if I have a large area of say 10 cells I have to create 10 duplicate entries in the lookup table (one for each cell).
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim cellTitle As Range
Set cellTitle = Range("J2")
Dim cellTip As Range
Set cellTip = Range("J3")
If Target.Address = "$J$3:$K$5" Or Target.Address = "$J$2:$K$2" Or Target.Address = "$K$1" Then
'leave existing content in case user wants to copy tip
Else
Range("K1").Value = Target.Address
Title = Application.VLookup(Target.Address, Sheets("Settings").Range("TipsDashboard"), 2, False)
If Not IsError(Title) Then
Tip = Application.VLookup(Target.Address, Sheets("Settings").Range("TipsDashboard"), 3, False)
cellTitle.Value = Title
cellTip.Value = Tip
Else
cellTitle.Value = "Tips & Instructions"
cellTip.Value = "Try selecting various fields to get dynamic tips or instructions in this space."
End If
End If
End Sub
Here is a sample of my lookup table:
You'll notice there are ranges here, but they are merged cells.
edited: made so that it's possible to associate different cells in active sheet to the same range value in "cell" column of" Settings" sheet
Option Explicit
Private Sub Worksheet_SelectionChange(ByVal target As Range)
Dim cellTitle As Range, cellTip As Range, found As Range
Set cellTitle = Range("J2")
Set cellTip = Range("J3")
If target.address = "$J$3:$K$5" Or target.address = "$J$2:$K$2" Or target.address = "$K$1" Then
'leave existing content in case user wants to copy tip
Else
Range("K1").Value = target.address
Set found = GetCell(target, Sheets("Settings").Range("TipsDashboard").Columns(1))
If Not found Is Nothing Then
cellTitle.Value = found.Offset(, 1)
cellTip.Value = found.Offset(, 2)
Else
cellTitle.Value = "Tips & Instructions"
cellTip.Value = "Try selecting various fields to get dynamic tips or instructions in this space."
End If
End If
End Sub
Function GetCell(target As Range, sourceRng As Range) As Range
Dim cell As Range, cell2 As Range
With target
For Each cell In sourceRng.SpecialCells(xlCellTypeConstants, xlTextValues)
Set cell2 = GetRangeFromAddress(.Parent, cell.Value)
If Not cell2 Is Nothing Then
If Not Intersect(.cells, cell2) Is Nothing Then
Set GetCell = cell
Exit Function
End If
End If
Next cell
End With
End Function
Function GetRangeFromAddress(sht As Worksheet, address As String) As Range
On Error Resume Next
Set GetRangeFromAddress = sht.Range(address)
On Error GoTo 0
End Function

Getting Right Cell Name of current Cell VBA excel

I have current cell name like B7 i want to get cell name of the cell right to current cell for example in this case the result will be C7. How can I achieve this
This is what I have tired but its not working
CellName = "B7"
ValueCellName = Right(Range(CellName)).name
Try using offset function:
valuecellname = Range(cellname).Offset(0, 1).Address
Is this what you are trying?
Sub Sample()
Debug.Print GetrightCell("B7")
Debug.Print GetrightCell("XFD7")
Debug.Print GetrightCell("ADIL1234")
End Sub
'~~> Function returns the right cell if there is one!
Function GetrightCell(CellName As String) As String
On Error GoTo Whoa
If Range(CellName).Column <> Columns.Count Then
GetrightCell = Range(CellName).Offset(0, 1).Address
Else
GetrightCell = "There are no more cells to the right of this cell"
End If
Exit Function
Whoa:
GetrightCell = "Invalid Cell Name"
End Function

How to fill color in a cell in VBA?

I would like to color cells that have "#N/A" value in the currentsheet. In order to do this i use following macro:
Sub ColorCells()
Dim Data As Range
Dim cell As Range
Set currentsheet = ActiveWorkbook.Sheets("Comparison")
Set Data = currentsheet.Range("A2:AW1048576")
For Each cell In Data
If cell.Value = "#N/A" Then
cell.Interior.ColorIndex = 3
End If
Next
End Sub
But the line If cell.Value = "#N/A" Then gives an error: Type mismatch. Maybe someone can help to understand where is the error? Thanks
Non VBA Solution:
Use Conditional Formatting rule with formula: =ISNA(A1) (to highlight cells with all errors - not only #N/A, use =ISERROR(A1))
VBA Solution:
Your code loops through 50 mln cells. To reduce number of cells, I use .SpecialCells(xlCellTypeFormulas, 16) and .SpecialCells(xlCellTypeConstants, 16)to return only cells with errors (note, I'm using If cell.Text = "#N/A" Then)
Sub ColorCells()
Dim Data As Range, Data2 As Range, cell As Range
Dim currentsheet As Worksheet
Set currentsheet = ActiveWorkbook.Sheets("Comparison")
With currentsheet.Range("A2:AW" & Rows.Count)
.Interior.Color = xlNone
On Error Resume Next
'select only cells with errors
Set Data = .SpecialCells(xlCellTypeFormulas, 16)
Set Data2 = .SpecialCells(xlCellTypeConstants, 16)
On Error GoTo 0
End With
If Not Data2 Is Nothing Then
If Not Data Is Nothing Then
Set Data = Union(Data, Data2)
Else
Set Data = Data2
End If
End If
If Not Data Is Nothing Then
For Each cell In Data
If cell.Text = "#N/A" Then
cell.Interior.ColorIndex = 4
End If
Next
End If
End Sub
Note, to highlight cells witn any error (not only "#N/A"), replace following code
If Not Data Is Nothing Then
For Each cell In Data
If cell.Text = "#N/A" Then
cell.Interior.ColorIndex = 3
End If
Next
End If
with
If Not Data Is Nothing Then Data.Interior.ColorIndex = 3
UPD: (how to add CF rule through VBA)
Sub test()
With ActiveWorkbook.Sheets("Comparison").Range("A2:AW" & Rows.Count).FormatConditions
.Delete
.Add Type:=xlExpression, Formula1:="=ISNA(A1)"
.Item(1).Interior.ColorIndex = 3
End With
End Sub
Use conditional formatting instead of VBA to highlight errors.
Using a VBA loop like the one you posted will take a long time to process
the statement If cell.Value = "#N/A" Then will never work. If you insist on using VBA to highlight errors, try this instead.
Sub ColorCells()
Dim Data As Range
Dim cell As Range
Set currentsheet = ActiveWorkbook.Sheets("Comparison")
Set Data = currentsheet.Range("A2:AW1048576")
For Each cell In Data
If IsError(cell.Value) Then
cell.Interior.ColorIndex = 3
End If
Next
End Sub
Be prepared for a long wait, since the procedure loops through 51 million cells
There are more efficient ways to achieve what you want to do. Update your question if you have a change of mind.
Select all cells by left-top corner
Choose [Home] >> [Conditional Formatting] >> [New Rule]
Choose [Format only cells that contain]
In [Format only cells with:], choose "Errors"
Choose proper formats in [Format..] button
You need to use cell.Text = "#N/A" instead of cell.Value = "#N/A". The error in the cell is actually just text stored in the cell.

Let the user click on the cells as their input for an Excel InputBox using VBA

I have an InputBox that stores user input into a variable. The input the user is inputting is a cell number.
For example, the input box pops up and asks the user, "Where would you like to start?" The user would then type in A4, or whichever cell they would want to start.
My question is, is there a way to allow the user to physically click on cell A4 instead of typing it in?
Thanks in advance for any help
Update: So, basically we have long lists of transposed data that span horizontally. We want those lists to stacked on top of each other horizontally, which is what this code is supposed to do.
Everything worked fine before, but the user would to have to manually type in the cell number into the InputBox. The input box asks the user where they want to start cutting and the second box asks the user where they want to start pasting. I would store those input values into string variables and everything worked like a charm.
Since then, I wanted the user to be able to physically click on the cell since it can be difficult to look at which row number it actually is. The code below is updated to reflect the changes trying to be used to allow the user to click on the cell. I added the Application.InputBox method and changed my declarations of the variables to Range.
I stepped into the program one at a time to see what was going on and this is what I found. Before, if the User wanted to start at B4 and paste to A16, it would select the data range for B(B4:B15), cut it, and paste it to A16. Then, the way I had the code, it would go back to the B4 user input spot and using a for loop to increment my x variable, it would offset to the next column over to the right. So, it would then repeat the process of cutting column C(C4:C15) and paste it this time to A28(using xldown), and so on for proceeding columns.
What is happening now when I stepped into this current code is that I don't see any recorded values into my Range variables. It does the first step of cutting B4:B15 and pasting it to A16, but when it goes to run the next loop, instead of starting back at B4 and offsetting, it starts off on A16 and then offsets. It should be going back to B4, which the user selected as the starting spot, and then offsetting.
Sorry, for the long explanations, but I hope this helped to clear the situation up.
Current code using Application.InputBox
Dim x As Integer
Dim strColumnStart As Range
Dim strColumnEnd As Range
On Error Resume Next
Application.DisplayAlerts = False
Set strColumnStart = Application.InputBox("What cell would you like to start at?", "Starting position","Please include column letter and cell number", Type:=8)
On Error GoTo 0
Set strColumnEnd = Application.InputBox("Where would you like to paste the cells to?", "Pasting position", "Please include column letter and cell number", Type:=8)
On Error GoTo 0
Application.DisplayAlerts = True
If strColumnStart = "What cell would you like to start at?" Or _
strColumnEnd = "Please include column letter and cell number" Then
Exit Sub
Else
For x = 0 To strColumnStart.CurrentRegion.Columns.Count
strColumnStart.Select
ActiveCell.Offset(0, x).Select
If ActiveCell.Value = Empty Then
GoTo Message
Else
Range(Selection, Selection.End(xlDown)).Select
Selection.Cut strColumnEnd.Select
ActiveCell.Offset(-2, 0).Select
ActiveCell.End(xlDown).Select
ActiveCell.Offset(1, 0).Select
ActiveSheet.Paste
strColumnStart.Select
End If
Next x
End If
Message:
MsgBox ("Finished")
strColumnEnd.Select
ActiveSheet.Columns(ActiveCell.Column).EntireColumn.AutoFit
Application.CutCopyMode = False
End Sub
From: http://www.ozgrid.com/VBA/inputbox.htm
Sub RangeDataType()
Dim rRange As Range
On Error Resume Next
Application.DisplayAlerts = False
Set rRange = Application.InputBox(Prompt:= _
"Please select a range with your Mouse to be bolded.", _
Title:="SPECIFY RANGE", Type:=8)
On Error GoTo 0
Application.DisplayAlerts = True
If rRange Is Nothing Then
Exit Sub
Else
rRange.Font.Bold = True
End If
End Sub
Updated with OP's requirements:
Sub Test2()
Dim x As Integer
Dim rngColumnStart As Range
Dim rngColumnEnd As Range
Dim rngCopy As Range
Dim numRows As Long, numCols As Long
On Error Resume Next
Set rngColumnStart = Application.InputBox( _
"Select the cell you'd like to start at", _
"Select starting position", , Type:=8)
If rngColumnStart Is Nothing Then Exit Sub
Set rngColumnEnd = Application.InputBox( _
"Select where you'd like to paste the cells to", _
"Select Pasting position", , Type:=8)
On Error GoTo 0
If rngColumnEnd Is Nothing Then Exit Sub
Set rngColumnEnd = rngColumnEnd.Cells(1) 'in case >1 cell was selected
Set rngCopy = rngColumnStart.CurrentRegion
numRows = rngCopy.Rows.Count
numCols = rngCopy.Columns.Count
For x = 1 To numCols
rngCopy.Columns(x).Copy _
rngColumnEnd.Offset((x - 1) * numRows, 0)
Next x
rngCopy.ClearContents
MsgBox ("Finished")
rngColumnEnd.EntireColumn.AutoFit
Application.CutCopyMode = False
End Sub