Finding a value in the range - vba

I am writing a subroutine that looks through a range of cells starting in cell A1 (the range is 1 column wide) containing String values. My sub first finds the entire range and assign it to a Range variable "theForest" to help make searching easier. Then, it looks through each cell in the range until it finds the word “Edward”. If he is found or not, it display the result in a message (stating that he was or was not found).
The code I have so far is this:
With Range("A1")
'this will help find the entire range, since it is only one column I will search by going down
theForest = Range(.Offset(0,0), .End(xlDown)).Select
Dim cell As Range
For Each cell In theForest
If InStr(Edward) Then
Msgbox"He was found"
Else
Msgbox"He was not found sorry"
End If
Next cell
End With
However I am getting numerous errors upon running the program and I think the issue is with the
theForest = Range(.Offset(0,0), .End(xlDown.)).Select
line of code. I would appreciate any guidance into this simple code.
Thank you :)
EDIT: Here is some new code I have come up with:
Dim isFound As Boolean
isFound = False
With Range("A1")
For i = 1 to 500
If .Offset(1,0).Value = "Edward" Then
isFound = True
Exit For
End If
Next
End With
If isFound = True Then
Msgbox " Edward was found"
Else
MsgBox "Edward was not found"
End if
Then again it does not include finding the entire range and assiging it to the range variable theForest.

Dim theForest as Range, f as Range
Set theForest = ActiveSheet.Range(ActiveSheet.Range("A1"), _
ActiveSheet.Range("A1").End(xlDown))
Set f = theForest.Find("Edward", lookat:=xlWhole)
If Not f Is Nothing Then
Msgbox"He was found"
Else
Msgbox"He was not found sorry"
End If

Related

Finding a cell based on the header of a section of data, then selecting the last row of that section

I am attempting to find the text of a header row based on the value of a cell relative to the cell that is clicked in. The way I have attempted to do this is follows:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim var1 As Variant
Dim var2 As Variant
Dim var3 As Variant
Dim FormName As String
FormName = "New Form"
Static NewFormCell As Range
Application.ScreenUpdating = False
If Not Intersect(Target, Range("G16:X80")) Is Nothing Then
If Target.Cells.Count = 1 Then
var1 = Cells(Target.Row, 2).Value
var2 = Cells(15, Target.Column).Value
If Not (IsEmpty(var1)) And Not (IsEmpty(var2)) And var2 <> "+" And Target.Interior.ColorIndex <> 2 And Target.Borders(xlEdgeLeft).LineStyle <> xlNone Then
If IsEmpty(Target) Then
Target.Value = "X"
Target.HorizontalAlignment = xlCenter
Target.VerticalAlignment = xlCenter
Target.Font.Bold = True
Dim Header As Range
Set Header = Range("A54:E160").Find(var2, LookIn:=xlValues)
Header.Offset(1, 1).End(xlDown).EntireRow.Select
Dim CopyCell As Range
'Header.End(xlDown).EntireRow.Insert
'Set CopyCell = Header.End(xlDown). [offset?]
'CopyCell.Value = var1
Else
Target.ClearContents
End If
Else
Exit Sub
End If
End If
End If
Application.ScreenUpdating = True
End Sub
The issue is VBA is throwing Run-Time Error 91 ("Object variable or With block variable not set"). It then highlights the last row in that section of code. Since I set that variable in the previous line, I'm not sure why I'm receiving this error or if I'm even going about this the right way.
Any input would be greatly appreciated!
EDIT: I cleared the above issue by searching over a wider range. The cell I wanted to select was merged, but I still assumed the value was stored within column A. But this code still isn't quite doing what I'd like it to:
I want to select the last row in the section (not the last row of data in the sheet, but the last contiguous data in column B), but right now my code is jumping me all the way to the bottom of the sheet.
The problem is that your .Find isn't finding the value. In this case, you can add some code to handle that.
...
Dim Header As Range
Set Header = Range("A59:A159").Find(var2, LookIn:=xlFormulas)
If Header Is Nothing Then
' There's no value found, so do something...
msgbox(var2 & " was not found in the range, will exit sub now."
Exit Sub
End If
MsgBox Header
...
...of course there are myriad ways/things you can do to handle this. If you still want to execute other code, then wrap everything in an If Header is Nothing Then // 'do something // Else // 'other code // End IF type thing.
It really just depends on what you want to do. Again, your error is being caused by the fact that the var2 isn't being found, so just find other things to do in that case.

Why does autofit row VBA code in Excel keep causing #value error in my formula?

I have a concatenate based on offset array code that I'm using to combine data.
Public Function concatPlusIfs(rng As Range, sep As String, lgCritOffset1 As Long, lgCritOffset2 As Long, varCrit1 As Variant, lgCritOffset3 As Long, lgCritOffset4 As Long, varCrit2 As Variant, Optional noDup As Boolean = False, Optional skipEmpty As Boolean = False) As String
Dim CL As Range, strTemp As String
If noDup Then 'remove duplicates, use collection to avoid them
Dim newRow As New Collection
On Error Resume Next
For Each CL In rng.Cells
If skipEmpty = False Or Len(Trim(CL.Text)) > 0 Then
If CL.Offset(lgCritOffset1, lgCritOffset2) = varCrit1 And CL.Offset(lgCritOffset3, lgCritOffset4) = varCrit2 Then newRow.Add CL.Text, CL.Text
End If
Next
For i = 0 To newRow.Count
strTemp = strTemp & newRow(i) & sep
Next
Else
For Each CL In rng.Cells
If skipEmpty = False Or Len(Trim(CL.Text)) > 0 Then
If CL.Offset(lgCritOffset1, lgCritOffset2) = varCrit1 And CL.Offset(lgCritOffset3, lgCritOffset4) = varCrit2 Then strTemp = strTemp & CL.Text & sep
End If
Next
End If
concatPlusIfs = Left(strTemp, Len(strTemp) - Len(sep))
End Function
The code works great. It's not mine, but I tweaked someone else's code. The problem is that it will sometimes return a small amount of text and other times a large amount of text. I need the rows to autofit height. Before I started using the new concatPlusIfs formula, I used a code on the worksheet to autofit row height, but it cause a weird problem with the above code and only the above code and I can't find any mention of this type of problem. It works fine with all other arrays or non array formulas that I'm using. Basically what happens is that for a fraction of a second I can see the correct output in the cell and then I get #value!. I have no idea what's going on. I've tried autofit rows as a macro instead and it had the same effect. If I manually autofit the row everything is fine, but that's not a viable option.
Does anyone understand what would cause a problem like this? Or How can I fix it?
I'm not using any merged rows anywhere on the sheet.
Here are a few of the autofit strategies I've tried. One as a macro:
Sub AutoFit()
Worksheets("Sheet1").Range("A2:A" & Rows.Count).Rows.AutoFit
End Sub
Also as a code on the sheet,
Private Sub Worksheet_Change(ByVal Target As Range)
Target.EntireRow.AutoFit
End Sub
And,
Private Sub Worksheet_Calculate()
Application.EnableEvents = False
Me.Rows.AutoFit
'or be specific
Me.Rows("1:33").AutoFit
Application.EnableEvents = True
End Sub
Thank you for any help with this.
You most likely get #VALUE! error when your formula tries to convert the ### from the .Text property to value. That is why you should use .Value2 or .Value instead.

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

someExcel VBA: Cannot create a range object successfully

This is my first question here, so bear with me. I'm a security consultant working on a huge firewall migration, for which I got my VBA skill from under a thick layer of dust. So far I have managed to get all my issues resolved by searching, but this issue: I get errors when doing exactly how I find it everywhere.
What I want to do:
I have an array that contains (among other things), strings formatted like this: "A3:P59", representing a cell range.
Now, this are ranges within a table. When I get the address of a certain cell in the table, I want to test if it's in that range.
I wrote a test function:
Function TestCellRange() As Boolean
Dim tbl As ListObject
Dim cell, rng, test As range
Dim range As range
Dim bRow, eRow As Integer
Set tbl = shRulebase.ListObjects("tblBFFirewallRules")
shRulebase.Activate
With shRulebase
cell = tbl.DataBodyRange(5, 1).Address(False, False) 'it's this command that gives me issues
Set range = .range(.Cells(bRow, 1), .Cells(eRow, 16))
Debug.Print cell
'Set rng = shRulebase.range(range)
Debug.Print rng
Set test = Application.Intersect(cell, range(range(A3), range(P59)))
If test Is Nothing Then
MsgBox ("oops")
TestCellRange = False
Else
MsgBox ("yup yup")
TestCellRange = True
End If
End With
End Function
Now whatever I try, I keep getting blocked on the set range:
set range = .Range("A3:P59") -> will return "object required", on the "set test" line (if i use intersect (cell, range))
Set range = range("A3:P59") -> will return object variable or with block variale not set on the same line
Set range = .range(.Cells(bRow, 1), .Cells(eRow, 16)) -> will step through, but debug.print returns a type mismatch and "Set test = Application.Intersect(cell, range)" returns a "object required"
Any help would be really appreciated...I'm all to familiar with networks ip's and the bits and bytes of it, but here I am a bit out of my comfort zone and I need to finish this by tomorrow :(
Greetings,
Kraganov
EDIT Some More tries:
rng and cell as variant:
cell = tbl.DataBodyRange(5, 1).Address(False, False)
rng = .range("A3:P59").Address(False, False)
Set test = Application.Intersect(cell, rng)
==>I would get objects required
just using rng as range and trying to set it without "set"
rng = .range("A3:P59")
EDIT 2 : I found a way around using the range.
So what I was trying to do, was the following:
I had a table that contains information about firewall rules. However, not every line describes a rule. There are also lines that described the context in which the rules below that line were to be placed.
Outside of the table, aside of those lines there would be a cell with the range of cells for that context. I wanted to use that to describe the context for those rules, if I pulled them.
I ended up looping through the table rows and identifying those specific rows and setting a "context" variable when, a row like that was met.
Try setting the cell as well as following:
set cell = tbl.DataBodyRange(5, 1).Address(False, False)
What is cell? A Range?
You do not need to add 'set' to the range value assignment.
Try just
range = .Range("A3:P59")
Function TestCellRange() As Boolean
Dim tbl As ListObject
Dim cellToTest As Range
Dim testResult As Range
Set tbl = shRulebase.ListObjects("tblBFFirewallRules")
Set cellToTest = tbl.DataBodyRange.Cells(5, 1)
'or with one more level of indirection
'Set cellToTest = shRulebase.range(tbl.DataBodyRange.Cells(5, 1).Value)
Set testResult = Application.Intersect(cellToTest, [A3:P59])
If testResult Is Nothing Then
MsgBox ("oops")
TestCellRange = False
Else
MsgBox ("yup yup")
TestCellRange = True
End If
End Function
Thanks to the post of VincentG I found the working solution. Thanks for that.
Function TestCellRange() As Boolean
Dim tbl As ListObject
Dim cellToTest As range
Dim testResult As range
Set tbl = shRulebase.ListObjects("tblBFFirewallRules")
shRulebase.Activate
Set cellToTest = tbl.DataBodyRange.Cells(5, 1)
'or with one more level of indirection
'Set cellToTest = shRulebase.range(tbl.DataBodyRange.Cells(5, 1).Value)
Set testResult = Application.Intersect(cellToTest, range("A3:P59"))
If testResult Is Nothing Then
MsgBox ("oops")
TestCellRange = False
Else
MsgBox ("yup yup")
TestCellRange = True
End If
End Function

VBA Record date of row change in specific column

I'm trying to automatically update the "Updated" column of an excel spreadsheet when any cell of that specific row changes to today's date. I was able to do this by hard-coding where the "Updated" column header would be, however, it is now necessary to search for that column header as it may move.
The code I am trying to implement works but immediately gives me the error Automation error - The object invoked has disconnected from it's clients.
Any help would be appreciated. Here is the code I have currently:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("A:DX")) Is Nothing Then
Dim f As Range
Set f = ActiveSheet.Range("A1:DD1").Find("Updated", lookat:=xlWhole)
' f.Row = Range(Target).Row
If Not f Is Nothing Then
Range(Split(f.Address, "$")(1) & Target.Row).Value = Now
Else
MsgBox "'Updated' header not found!"
End If
End If
End Sub
You got into an endless loop.
Try this:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("A:DX")) Is Nothing Then
Dim f As Range
Set f = ActiveSheet.Range("A1:DD1").Find("Updated", lookat:=xlWhole)
' f.Row = Range(Target).Row
If f Is Nothing Then
MsgBox "'Updated' header not found!"
ElseIf Intersect(Target, f.EntireColumn) Is Nothing Then
Intersect(Target.EntireRow, f.EntireColumn).Value = Now
' Else
' MsgBox "We entered this function again because the row above updated the Updated column", vbInformation, "False alarm"
End If
End If
End Sub
To understand what happens,
Uncomment the else and MsgBox
Put a breakpoint on the MsgBox
When you hit it, press [ctrl]-L
In a case such as this, I run into far fewer problems when I simply loop through the available cells to find the column header. Using the .Find method also works, but is less "tunable" to my needs in a custom application.
Public Function FindColumn(header As String) As Long
Dim lastCol As Long
Dim headerCol As Long
Dim i As Long
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("VTO2 Labor")
lastCol = sh.Cells(1, sh.Columns.Count).End(xlToLeft).Column
headerCol = 0
For i = 1 To lastCol
If sh.Cells(1, i).Value = header Then
headerCol = i
End If
Next i
FindColumn = headerCol
End Function
It isn't clear on whether the Updated column header could be in row 1 or if it will always be in row 1, just not in the same location.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("A:DX")) Is Nothing Then
On Error GoTo bm_SafeExit
'TURN OFF EVENTS IF YOU ARE GOING TO WRITE A VALUE INTO THE WORKSHEET!
Application.EnableEvents = False
Dim uCol As Long, f As Range
If Application.CountIf(Rows(1), "updated") Then
uCol = Application.Match("updated", Rows(1), 0)
For Each f In Intersect(Target, Range("A:DX"))
If f.Row > 1 Then _
Cells(f.Row, uCol) = Now
Next f
Else
MsgBox "'Updated' header not found!"
End If
End If
bm_SafeExit:
Application.EnableEvents = True
End Sub
That should survive multiple updates (e.g. when pasting values). The problem I see is that is the Updated column is being shifted around, presumably through inserting columns or the like, then the change routine is going to run.