Can I find whether a Cell in Excel is referenced in a formula? - vba

I have searched alot of sites on the internet, and I'm guessing I haven't found an answer because it is not possible, to try to understand the following:
I would like to understand if a Cell containing a value (say 10) plays into / forms part of a formula further into the document. I KNOW that the cell I have is NOT a formula cell, it is a single entry, however, I am trying to understand if this cell forms part of a formula. The need for this is there are ALOT of formulas and ALOT of data, and I am trying to see which data is relvant and which data is not.
Hope somone can help?
Kind regards
Paul

Manually you can use "Trace Dependents" on the 'Formula Auditing' menu under "Formulas" tool tab.
Using VBA you can check the number of dependents like this:
Range("A1").Dependents.Count
If you want a list of cell addresses that cell A1 is used in you can do this:
MsgBox (Range("A1").Dependents.Address)
I have A1 used in two other cells so my result looks like this:
Full code with error checking:
Sub test()
On Error Resume Next
If Range("A1").Dependents Is Nothing Then
MsgBox ("No dependents found")
Else
MsgBox (Range("A1").Dependents.Address)
End If
End Sub

The Dependents property of a Range object gives you the dependent cells of your formula. Be careful you will get an error if there are no dependent cells
Function hasDependents(r As Range) As Boolean
On Error GoTo err
hasDenpedents = r.Dependents
Exit Function
err:
hasDependents = False
End Function
And then
if hasDependents([A1]) then
'...

Related

Embedded "IF" formula breaks occasionally, VBA alternative?

I have a very large embedded IF formula that appears to occasionally break for no reason. Opening and closing the page a few times eventually gets it working again. I am wondering if there is a VBA alternative for it. Here is the IF formula I am running.
=IF(ISNUMBER(SEARCH("76210",E125)),"_012_00762_10",IF(ISNUMBER(SEARCH("76220",E125)),"_012_00762_20",IF(ISNUMBER(SEARCH("76900",E125)),"_012_00769_00",IF(ISNUMBER(SEARCH("76901",E125)),"_012_00769_01",IF(ISNUMBER(SEARCH("85702",E125)),"_012_00857_02",IF(ISNUMBER(SEARCH("85710",E125)),"_012_00857_10",IF(ISNUMBER(SEARCH("100800",E125)),"_012_01008_00",IF(ISNUMBER(SEARCH("100900",E125)),"_012_01009_00",IF(ISNUMBER(SEARCH("123100",E125)),"_012_01231_00",IF(ISNUMBER(SEARCH("124600",E125)),"_012_01246_00",IF(ISNUMBER(SEARCH("124601",E125)),"_012_01246_01",IF(ISNUMBER(SEARCH("124640",E125)),"_012_01246_40",IF(ISNUMBER(SEARCH("124641",E125)),"_012_01246_41",IF(ISNUMBER(SEARCH("142301",E125)),"_012_01423_01",IF(ISNUMBER(SEARCH("158801",E125)),"_012_01588_01",IF(ISNUMBER(SEARCH("158900",E125)),"_012_01589_00",IF(ISNUMBER(SEARCH("159203",E125)),"_012_01592_03",IF(ISNUMBER(SEARCH("159303",E125)),"_012_01593_03",IF(ISNUMBER(SEARCH("159401",E125)),"_012_01594_01",IF(ISNUMBER(SEARCH("159410",E125)),"_012_01594_10",IF(ISNUMBER(SEARCH("159420",E125)),"_012_01594_20",IF(ISNUMBER(SEARCH("159501",E125)),"_012_01595_01",IF(ISNUMBER(SEARCH("169000",E125)),"_012_01690_00",IF(ISNUMBER(SEARCH("186900",E125)),"_012_01869_00",IF(ISNUMBER(SEARCH("213200",E125)),"_012_02132_00",IF(ISNUMBER(SEARCH("213300",E125)),"_012_02133_00",IF(ISNUMBER(SEARCH("215400",E125)),"_012_02154_00",IF(ISNUMBER(SEARCH("220100",E125)),"_012_02201_00",IF(ISNUMBER(SEARCH("223800",E125)),"_012_02238_00",IF(ISNUMBER(SEARCH("225600",E125)),"_012_02256_00",IF(ISNUMBER(SEARCH("230700",E125)),"_012_02307_00",IF(ISNUMBER(SEARCH("230701",E125)),"_012_02307_01",IF(ISNUMBER(SEARCH("231800",E125)),"_012_02318_00",IF(ISNUMBER(SEARCH("235000",E125)),"_012_02350_00",IF(ISNUMBER(SEARCH("235020",E125)),"_012_02350_20",IF(ISNUMBER(SEARCH("242000",E125)),"_012_02420_00",IF(ISNUMBER(SEARCH("246400",E125)),"_012_02464_00",IF(ISNUMBER(SEARCH("292900",E125)),"_012_02929_00",""))))))))))))))))))))))))))))))))))))))
Basically it is built so a serial number is scanned and it populates a cell for the users who use this sheet with its results from the search. I am already running one macro in this sheet as well. Here is that...
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Set rng = Intersect(Range("A2:A500, J2:J500"), Target) ' define range of interest
If Not rng Is Nothing Then ' check it's not "nothing"
If WorksheetFunction.CountA(rng) = rng.Count Then 'check for all of its cells being not empty
On Error GoTo safe_exit 'add error control
Application.EnableEvents = False 'don't do anything until you know something has to be done
rng.Offset(, 1).Value = Date 'write Date next to all relevant changed cells
End If
End If
safe_exit:
Application.EnableEvents = True
End Sub
Maybe there is a better way to build this search using a formula that isn't using embedded IF statements, but i couldn't think of another way to do it. Thanks in advance.
This may be what you're looking for:
=IF(ISNA(MATCH(1,IF(ISERR(SEARCH($A$5:$A$42,$E$125)),0,1),0)),"",INDEX($B$5:$B$42,MATCH(1,IF(ISERR(SEARCH($A$5:$A$42,$E$125)),0,1),0)))
entered as an array formula (CTRL-SHIFT-ENTER).
Here $A$5:$A$42 contains 76210, 76220, ... , 292900 (entered as text, not numbers); and $B$5:$B$42 contains _012_00762_10, _012_00762_20, ... , _012_02929_00.
Hope that helps.
Any time you have to go more than 2 deep on an IF you may want to rethink the usage.
What you can do is build a table from your values. Then reference that table as part of your lookup. Assuming your list of value is in range D8:E45 you could use the formula =VLOOKUP(E125,$D$8:$E$45,2).
The beginning of your table would look like what's seen below. The input result cell is referencing your input value and pulling the match of the second column.
To get your table you can take your source formula and replace (Find and Replace - Ctrl+H) some characters with unique delimiting characters. Then use Text To Columns Alt+D+E and delimit and Copy>Paste special>Transpose to quickly have it close to the format you need.

“Run-time error ‘13’: Type mismatch” error message

Good afternoon.
I’m new at VBA. From my research on the internet, I’ve been able to add some lines that display a message box when an NG is entered into a cell within the range. However, when I try to delete the inputs from several cells, I get a Run-time error ‘13’: Type mismatch message. Any ideas what I’m doing wrong and how to fix it? I’ve added the code that I put in VBA below:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Range("I3:JY30")) Is Nothing Then Exit Sub
If Target.Value <> "NG" Then Exit Sub
MsgBox "ATTENTION: If bell cup is No Good, please replace with new cup and notify supervisor/leader for review. Also, document bell cup serial number and concern on worksheet titled Scrap Bell Tracking "
End Sub
Also, when I click Debug, the If Target.Value <> "NG" Then is highlighted.
Thank you in advance for your help.
Target is a Range, and hence it may consist of more than one cell. In that case, the Value property is invalid.
A simple solution would be to ignore changes with more than one cell: For that, we need to add the following before the access to the Value property:
If Target.Count <> 1 Then Exit Sub
But that would not show a message if e. g. the user pastes five cells, and one or more of them contain the text. The perfect solution would be looping through the range and check each cell separately. And then you would have to think if you want to show the message more than one time if the text is found in more than one cell. So, I will leave that as an exercise to the reader...

Code that works for a form control doesn't work for ActiveX control

First time poster in StackOverflow (but not stackexchange) so please let me know if I can clarify or make any formatting changes. Thank you.
Try as I might, I can't find the answer to this question. I suspect it's due to a lack of understanding when it comes to the basics of VBA. I have knowledge of VBA, but little understanding. That being said, here's the problem.
I've set up a form control Combo Box linked to a macro. I've set the input range to a list of hyperlinks in a different sheet and named the range "Hyperlinks". Each hyperlink is to a different sheet in the workbook. I've set the cell link to a blank sell adjacent to the hyperlinks and named it "Linked_Cell." A picture is below.
Form Control View
The macro code is as follows
Sub DropDown10_Change()
HyperLink_Index = Range("Linked_cell")
If Range("HyperLinks").Offset(HyperLink_Index - 1, 0).Hyperlinks(1).Name <> "" Then
Range("HyperLinks").Offset(HyperLink_Index - 1, 0).Hyperlinks(1).Follow NewWindow:=False, AddHistory:=True
End If
End Sub
This automatically moves someone to the sheet they select when they select that sheet from the drop-down menu.
I would like to use an Active X combo box instead of a form control for all the obvious reasons (resize text, etc.) However, I can't get it to work.
I've set "ListFillRange" to "Hyperlinks" and linked cell to "Linked_cell" and entered the same macro code. It looks like this:
View of Active X Combo Box
When I select from the drop down in the Active X Combo box I receive run time error 1004: "Method 'range' of object '_worksheet' failed." I've verified that my named ranges are correct and the code returns no such error when it's in a macro linked to a form control.
Any help is much appreciated! Thank you!
UPDATE: Fixed the Range error by updating the code to the following
Sub ComboBox1_Change()
Dim HyperLink_Index As Range
Set HyperLink_Index = Sheets("SheetList").Range("Linked_Cell")
If Sheets("SheetList").Range("HyperLinks").Offset(HyperLink_Index - 1, 0).Hyperlinks(1).Name <> "" Then
Sheets("SheetList").Range("HyperLinks").Offset(HyperLink_Index - 1, 0).Hyperlinks(1).Follow NewWindow:=False, AddHistory:=True
End If
End Sub
I now receive a Type Mismatch error on the beginning of the IF statement. I don't see the error and still have no idea why this behavior doesn't appear for identical macro code linked to a form control.
P.S. Sorry, I don't mean to turn StackOverflow in to my personal debugging team, so the main question I have is "Why is the behavior different between a macro and active x code?"
UPDATE 2: Found a fix. Was using the wrong index. The fix is below. Leaving it here in case someone else can find it useful.
Sub ComboBox1_Change()
If ComboBox1.Value <> "" Then
Sheets("SheetList").Range("Hyperlinks").Hyperlinks(ComboBox1.ListIndex + 1).Follow NewWindow:=False, AddHistory:=True
End If
End Sub
Found a fix. Was using the wrong index. The fix is below. Leaving it here in case someone else can find it useful.
Sub ComboBox1_Change()
If ComboBox1.Value <> "" Then
Sheets("SheetList").Range("Hyperlinks").Hyperlinks(ComboBox1.ListIndex +1).Follow NewWindow:=False, AddHistory:=True
End If
End Sub

VBA- Using inputbox to filter and copy data

i am working on a userform where i puted a button that when i click on it i got an input box where i try to filter data of the column (E) then after filtering this data copy from colum A1 till the value filtered in the column E in another sheet caaled filtred_data i am using this code this code but it show me a bug dont nw how to fix it
Private Sub CommandButton9_Click()
Dim xno As Integer, Found As Range
Do
xno = Application.InputBox("Enter the number of Top communities ", Type:=1)
If TypeName(xno) = "Boolean" Then Exit Sub
Set Found = Columns("E").Find(what:=xno, lookat:=xlWhole, LookIn:=xlValues)
If Found Is Nothing Then
MsgBox "the number was not found, please try again !!", vbInformation
Else
Found.Range("A1:F10000").Copy Destination:=Sheets("filtred_data").Range("A1:F10000")
End If
Loop
End Sub
if anyone can help me please , thank you
The problem in your case is that you are setting the Found variable to be a single cell by using the Find method. Later in your code, you are trying to copy the A1:F10000 of that ONE cell when you write Found.Range("A1:F1000").
Essentially, your code looks like this (assume Found refers to cell E25):
Range("E25").Range("A1:F1000").Copy
Can you see why that would cause an error?
I'd try to offer more help, but it's hard to determine exactly what you want. Can you possibly give more details about your spreadsheet layouts and an example of what you want to happen?

Get the cell reference of the value found by Excel INDEX function

The Problem
Assume that the active cell contains a formula based on the INDEX function:
=INDEX(myrange, x,y)
I would like to build a macro that locates the value found value by INDEX and moves the focus there, that is a macro changing the active cell to:
Range("myrange").Cells(x,y)
Doing the job without macros (slow but it works)
Apart from trivially moving the selection to myrange and manually counting x rows y and columns, one can:
Copy and paste the formula in another cell as follows:
=CELL("address", INDEX(myrange, x,y))
(that shows the address of the cell matched by INDEX).
Copy the result of the formula above.
Hit F5, Ctrl-V, Enter (paste the copied address in the GoTo dialog).
You are now located on the very cell found by the INDEX function.
Now the challenge is to automate these steps (or similar ones) with a macro.
Tentative macros (not working)
Tentative 1
WorksheetFunction.CELL("address", ActiveCell.Formula)
It doesn't work since CELL for some reason is not part of the members of WorksheetFunction.
Tentative 2
This method involves parsing the INDEX-formula.
Sub GoToIndex()
Dim form As String, rng As String, row As String, col As String
form = ActiveCell.Formula
form = Split(form, "(")(1)
rng = Split(form, ",")(0)
row = Split(form, ",")(1)
col = Split(Split(form, ",")(2), ")")(0)
Range(rng).Cells(row, CInt(col)).Select
End Sub
This method actually works, but only for a simple case, where the main INDEX-formula has no nested subformulas.
Note
Obviously in a real case myrange, x and ycan be both simple values, such as =INDEX(A1:D10, 1,1), or values returned from complex expressions. Typically x, y are the results of a MATCH function.
EDIT
It was discovered that some solutions do not work when myrange is located on a sheet different from that hosting =INDEX(myrange ...).
They are common practice in financial reporting, where some sheets have the main statements whose entries are recalled from others via an INDEX+MATCH formula.
Unfortunately it is just when the found value is located on a "far" report out of sight that you need more the jump-to-the-cell function.
The task could be done in one line much simpler than any other method:
Sub GoToIndex()
Application.Evaluate(ActiveCell.Formula).Select
End Sub
Application.Evaluate(ActiveCell.Formula) returns a range object from which the CELL function gets properties when called from sheets.
EDIT
For navigating from another sheet you should first activate the target sheet:
Option Explicit
Sub GoToIndex()
Dim r As Range
Set r = Application.Evaluate(ActiveCell.Formula)
r.Worksheet.Activate
r.Select
End Sub
Add error handling for a general case:
Option Explicit
Sub GoToIndex()
Dim r As Range
On Error Resume Next ' errors off
Set r = Application.Evaluate(ActiveCell.Formula) ' will work only if the result is a range
On Error GoTo 0 ' errors on
If Not (r Is Nothing) Then
r.Worksheet.Activate
r.Select
End If
End Sub
There are several approaches to select the cell that a formula refers to...
Assume the active cell contains: =INDEX(myrange,x,y).
From the Worksheet, you could try any of these:
Copy the formula from the formula bar and paste into the name box (to the left of the formula bar)
Define the formula as a name, say A. Then type A into the Goto box or (name box)
Insert hyperlink > Existing File or Web page > Address: #INDEX(myrange,x,y)
Adapt the formula to make it a hyperlink: =HYPERLINK("#INDEX(myrange,x,y)")
Or from the VBA editor, either of these should do the trick:
Application.Goto Activecell.FormulaR1C1
Range(Activecell.Formula).Select
Additional Note:
If the cell contains a formula that refers to relative references such as =INDEX(A:A,ROW(),1) the last of these would need some tweaking. (Also see: Excel Evaluate formula error). To allow for this you could try:
Range(Evaluate("cell(""address""," & Mid(ActiveCell.Formula, 2) & ")")).Select
This problem doesn't seem to occur with R1C1 references used in Application.Goto or:
ThisWorkbook.FollowHyperlink "#" & mid(ActiveCell.FormulaR1C1,2)
You could use the MATCH() worksheet function or the VBA FIND() method.
EDIT#1
As you correctly pointed out, INDEX will return a value that may appear many times within the range, but INDEX will always return a value from some fixed spot, say
=INDEX(A1:K100,3,7)
will always give the value in cell G3 so the address is "builtin" to the formula
If, however, we have something like:
=INDEX(A1:K100,Z100,Z101)
Then we would require a macro to parse the formula and evaluate the arguments.
Both #lori_m and #V.B. gave brilliant solutions in their own way almost in parallel.
Very difficult for me to choose the closing answer, but V.B. even created Dropbox test file, so...
Here I just steal the best from parts from them.
'Move to cell found by Index()
Sub GoToIndex()
On Error GoTo ErrorHandler
Application.Goto ActiveCell.FormulaR1C1 ' will work only if the result is a range
Exit Sub
ErrorHandler:
MsgBox ("Active cell does not evaluate to a range")
End Sub
I associated this "jump" macro with CTRL-j and it works like a charm.
If you use balance sheet like worksheets (where INDEX-formulas, selecting entries from other sheets, are very common), I really suggest you to try it.