I have a macro enabled work sheet in which i have data validations for columns where i want to regulate the data input. I cannot use regular data validation feature in excel as it fails to function as we copy data from other sources which is the case in my requirement.So i am implementing data validations through macros . I have a scenario where one column can input only decimal data. The conditions are as follows the input data is of length 9 which constitutes only 2 decimal positions. I have partly written a macro for this validation which does not work(When i make a invalid input macro is not triggered therefore no msgbox pop up) and i am stuck at this point.Please help me out here to find a different if condition for the validation. The macro i have written is as follows:
Set AffectedCells = Intersect(Target, Target.Parent.Range("F:F"))
If Not AffectedCells Is Nothing Then
For Each Cell In AffectedCells
If Not (Cell.Value * (10 ^ 2) Mod 10) <> 0 Then
MsgBox "The value you entered is not valid."
Application.Undo 'undo insert
Exit Sub 'stop checking after one invalid data was found.
End If
This needs to be pasted on the sheet code space for the sheet you want the macro to run on.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim xCell As Range, AffectedCells As Range
Set AffectedCells = Intersect(Target, Target.Parent.Range("F:F"))
If Not AffectedCells Is Nothing Then
For Each xCell In AffectedCells
If Not (xCell.Value * (10 ^ 2) Mod 10) <> 0 Then
MsgBox "The value you entered is not valid."
Application.EnableEvents = False
Application.Undo
Application.EnableEvents = True
Exit Sub
End If
Next xCell
End If
End Sub
Is this what you are trying? I have commented the code so you should not have a problem undrstanding it. But if you do then simply ask.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim xCell As Range, AffectedCells As Range
On Error GoTo Whoa
Application.EnableEvents = False
Set AffectedCells = Intersect(Target, Columns(6))
If Not AffectedCells Is Nothing Then
For Each xCell In AffectedCells
'~~> Avoid cases like IP address 10.1.2.234
'~~> Check if the number contains decimal
If IsNumeric(xCell.Value) And _
Int(xCell.Value) <> xCell.Value Then
'~~> Check the position of the decimal
'~~> Check the length of the string
If Mid(xCell.Value, Len(xCell.Value) - 2, 1) <> "." Or _
Len(xCell.Value) > 9 Then
'
'~~> INVALID INPUT: Do what you want
'
'MsgBox "The value you entered is not valid."
'Application.Undo
'Exit For
End If
End If
Next xCell
End If
Letscontinue:
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume Letscontinue
End Sub
Related
Can someone please help me with this code. It will insert the current date in H if I do any changes to I.
My problem is that this will not work if for example I fill in I1 with something, and then I drag down for copying in many cells at once. If for example I copy value from I1 once at a time in each cell( I2,I3 ETC) it will work.
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
'Updated by Extendoffice 2017/10/12
Dim xRg As Range, xCell As Range
On Error Resume Next
If (Target.Count = 1) Then
If (Not Application.Intersect(Target, Me.Range("I:I")) Is Nothing) Then _
Target.Offset(0, -1) = Date
Application.EnableEvents = False
Set xRg = Application.Intersect(Target.Dependents, Me.Range("I:I10"))
If (Not xRg Is Nothing) Then
For Each xCell In xRg
xCell.Offset(0, -1) = Date
Next
End If
Application.EnableEvents = True
End If
End Sub
Thank you !
Avoid the unnecessary use of On Error Resume Next. Handle the Error gracefully. I recommend reading THIS once when using Worksheet_Change
Also you have If (Target.Count = 1) Then because of which your code doesn't execute. When you drag, the count increases.
Is this what you are trying?
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo Whoa
Dim aCell As Range
Application.EnableEvents = False
If Not Intersect(Target, Range("I:I")) Is Nothing Then
For Each aCell In Target
'~~> Additional blank check for I. So that the date
'~~> is not inserted if the value is deleted. Remove this
'~~> if you want the date to be inserted even when the value is deleted
If Len(Trim(aCell.Value)) <> 0 Then
Range("H" & aCell.Row).Value = Date
Else
'Remove Date?
End If
Next aCell
End If
Letscontinue:
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume Letscontinue
End Sub
In action:
I have a column named "time" in my excel sheet. I want to write a code such that whenever user performs an entry in time column, if it is a whole number, it should accept, but if it is not a pop up should appear saying "only numbers allowed". Also, the validation should be dynamic i.e. should automatically validate next row if users enters a new entry
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Target.Column = Range("Meeting Time").Column Then
If Not (IsNumeric(Target.Value)) Then
MsgBox "only numbers allowed"
Target.Value = ""
Target.Select
End If
End If
End Sub
You could try:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
'1. Check if the column that affected is B (change to the column you want)
'2. Check if changed field is one (used to avoid errors if user change more than one cells at the same time)
If Not Intersect(Target, Columns("B:B")) Is Nothing And Target.Count = 1 Then
'Check if target is numeric
If Not IsNumeric(Target.Value) Then
Call Clear(Target)
End If
'Check if target.offset(1,0) is numeric
If Not IsNumeric(Target.Offset(1, 0).Value) Then
Call Clear(Target.Offset(1, 0))
End If
End If
End Sub
Sub Clear(ByVal rng As Range)
'Disable events in order to prevent code to re trigger when clear cell
Application.EnableEvents = False
rng.Value = ""
'Enable events
Application.EnableEvents = True
End Sub
EDITED VERSION:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
'1. Check if the column that affected is B (change to the column you want)
'2. Check if changed field is one (used to avoid errors if user change more than one cells at the same time)
If Not Intersect(Target, Columns("B:B")) Is Nothing And Target.Count = 1 Then
'Check if target is numeric
If Not IsNumeric(Target.Value) Then
Call Clear(Target)
ElseIf Target.Value > 160 Or (Target.Value = Int(Target.Value) = False) Then
Call Clear(Target)
End If
'Check if target.offset(1,0) is numeric
If Not IsNumeric(Target.Offset(1, 0).Value) Then
Call Clear(Target.Offset(1, 0))
ElseIf Target.Offset(1, 0).Value > 160 Or (Target.Offset(1, 0).Value = Int(Target.Offset(1, 0).Value) = False) Then
Call Clear(Target)
End If
End If
End Sub
Sub Clear(ByVal rng As Range)
'Disable events in order to prevent code to re trigger when clear cell
Application.EnableEvents = False
rng.Value = ""
'Enable events
Application.EnableEvents = True
End Sub
first you can create a range name for column you want your "time" and you can use the sample codes below.
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Target.Column = Range("time").Column Then
If Not (IsNumeric(Target.Value)) Then
MsgBox "only numbers allowed"
Target.Value = ""
Target.Select
End If
End If
End Sub
I have a trigger that I want to use in certain worksheet - just inside 2 specific columns. But whan I enter a value inside another range it triggers the Private Sub of that worksheet.
I want it would start to work just whan I cange value within columns E or H.
Is someone knows how to do it right?
Private Sub Worksheet_Change(ByVal Target As Range)
Dim LR As Long
Dim rng1 As Range
Dim rng2 As Range
'WE WANT TO KEEP THE TARGET COLUMNS BETWEEN 0% TO 100%
LR = Cells(Rows.Count, "A").End(xlUp).Row
Set rng1 = Intersect(Target, Range(Cells(2, "E"), Cells(LR, "E")))
On Error GoTo 1
If Target.Value < 0 Or Target.Value > 1 Then
MsgBox "bla bla bla", vbCritical + vbMsgBoxRtlReading + vbMsgBoxRight, "error"
Target.Value = 0
Exit Sub
End If
On Error GoTo 1
Set rng2 = Intersect(Target, Range(Cells(2, "H"), Cells(LR, "H")))
If Target.Value < 0 Or Target.Value > 1 Then
MsgBox "bla bla bla", vbCritical + vbMsgBoxRtlReading + vbMsgBoxRight, "error"
Target.Value = 0
Exit Sub
End If
1
End Sub
You just need to check if Target intersects with your desired range. I would Union the two columns together in this check.
As cryptically stated by DisplayName, since Target can contain more than one cell, you should check each cell in target individually. Alternatively, if your intention for Target was to always have one cell, then you can avoid the For...Each statement altogether and use this check: If Target.Cells.Count > 1 Then Exit Sub to not run the procedure when more than 1 cell is changed.
I also added another intersect target, Me.Rows("2:" & rows.count) to avoid updating any headers you may have. If your data does not contain headers, then you can remove this range from Intersect().
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo safeExit
Dim rngIntersect As Range
Set rngIntersect = Intersect(Target, Union(Me.Columns("E"), Me.Columns("H")), _
Me.Rows("2:" & Rows.Count))
If Not rngIntersect Is Nothing Then
Application.EnableEvents = False
Dim cel As Range
For Each cel In rngIntersect
If cel.Value < 0 Or cel.Value > 1 Then
MsgBox "bla bla bla", vbCritical + vbMsgBoxRtlReading + vbMsgBoxRight, _
"error"
cel.Value = 0
End If
Next cel
End If
safeExit:
Application.EnableEvents = True
End Sub
As a side note, when you are using the same exact range more than once, it's not a bad idea to go ahead and set that range to a variable. So, we use rngIntersect twice in this code, so this prevents us from having to issue multiple calls to the Intersect() and Union() functions. On top of that, you run into less debugging headaches when you only have to update the range in one place rather than multiple times in your code.
The intersect can check if any of the cells in Target (yes, Target can be more than a single cell) intersect with the Union of columns E and H.
Private Sub Worksheet_Change(ByVal Target As Range)
' this next line could also be,
'If Not Intersect(Target, Range("E:E, H:H")) Is Nothing Then
If Not Intersect(Target, Union(Range("E:E"), Range("H:H"))) Is Nothing Then
On Error GoTo bye_bye
Application.EnableEvents = False
Dim t As Range
For Each t In Intersect(Target, Union(Range("E:E"), Range("H:H")))
If (t.Value2 < 0 Or t.Value2 > 1) And t.Row > 1 Then
MsgBox "bla bla bla", vbCritical + vbMsgBoxRtlReading + vbMsgBoxRight, "error"
t = 0
End If
Next t
End If
bye_bye:
Application.EnableEvents = True
End Sub
I have to macro
one for changing the text in rang to uppercase and the other one for clear rang content.
This the first one
Private Sub Worksheet_Change(ByVal Target As Range)
If Not (Application.Intersect(Target, Range("B9:B28")) _
Is Nothing) Then
With Target
If Not .HasFormula Then
Application.EnableEvents = False
.Value = UCase(.Value)
Application.EnableEvents = True
End If
End With
End If
End Sub
It work fine and when I enter a value it changes it to uppercase, But when I run this macro to clear range content
Sub clearCellContentsKeepFormatting()
Dim Answer As VbMsgBoxResult
Answer = MsgBox("Are you sure about this?", vbYesNo + vbQuestion, "Clear All Proudcts")
If Answer = vbYes Then
Range("B9", "B28").ClearContents
Range("C9", "C28").ClearContents
Else
Exit Sub
End If
End Sub
I get
Runtime Error 13 type mismatch
And when I press debug button it marks this line
.Value = UCase(.Value)
So, How can I fix that?
It's happening because .Value is an array if the target range has more than one cell, and you cant call UCase on an array.
You could get round this by processing each cell one at a time:
Dim c As Range
With Target
If Not .HasFormula Then
Application.EnableEvents = False
For Each c In Target
c.Value = UCase(c.Value)
Next c
Application.EnableEvents = True
End If
End With
though this will have a performance impact.
Another point is that you appear to be attempting to set the whole of the Target range to upper case, not only the part that overlaps with B9:B28. If you only want B9:B28 to be forced to upper case, you need something like:
Dim rngIntersection As Range
Set rngIntersection = Application.Intersect(Target, Range("B9:B28"))
If Not (rngIntersection Is Nothing) Then
Dim c As Range
With rngIntersection
If Not .HasFormula Then
Application.EnableEvents = False
For Each c In rngIntersection
c.Value = UCase(c.Value)
Next c
Application.EnableEvents = True
End If
End With
End If
I have code that retrieves information from SQL and VFP and populates a dropdown list in every cell in column "A" except A1 - this is a header.
I need to populate the "G" column on the row where the user selects the value from a dropdown in the "A" column.
I believe I need to be in Private Sub Worksheet_SelectionChange(ByVal Target As Range) which is in the sheet object.
Below is something similar to what I want to do.
If cell "a2".valuechanged then
Set "g2" = "8000"
End if
If cell "a3".valueChanged then
Set "g3" = "8000"
End if
The code above doesn't work, but I think it is easy to understand. I want to make this dynamic, so I don't have too many lines of code.
I have already explained about events and other things that you need to take care when working with Worksheet_Change HERE
You need to use Intersect with Worksheet_Change to check which cell the user made changes to.
Is this what you are trying?
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo Whoa
'~~> Check if user has selected more than one cell
If Target.Cells.CountLarge > 1 Then Exit Sub
Application.EnableEvents = False
'~~> Check if the user made any changes in Col A
If Not Intersect(Target, Columns(1)) Is Nothing Then
'~~> Ensure it is not in row 1
If Target.Row > 1 Then
'~~> Write to relevant cell in Col G
Range("G" & Target.Row).Value = 8000
End If
End If
Letscontinue:
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume Letscontinue
End Sub
Try this
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Row > 1 And Target.Column <> 7 Then
Cells(Target.Row, "G").Value = 8000
End If
End Sub
If you only need it to fire on column A then
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Row > 1 And Target.Column = 1 Then
Cells(Target.Row, "G").Value = 8000
End If
End Sub
can you not put an if statement in column G , as in
If (A1<>"", 8000,0)
Other wise something like this will get you going:
Private Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
If Target.Column = 1 Then
If Target.Value2 <> "" Then
Target.Offset(0, 6) = "8000"
Else
Target.Offset(0, 6) = ""
End If
End If
On Error GoTo 0
End Sub
Thanks
Ross
I had a similar problem. I used Siddharth Rout's code. My modifications allow a user to paste a range of cells in column a (ex. A3:A6) and have multiple cells modified (ex. H3:H6).
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo Whoa
'~~> Check if user has selected more than one cell
If Target.Cells.CountLarge < 1 Then Exit Sub
If Target.Cells.CountLarge > 500 Then Exit Sub
Debug.Print CStr(Target.Cells.CountLarge)
Application.EnableEvents = False
Dim the_row As Range
Dim the_range As Range
Set the_range = Target
'~~> Check if the user made any changes in Col A
If Not Intersect(the_range, Columns(1)) Is Nothing Then
For Each the_row In the_range.Rows
'~~> Ensure it is not in row 2
If the_row.Row > 2 Then
'~~> Write to relevant cell in Col H
Range("H" & the_row.Row).Value = Now
End If
Next
End If
Letscontinue:
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume Letscontinue
End Sub