Checking datatype in excel VBA - excel

I wrote a code that checks whether the entered data is numeric with the isNumeric function. Now i want to specify and check whether it is an Integer. As far as i know, there is no function like isInteger. How can I check the datatype?
I posted a snippet of the code below, I hope it makes sense like this. If not please let me know.
Thank you for your help!
Sub CheckColumnsHardwareDefinition()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Hardware Definition")
Dim Target As Range
Dim Target2 As Range
Dim lr As Long
Dim lr2 As Long
Dim DblLengthMin As Double
Dim DblLengthMax As Double
Dim DblWeightMin As Double
Dim DblWeightMax As Double
Dim dynamicArray1() As String
Dim dynamicArray2() As String
Dim f1 As Integer
Dim f2 As Integer
f1 = 0
f2 = 0
DblLengthMax = 20000
DblLengthMin = 5
DblWeightMin = 0.0001
DblWeightMax = 10000
lr3 = Application.WorksheetFunction.Max( _
ws.Range("A" & ws.Rows.Count).End(xlUp).Row, _
ws.Range("B" & ws.Rows.Count).End(xlUp).Row, _
ws.Range("C" & ws.Rows.Count).End(xlUp).Row, _
ws.Range("D" & ws.Rows.Count).End(xlUp).Row, _
ws.Range("E" & ws.Rows.Count).End(xlUp).Row, _
ws.Range("F" & ws.Rows.Count).End(xlUp).Row)
For Each Target3 In Range("A2:F" & lr3)
If IsEmpty(Target3) Then
Target3.Interior.ColorIndex = 8
End If
Next Target3
lr = Application.WorksheetFunction.Max( _
ws.Range("C" & ws.Rows.Count).End(xlUp).Row, _
ws.Range("D" & ws.Rows.Count).End(xlUp).Row, _
ws.Range("E" & ws.Rows.Count).End(xlUp).Row)
For Each Target In Range("C2:E" & lr)
If **Not IsNumeric(Target)** Then
f1 = f1 + 1
Target.Interior.ColorIndex = 3
ReDim Preserve dynamicArray1(0 To f1)
dynamicArray1(f1) = "Row " & Target.Row & " Column " & Target.Column & " wrong
entry: " & Target.Value
End If
If **IsNumeric(Target)** And Target.Value > DblLengthMax Or Target.Value <
DblLengthMin
Then
f2 = f2 + 1
Target.Interior.ColorIndex = 46
ReDim Preserve dynamicArray2(0 To f2)
dynamicArray2(f2) = "Row " & Target.Row & " Column " & Target.Column & " wrong
entry: " & Target.Value
End If
Next Target
Inhalt1 = Join(dynamicArray1, vbCrLf)
MsgBox ("Wrong datatype! " & vbCrLf & vbCrLf & f1 & " Datatype Errors (marked
red)" & vbCrLf & "Only numbers can be entered. Check again" & vbCrLf & Inhalt1)
Inhalt2 = Join(dynamicArray2, vbCrLf)
MsgBox ("Entries out of range!" & vbCrLf & vbCrLf & f2 & " Range errors (marked
orange)" & vbCrLf & "The value is out of range. Check for unit [mm] " & vbCrLf &
Inhalt2)
End Sub

Let's take advantage of the "internal" casting of VBA
Function isInteger(val As Variant) As Boolean
Dim i As Integer
On Error GoTo EH
i = CInt(val)
If i = val Then ' check if it was cut or not
isInteger = True
Else
isInteger = False
End If
Exit Function
EH:
isInteger = False
End Function
As i was declared as integer i=val will cause an overflow and therefore the result is FALSE for 33000. If you do not want that you have to declare i as long and use CLng()
A short version would look like that
Function isInteger(val As Variant) As Boolean
On Error GoTo EH
isInteger = (val = CInt(val))
Exit Function
EH:
End Function

Related

Data validation for certain columns between other columns only

Hey guys I am trying to change a code that I wrote for an excel vba Data validation tool. This is the first table i used:
Now I have another table with additional variables :
When I reuse the code from the first one (shown below) the columns on the right of length/width and height are also checked. I only want the three columns to be checked. I tried setting the variable lCol to 3 but then only C2 and the values below are checked. How can i apply the code only to the columns B/C/D without including the ones on the right without changing up the code completely?
Any help is appreciated!
Sub CheckColumnsTransportationMean()
Dim rng As Range
Dim lCol As Long, lRow As Long
Dim DblLengthMin As Double
Dim DblLengthMax As Double
Dim dynamicArray1() As String
Dim dynamicArray2() As String
Dim f1 As Integer
Dim f2 As Integer
f1 = 0
f2 = 0
ReDim Preserve dynamicArray1(0)
ReDim Preserve dynamicArray2(0)
DblLengthMax = 20000
DblLengthMin = 5
lCol = Range("C2").End(xltoRight).Column
lRow = Range("C2").End(xlDown).Row
For Each rng In Range("C2", Cells(lRow, lCol))
If IsNumeric(rng) = False Then
f1 = f1 + 1
rng.Interior.ColorIndex = 3
ReDim Preserve dynamicArray1(0 To f1)
dynamicArray1(f1) = "Row " & rng.Row & " Column " & rng.Column & " wrong
entry: " & rng.Value
End If
If IsNumeric(rng) And rng.Value > DblLengthMax Or rng.Value < DblLengthMin Then
f2 = f2 + 1
rng.Interior.ColorIndex = 46
ReDim Preserve dynamicArray2(0 To f2)
dynamicArray2(f2) = "Row " & rng.Row & " Column " & rng.Column & " wrong entry: " &
rng.Value
End If
Next rng
Inhalt1 = Join(dynamicArray1, vbCrLf)
MsgBox ("Wrong datatype! " & vbCrLf & vbCrLf & f1 & " Datatype Errors (marked red)" &
vbCrLf & "Only numbers can be entered. Check again" & vbCrLf & Inhalt1)
Inhalt2 = Join(dynamicArray2, vbCrLf)
MsgBox ("Entries out of range!" & vbCrLf & vbCrLf & f2 & " Range errors (marked
orange)" & vbCrLf & "The value is out of range. Check for unit [mm] " & vbCrLf &
Inhalt2)
End Sub

Paint cells using as reference text within a clicked cell

I have data like this in different cells in column F: 3RG-1S,22,45YM+1W,32VC,23
How can I do to once I click on a cell in column F, in this case, rows 3, 22, 45, 32 and 23 get painted in yellow?
Please help, I've been trying to do this, but I don't know how to use those formulas within VBA
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim celda As Range
Dim rowvalue As Integer
Dim column As Integer
Dim comas As Integer
Dim positioncoma As Integer
Dim newpositioncoma As Integer
Dim contenidocelda As String
Dim i As Long
Dim NumberOfHits As Long
Dim e As Integer
If ActiveCell.value <> "" Then
Range("A1:F500").Interior.ColorIndex = xlNone
Set celda = ActiveCell
column = ActiveCell.column
If column = 6 Then 'Only works when clicking cells in column F
For i = 1 To Len(celda)
If Mid(celda, i, 1) = "," Then
NumberOfHits = NumberOfHits + 1
End If
Next
comas = NumberOfHits 'Gets the number of commas in the selected cell
positioncoma = 0 'counter in zero
If comas <> 0 Then 'Loop to find the first numbers for each value within commas and paint those rows in yellow
For e = 1 To comas
newpositioncoma = "=IFERROR(FIND(" & Chr(34) & "," & Chr(34) & "," & celda & "," & positioncoma & "+1),LEN(" & celda & "))"
contenidocelda = "=MID(" & celda & "," & positioncoma & "+1," & newpositioncoma & "-" & positioncoma & "-1)"
rowvalue = "=LEFT(" & contenidocelda & ", MATCH(FALSE, ISNUMBER(MID(" & contenidocelda & ", ROW(INDIRECT(" & Chr(34) & "1:" & Chr(34) & "&LEN(" & contenidocelda & ")+1)), 1) *1), 0) -1)"
Range("A" & rowvalue & ":F" & rowvalue).Interior.ColorIndex = 36
positioncoma = newpositioncoma
Next e
Else
rowvalue = "=LEFT(celda,MATCH(FALSE,ISNUMBER(MID(celda,ROW(INDIRECT(" & Chr(34) & "1:" & Chr(34) & "&LEN(celda)+1)),1)*1),0)-1)"
End If
Else
Range("A1:F500").Interior.ColorIndex = xlNone 'unpaint cells once click somewhere else
End If
Else
Range("A1:F500").Interior.ColorIndex = xlNone 'unpaint cells if ActiveCell is empty
End If
End Sub
At the moment I'm using the following code that highlights cells but only when I have a simple number as a value. I can't find a way to get the numbers 3, 22, 45, 32 and 23 from a string like this: 3RG-1S,22,45YM+1W,32VC,23.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim rowvalue As Integer
Range("A4:xz90").Interior.ColorIndex = xlNone
If ActiveCell.column = 6 Then
rowvalue = ActiveCell.Row
Range("A" & rowvalue & ":xz" & rowvalue).Interior.ColorIndex = 19
If VarType(ActiveCell.Value) = 5 Then
rowvalue = ActiveCell.Value
Range("A" & rowvalue & ":xz" & rowvalue).Interior.ColorIndex = 35
End If
End If
End Sub
Example of my worksheet and result when I click cell F69
Dim v As Variant
Dim iRow As Long
Range("A1:F500").Interior.ColorIndex = xlNone
For Each v In Split(Range("f1"), ",")
iRow = Val(v)
If iRow > 0 Then
Range(Cells(iRow, "A"), Cells(iRow, "F")).Interior.Color = vbYellow
End If
Next

display only cells with value in Pop Up Form

the macro below takes two cell values (from first and second column)
and displays the column and there cell content in a Pop up Form
Im trying to add the condition that only the column and cell value is displayed if the cell contains value.
something like that =IF(A1<>"",result,"")
but I dont know how to implement that for all cells not only for a specific one.
Option Explicit
Const rangeForSearch = "G2"
Const rowTitles = 4
Dim arrTmp
Dim lastRow As Long, lastColumn As Long
Dim textForSearch As String, textForSearch_withoutSpaces As String
Dim strTmp As String
Dim i As Long, j As Long
Sub searchPerson()
Application.ScreenUpdating = False
With ActiveSheet
textForSearch = .Range(rangeForSearch)
If textForSearch = "" Then
MsgBox "Input text in cell """ & rangeForSearch & """ and try again!", vbCritical
Application.ScreenUpdating = True
Exit Sub
End If
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
lastColumn = .Cells(rowTitles, .Columns.Count).End(xlToLeft).Column
If lastRow <= rowTitles Or lastColumn <= 2 Then
MsgBox "Dataset is wrong! Check it and try again!", vbCritical
Application.ScreenUpdating = True
Exit Sub
End If
arrTmp = .Range(.Cells(rowTitles, "A"), .Cells(lastRow, lastColumn))
End With
'---------------------------------------
textForSearch_withoutSpaces = Replace(textForSearch, " ", "")
For i = LBound(arrTmp, 1) + 1 To UBound(arrTmp, 1)
strTmp = Replace(arrTmp(i, 1) & arrTmp(i, 2), " ", "")
If StrComp(textForSearch_withoutSpaces, strTmp, vbTextCompare) = 0 Then Exit For
Next i
If i = UBound(arrTmp, 1) + 1 Then
strTmp = textForSearch & vbCrLf & vbCrLf & "No dataset!"
Else
strTmp = textForSearch
For j = 3 To lastColumn
strTmp = strTmp & vbCrLf & vbCrLf & arrTmp(1, j) & ": " & arrTmp(i, j)
Next j
End If
Application.ScreenUpdating = True
MsgBox strTmp, , "Result"
End Sub
maybe
For j = 3 To lastColumn
If Not IsEmpty(arrTmp(i, j)) Then strTmp = strTmp & vbCrLf & vbCrLf & arrTmp(1, j) & ": " & arrTmp(i, j)
Next j

VBA Code to add comment only AFTER the INITIAL cell value is changed?

I have a data entry form that let's users enter the data into specific cells. What i want is a way to track changes to the cell values. When the data entered initially through the entry form, i don't want that information to be tracked. However, if the user tries to change/edit the data that was entered then i want to add a comment to show the initial value and the amended one as well.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim singlecell As Range
If Target.Cells.CountLarge > 1000 Then Exit Sub
For Each singlecell In Target
If singlecell.Comment Is Nothing Then
singlecell.AddComment Now & " - " & singlecell.Value & " - " & Environ("UserName")
Else
singlecell.Comment.Text _
vbNewLine & Now & " - " & singlecell.Value & " - " & Environ("UserName") _
, Len(singlecell.Comment.Text) + 1 _
, False
End If
singlecell.Comment.Shape.TextFrame.AutoSize = True
Next singlecell
End Sub
The code i tried adds a comment when the information from the entry form is submitted. However I don't need the comment to show just yet, I only want it when the user changes the initial cell value.
you can use a helper array to temporary store all of current cell comments and get the sensitive text out of the last recorded comment to compare with current cell content
Private Sub Worksheet_Change(ByVal Target As Range)
Dim singleCell As Range
Dim commentsArray As Variant 'array to hold all singleCell comments
Dim oldText As String ' string to hold last comment sensitive content
If Target.Cells.CountLarge > 1000 Then Exit Sub
For Each singleCell In Target
If singleCell.Comment Is Nothing Then
singleCell.AddComment Now & " - " & singleCell.Value & " - " & Environ("UserName")
Else
commentsArray = Split(singleCell.Comment.Text, vbNewLine) ' fill the array with current singleCell comments
oldText = CStr(Split(commentsArray(UBound(commentsArray)), " - ")(1)) ' extract last recorded comment sensitive text
'update comment if current cell value differs from last recorded comment sensitive text
If oldText <> CStr(singleCell.Value2) Then _
singleCell.Comment.Text _
vbNewLine & Now & " - " & singleCell.Value & " - " & Environ("UserName") _
, Len(singleCell.Comment.Text) + 1 _
, False
End If
singleCell.Comment.Shape.TextFrame.AutoSize = True
Next
End Sub
Copy and create the same table in same sheet, have it hidden ,
Sub CopyCurrentTable()
Application.ScreenUpdating = False
With shtMapping
.Range("E4:G1000").ClearContents 'which value to which value you are copying
.Range("B4:D" & GetLastRow(shtMapping, "B", 4)).Copy ' starting postion
.Range("E4").PasteSpecial xlPasteAll
Application.CutCopyMode = False
End With
End Sub
Sub LogAuditTrail()
Dim colOld As Collection
Dim colNew As Collection
Dim objNew As ClsMapping
Dim objOld As ClsMapping
Set colOld = getMappingData("E")
Set colNew = getMappingData("B")
Dim sTS As String
sTS = Format(Now, "dd-mmm-yyy hh:mm:ss")
For Each objNew In colNew
'Detect Items Changed
If ItemIsInCollection(colOld, objNew.getKey) Then
Set objOld = colOld(objNew.getKey)
If objNew.isDifferent(objOld) Then
Call PlotToAudit(objNew, objOld, sTS, "Change")
End If
Else
'Detect Items Added
Set objOld = New ClsMapping
Call PlotToAudit(objNew, objOld, sTS, "New")
End If
Next objNew
'Detect Items removed
For Each objOld In colOld
If Not ItemIsInCollection(colNew, objOld.getKey) Then
Set objNew = New ClsMapping
Call PlotToAudit(objNew, objOld, sTS, "Removed")
End If
Next objOld
End Sub
Sub PlotToAudit(obj1 As ClsMapping, obj2 As ClsMapping, sTS As String, sType As String)
Dim lRow As Long
lRow = shtAudit.Range("B1048576").End(xlUp).Row
If lRow = 3 Then
lRow = 5
ElseIf lRow = 1048576 Then
MsgBox "Audit sheet is full. Contact Support." & vbNewLine & "No audit trail will be saved", vbCritical, "ERROR"
Exit Sub
Else
lRow = lRow + 1
End If
With shtAudit
.Unprotect g_sPassword
.Range("B" & lRow).value = Application.UserName & "(" & Environ("USERNAME") & ")"
.Range("C" & lRow).value = sTS
.Range("D" & lRow).value = sType
Select Case sType
Case "Removed"
.Range("E" & lRow).value = ""
.Range("F" & lRow).value = ""
.Range("G" & lRow).value = ""
.Range("H" & lRow).value = obj2.FundCode
.Range("I" & lRow).value = obj2.Subs
.Range("J" & lRow).value = obj2.Reds
Case "New"
.Range("E" & lRow).value = obj1.FundCode
.Range("F" & lRow).value = obj1.Subs
.Range("G" & lRow).value = obj1.Reds
.Range("H" & lRow).value = ""
.Range("I" & lRow).value = ""
.Range("J" & lRow).value = ""
Case "Change"
.Range("E" & lRow).value = obj1.FundCode
.Range("F" & lRow).value = obj1.Subs
.Range("G" & lRow).value = obj1.Reds
.Range("H" & lRow).value = obj2.FundCode
.Range("I" & lRow).value = obj2.Subs
.Range("J" & lRow).value = obj2.Reds
End Select
With .Range("B" & lRow & ":J" & lRow)
.Interior.Color = vbWhite
.Borders.LineStyle = xlContinuou
End With
.Protect g_sPassword
End With
End Sub

If-Else-Statement in a Loop

My code is to concatenate and compare to a specific field. If it is equal then display it in a message box.
It is working in a single row but when I created a loop there is incorrect output.
Sub postURLGFormat(ByRef msgPostFormat As String)
Dim URG, urgValue, urgCode, contentField, urlgField As String
Dim numRows, i As Long
numRows = Cells(Rows.Count, "A").End(xlUp).Row
contentField = Range("A1").Value
urlgField = Range("J1").Value
URG = "URG" & urgCode
For i = 2 To numRows
urgCode = Cells(i, "A").Value2
If URG = urgValue Then
msgPostFormat = msgPostFormat & Chr(149) & " " & urlgField & " " & URG & " is in proper format and with correct CT" & vbLf
Else
msgPostFormat = msgPostFormat & Chr(149) & " " & contentField & " " & urgCode & " is not aligned in " & urlgField & vbLf
End If
Next i
End Sub
Here is an example loop to do what you need. You had a lot of variables that were not needed (unless you are using them later on that was not shown).
This method will loop through a range as determined by the last used row in Column A. Inside the For Each loop is the string comparison.
Option Explicit
Sub CheckVal()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim MyRange As Range, MyCell As Range
Set MyRange = ws.Range("A2:A" & ws.Range("A" & ws.Rows.Count).End(xlUp).Row)
For Each MyCell In MyRange
If "URG" & MyCell.Text = MyCell.Offset(, 9).Text Then
'Do what you want here with CORRECT format
Else
'Do what you want here with INCORRECT format
End If
Next MyCell
End Sub
Sub postURLGFormat(ByRef msgPostFormat As String)
Dim URG, urgValue, urgCode, contentField, urlgField As String
Dim numRows, i As Long
numRows = Cells(Rows.Count, "A").End(xlUp).Row
contentField = Range("A1").Value
urlgField = Range("J1").Value
For i = 2 To numRows
urgCode = Cells(i, "A").Value2
URG = "URG" & urgCode
If URG = urgValue Then
msgPostFormat = msgPostFormat & Chr(149) & " " & urlgField & " " & URG & " is in proper format and with correct CT" & vbLf
Else
msgPostFormat = msgPostFormat & Chr(149) & " " & contentField & " " & urgCode & " is not aligned in " & urlgField & vbLf
End If
Next i
End Sub

Resources