VBA Range.value function causing unexpected end - vba

This must seem like a terribly simple question, but I cannot figure out why my functions are ending unexpectedly on the Range.value = val call. Perhaps I am missing something very basic, but I have tested these out and each one of them are failing to resolve to anything and I don't know how to capture the error.
Here is the initial function:
Function incrementCount(upper As Range, Summed As Range, ParamArray sums() As Variant)
Dim deduct As Integer
Dim summation As Integer
Dim elem As Variant
Dim i As Long
Dim temp As Range
up = upper.Value
summation = Summed.Value
'Initialize the starting points of the increments
For i = LBound(sums) To UBound(sums)
MsgBox IsObject(sums(i)) 'Prints out as an true
MsgBox TypeName(sums(i)) 'Prints out as Rnage
MsgBox sums(i).Value 'Prints out as 0
Set temp = sums(i)
MsgBox temp.Value 'Prints out as 0
Set temp = Summed
MsgBox temp.Value 'Prints out as 1 (which is correct)
temp.value = 3 'Errors here
MsgBox temp.Value 'Never makes it to this line
sums(i).Value = 1 'I have also tried this with the same result
Next i
<more code that is never reached>
End Function
I am at my wits end. I have searched MSDN, stackoverflow, and all the many excel forums and all of them show setting values to a range like this. I have even separated the setting of a range value to a different function like this:
Function testsub(thecell As Range, thevalue As Integer)
thecell.value = thevalue
End Function
Ultimately i would like to be able to do something like discussed in this article where I loop over a random assortment of ranges and will increment them. Any help at all would be greatly appreciated.

You have not specified how IncrementCount() is being called.
If your function is being called from a worksheet cell, then it is "bombing out" at the correct line. A UDF called from a cell cannot modify the contents of other cells, it can only return a value.

Related

Which Loop function would better suit to read the cells and get the total?

I have a table with a few cells in blank and the other ones filled in. The ones filled I read as value 12 which I'll later sum up for each row and add to the last column as Total.
At first, I thought on doing a function to read the cells filled in as value = 12 and add to a counter, then create a sub to put the total on the last column. This is the idea of function I had in mind.
Public Function TestValue(ByRef rRng as Range) As Long
Dim rCell as Range
Dim lCont as Long
For Each rCell in rRng.Cells
If isEmpty(rCell.Value) = False then
lCont = lCont + 12
Else
End If
Next rCell
TestValue = lCont
End Function
I came up with a Do While just so you can have an idea on what I'm trying to do.
Public Sub Test()
Do
ActiveSheet.Range("I2:I8").Value = TestValue
Loop While isEmpty(Range("I2:I8")) = False
End Sub
For Each is the less human-error prone loop. I find it's easy to accidentally write an infinite loop in the Do While format For example norie mention's in the comments that this example should get stuck in an infinite loop: IsEmpty(Range("I2:I8")) won't work here - it will always return False
Does it need to be VBA? You could do this with a simple formula.
=COUNTA(I2:I8)*12

VLookUp not working - Property could not be assigned

My problem is, that when using the VlookUp I do get the Error:
The VLookup-Property of the WorksheetFunction-Object could not be assigned
' LookUp missing Data
Dim lookupRange As Range
Set lookupRange = Sheets("Kundenlisten HLK 2018").Range("A1:Y10354")
' Fill in Companyname
Dim tmp As String
tmp = Values(0)
tmp = TrueTrim(tmp)
testing.Cells(8, counter) = Application.WorksheetFunction.VLookup(tmp, lookupWS.Range("A2:Y10354"), 2, False)
Values = None
counter = counter + 1
lookupWS is the Name of the Worksheet
As you can see the table I am trying to lookup is filled with values from A to Y. The first column is the key I am trying to look up, but then the error from above occurs. The tmp variable is a String with a unique ID to look up the missing values, while the "2" is supposed to be the company name in the second column of the Range.
I looked up on the docs, but the types and everything are fine, I even checked while debugging.
testing.Cells(8, counter) can't be the source of the problem aswell, since I am using it before like this
testing.Cells(28, counter) = Left(mail.ReceivedTime, 10)
and it works
It's difficult to know what the problem is without any data, but here's something to help you in the right direction.
It's better to use Find and Offset than
WorksheetFunction.Vlookup in VBA
Something like this gives you exactly the same result, but you have much more control:
Sub Test()
Dim valueFound As Range
Set valueFound = lookupWS.Range("A2:A10354").Find(What:="Something", lookat:=xlWhole) 'xlWhole is equivalent to FALSE in VLOOKUP
If valueFound Is Nothing Then
MsgBox "Nothing found"
Else
MsgBox valueFound.Offset(0, 1) 'offsetting by 1 is equivalent to using 2 in a VLOOKUP
End If
End Sub

Making a CountRows function in Excel

I am trying to make a simple countRows function that will count the number of cells I have in a dynamic range. Basically if I have values in cells, say B2:B500, the count would return 499. However next time around values are in cell B2:B501, the count would return 500. But you wouldn't have to do anything to the cell in which you typed in the formula.
I thought if I reference the cell as a Variant, then any value could be accepted. Then find the Address of that cell and return the Count of a Range. But I get a #Value error.
Public Function countRows(startRange As Variant)
Dim rng As Range
Set rng = startRange.Address
If IsEmpty(Range(rng, rng.End(xlDown))) = True Then
countRows = 1
Else
countRows = Range(rng, rng.End(xlDown)).Rows.Count
End If
End Function
This is the code I have used for many years successfully under many different worksheets. It handles many cells, singular cells or empty cells.
Public Function CountRows(ByRef r As Range) As Long
If IsEmpty(r) Then
CountRows = 0
ElseIf IsEmpty(r.Offset(1, 0)) Then
CountRows = 1
Else
CountRows = r.Worksheet.Range(r, r.End(xlDown)).Rows.count
End If
End Function
Public Function CountCols(ByRef r As Range) As Long
If IsEmpty(r) Then
CountCols = 0
ElseIf IsEmpty(r.Offset(0, 1)) Then
CountCols = 1
Else
CountCols = r.Worksheet.Range(r, r.End(xlToRight)).Columns.count
End If
End Function
It's not entirely clear what you are looking for, when you mentioned there are values in cells "B2:B500" and the count should return 499, as there could be a few possible scenarios:
You simply want to count the rows in the range "B2:B500". The code will be:
Range("B2:B500").Rows.Count
You want to count the non-blank cells in the range "B2:B500". In that case, as suggested in the comments:
WorksheetFunction.CountA(Range("B2:B500"))
As indicated in your code rng.End(xlDown), you probably want to the count continuous non-blank cells starting with the range "B2" in the overall range "B2:B500". You may create a function like this:
Public Function countRows(rng As Range) As Long
Dim rw As Range
For Each rw In rng
If IsEmpty(rw) Then Exit For
countRows = countRows + 1
Next
End Function
Clarification:
Based on subsequent comments, I thought it's worth explaining why the variable "countRows" wasn't initialized by adding a line countRows = 0.
Certain programming languages like assembly language, C, C++ require explicit initialization. This was intentionally so designed due to the philosophy in which conflicts between performance and safety were generally resolved in favor of performance.
However, such is not the case with other programming languages like VBA or Java.
Speaking about VBA, during macro run, all the variables are initialized to a value. A numeric variable is initialized to zero, a variable length string is initialized to a zero-length string (""), and a fixed length string is filled with the ASCII code 0. Variant variables are initialized to Empty. An Empty variable is represented by a zero in a numeric context and a zero-length string ("") in a string context.
Therefore a separate line of code countRows = 0 wasn't added in the above code block.
While coding, one need to keep this in perspective as the same might not be true for other languages.

How do I find a value in a row and return the column number with VBA?

My excel sheet is filled with zeroes except for one cell in every row.
I want to find that cell and return the column.
For example: In the cell T616 is a value other than 0. May it be -15400.
I want to find that cell(T616) based on the row(616) and have the column returned(T). May it even be in a MsgBox.
This is my result of many tries and long Google-sessions:
Public Function find_Column(lRange As Range, lValue As String) As Integer
Dim vCell As Range
For Each vCell In lRange.Cells
If vCell.Value = lValue Then
find_Column = vCell.Column
MsgBox (find_Column)
Exit Function
End If
Next vCell
End Function
I found this code somewhere and modified it a little bit, but I can't remember where. So thanks to the creator!
How do I search for a number other than 0?
I'm relatively new to VBA and don't really have an idea what I am doing. Sorry for my bad English (foreigner). I'd appreciate any help. Thank you!
Try this:
Public Function findNonZeroValueInColumn(lRange As Range) As Integer
Dim vCell As Range
For Each vCell In lRange.Cells
If vCell.Value <> 0 Then
find_Column = vCell.Column
Exit Function
End If
Next vCell
End Function
Sub ShowValue()
call MsgBox(findNonZeroValueInColumn(Range("A:A")))
End Sub
Remember that Functions are supposed to return values. Subs (Procedures) do not return values.
The <> symbol is the "Not Equal" Comparison. So if you wanted to check if a cell didn't equal 0, you would write
If vCell.Value <> 0 Then
... ' rest of code here
In your problem:
Public Function find_Column(lRange As Range) As Integer
Dim vCell As Range
For Each vCell In lRange.Cells
If vCell.Value <> 0 Then
find_Column = vCell.Column
MsgBox (find_Column)
Exit Function
End If
Next vCell
End Function
Also since you are only checking against 0, you wouldn't need the extra lValue As String argument.
As the other part of your question has been answered while I was typing, if you want to return the column letter instead of the number...
find_Column = Replace(Replace(vCell.Address, vCell.Row, ""), "$", "")
If this is what you want the function to return, you would have to change the type your function is returning to string

Looping Word Match Function in Excel VBA

I have a list of keywords and want to see if one cell contains any one of these words. For example if my list of keywords is (Cat, Dog, Turtle) the function would return MATCH if it was looking inside "Mr. Dogs Magic Land". I have found a good UDF online to use as the function but when I try to loop it so it tests every word on my keyword list I get #VALUE!. The first function is my loop while the second is the UDF match function found on the internet (sorry don't remember where but props to whoever made it.) I've tried variations of word match functions such as InStr to no avail.
Function StringFind(rng(), source)
For I = LBound(rng) To UBound(rng)
StringFind = MyMatch(rng(I), source)
If StringFind = "MATCH" Then Exit Function
Next I
StringFind = "NO MATCH"
End Function
Function MyMatch(FindText As String, WithinText As Variant) As String
'
Dim vntFind As Variant
Dim vntWithin As Variant
For Each vntFind In Split(UCase(FindText), " ")
If Len(Trim(vntFind)) > 0 Then
For Each vntWithin In Split(UCase(WithinText), " ")
If Len(Trim(vntWithin)) > 0 Then
If vntFind = vntWithin Then
MyMatch = "MATCH"
Exit Function
End If
End If
Next
End If
Next
MyMatch = "NO MATCH"
End Function
1) FORMULA
I would first offer the non-VBA solution to this particular problem since VBA isn't really needed. This array formula will do the same thing. Enter the array by pressing CTRL-SHIFT-ENTER, you'll see the curly braces { } appear around your formula. Then you can copy down.
'=IF(OR(ISNUMBER(SEARCH($F$1:$F$3, A1))), "Match", "No Match")
2) UDF
Using the same syntax as yours, here's how I might approach this with a UDF.
Function MySearch(MyRNG As Range, MyStr As String) As String
Dim cell As Range
For Each cell In MyRNG
If LCase(MyStr) Like LCase("*" & cell & "*") Then
MySearch = "Match"
Exit Function
End If
Next cell
MySearch = "No Match"
End Function
Plugged this in as-is in my VBE, and I couldn't even compile.
This line
StringFind = MyMatch(rng(I), source)
needs to be changed to
StringFind = MyMatch(rng(I).Value, source)
to even get it to work for me. This MAY be the cause of your problem.
EDIT
Ok, I reviewed all in more detail. It looks like this will work for you. (Sorry, I didn't mean to just do it all for you, but here it is.) It probably needs some more tweaking to make it work for your needs.
The problem was that you were looking for undefined data types (added/changed main function call to As String and As Range). While the undefined types can work, I think it was confusing in seeing why the problem was coming up. I tried to set a breakpoint in the function and never even got that far because the wrong data type was being passed. Personally, I always use Option Explicit to help prevent issues like this from arising in my own code.
The below code will now look for the value in the first argument(Search, can be a "" text/String or a single cell/Range) against all the values in the second argument (Source a Range consisting of either a single or multiple cells).
Public Function StringFind(Search As String, Source As Range)
Dim rngCell As Range
For Each rngCell In Source.Cells
StringFind = MyMatch(Search, rngCell.Value)
If StringFind = "MATCH" Then Exit Function
Next rngCell
StringFind = "NO MATCH"
End Function
Function MyMatch(FindText As String, WithinText As Variant) As String
'
Dim vntFind As Variant
For Each vntFind In Split(UCase(FindText), " ")
If Len(Trim(vntFind)) > 0 Then
If vntFind = Trim(UCase(WithinText)) Then
MyMatch = "MATCH"
Exit Function
End If
End If
Next
MyMatch = "NO MATCH"
End Function