Excel Worksheet_Change event triggering when deleting row - vba

I have an excel worksheet with some vba code that when i change a specific cell it automatically sets the date of today into the cell next to it.
That all works good, but when i delete an entire row that's above that specific cell it changes the date automatically to the date of today.
This is the code i use to automatically the change the cell:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim WorkRng As Range
Dim Rng As Range
Dim xOffsetColumn As Integer
Set WorkRng = Intersect(Application.Sheets("Example").Range("H10: H306, M10: M306, R10: R306, W10: W306, AB10: AB306, AG10: AG306"), Target)
xOffsetColumn = 1
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
If Not VBA.IsEmpty(Rng.Value) Then
Sheets("Example").Unprotect
Rng.Offset(0, xOffsetColumn).Value = Now
Rng.Offset(0, xOffsetColumn).NumberFormat = "dd-mm-yyyy"
Sheets("Example").Protect
Else
Rng.Offset(0, xOffsetColumn).ClearContents
End If
Next
Application.EnableEvents = True
End If
End Sub
Is someone familiar with this problem?

You can do some tests on Range Target, to avoid executing the code
(with Goto or rather Exit Sub) :
Target.Cells.Count > 1
Target.Rows.Count > 1
Target.Columns.Count > 1
You can use theses tests at the start of the Sub or with If Not WorkRng Is Nothing Then
So your code could be :
Private Sub Worksheet_Change(ByVal Target As Range)
Dim WorkRng As Range
Dim Rng As Range
Dim xOffsetColumn As Integer
If Target.Columns.Count > 1 Then Exit Sub
Set WorkRng = Intersect(Application.Sheets("Example").Range("H10: H306, M10: M306, R10: R306, W10: W306, AB10: AB306, AG10: AG306"), Target)
xOffsetColumn = 1
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
If Not VBA.IsEmpty(Rng.Value) Then
Sheets("Example").Unprotect
Rng.Offset(0, xOffsetColumn).Value = Now
Rng.Offset(0, xOffsetColumn).NumberFormat = "dd-mm-yyyy"
Sheets("Example").Protect
Else
Rng.Offset(0, xOffsetColumn).ClearContents
End If
Next
Application.EnableEvents = True
End If
End Sub

Related

procedure too large vba for excel

I am not used to writing code. I normally generate my code via macro and I am facing this issue. Can someone please help me?
Sub Test()
Dim WorkRng As Range
Dim Rng As Range
Dim xOffsetColumn As Integer
Set WorkRng = Intersect(Application.ActiveSheet.Range("B8:B38"), Target)
xOffsetColumn = 19
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
If Not VBA.IsEmpty(Rng.Value) Then
Rng.Offset(0, xOffsetColumn).Value = Now
Rng.Offset(0, xOffsetColumn).NumberFormat = "mm/dd/yyyy, hh:mm:ss"
Else
Rng.Offset(0, xOffsetColumn).ClearContents
End If
Next
Application.EnableEvents = True
End If
Dim WorkRng1 As Range
Dim Rng1 As Range
Dim xOffsetColumn1 As Integer
Set WorkRng1 = Intersect(Application.ActiveSheet.Range("C8:C38"), Target)
xOffsetColumn1 = 18
If Not WorkRng1 Is Nothing Then
For Each Rng1 In WorkRng1
If Not VBA.IsEmpty(Rng1.Value) Then
Rng1.Offset(0, xOffsetColumn1).Value = Now
Rng1.Offset(0, xOffsetColumn1).NumberFormat = "mm/dd/yyyy, hh:mm:ss"
Else
Rng1.Offset(0, xOffsetColumn1).ClearContents
End If
Next
Application.EnableEvents = True
End If
....................................
..............................
Dim WorkRng132 As Range
Dim Rng132 As Range
Dim xOffsetColumn132 As Integer
Set WorkRng132 = Intersect(Application.ActiveSheet.Range("EJ8:EJ38"), Target)
xOffsetColumn132 = 1
If Not WorkRng132 Is Nothing Then
For Each Rng132 In WorkRng132
If Not VBA.IsEmpty(Rng132.Value) Then
Rng132.Offset(0, xOffsetColumn132).Value = Now
Rng132.Offset(0, xOffsetColumn132).NumberFormat = "mm/dd/yyyy, hh:mm:ss"
Else
Rng132.Offset(0, xOffsetColumn132).ClearContents
End If
Next
Application.EnableEvents = True
End If
End Sub
One useful maxim in programming is Don't Repeat Yourself (DRY) - duplicated code is longer, harder to understand, and difficult to maintain.
There's a clear repeating pattern in your code. This block:
Dim WorkRng As Range
Dim Rng As Range
Dim xOffsetColumn As Integer
Set WorkRng = Intersect(Application.ActiveSheet.Range("B8:B38"), Target)
xOffsetColumn = 19
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
If Not VBA.IsEmpty(Rng.Value) Then
Rng.Offset(0, xOffsetColumn).Value = Now
Rng.Offset(0, xOffsetColumn).NumberFormat = "mm/dd/yyyy, hh:mm:ss"
Else
Rng.Offset(0, xOffsetColumn).ClearContents
End If
Next
Application.EnableEvents = True
End If
Can be refactored into a re-usable method with two parameters:
Sub Test()
'....
ProcessRange Application.Intersect(Me.Range("B8:B38"), Target), 19
ProcessRange Application.Intersect(Me.Range("C8:C38"), Target), 18
'etc for the other ranges
'....
End sub
'subprocedure
Sub ProcessRange(WorkRng As Range, offsetCol as Long)
Dim Rng As Range
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
With Rng.Offset(0, offsetCol)
If Not VBA.IsEmpty(Rng.Value) Then
.Value = Now
.NumberFormat = "mm/dd/yyyy, hh:mm:ss"
Else
.ClearContents
End If
End With
Next
Application.EnableEvents = True
End If
End Sub

Excel VBA - Do not execute if

This is my Macro for a time stamp:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim WorkRng As Range
Dim Rng As Range
Dim xOffsetColumn As Integer
Set WorkRng = Intersect(Application.ActiveSheet.Range("N:N"), Target)
xOffsetColumn = 6
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
If Not VBA.IsEmpty(Rng.Value) Then
Rng.Offset(0, xOffsetColumn).Value = Now
Rng.Offset(0, xOffsetColumn).NumberFormat = "mm-dd-yyyy, hh:mm:ss"
Else
Rng.Offset(0, xOffsetColumn).ClearContents
End If
Next
Application.EnableEvents = True
End If
End Sub
I did not write this originally. I found it off of a forum as my macro knowledge is primitive at best.
Essentially I would like the time stamp to ONLY OCCUR ONCE so I need this macro not to run if a time stamp already exists in column AK.
I think this does what you want. It checks if AK is blank - if so, it adds the date, if not, it does nothing.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim WorkRng As Range
Dim Rng As Range
Dim xOffsetColumn As Long
Set WorkRng = Intersect(Application.ActiveSheet.Range("A:A"), Target)
xOffsetColumn = 36
If Not WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
If Not VBA.IsEmpty(Rng.Value) Then
If Len(Rng.Offset(0, xOffsetColumn)) = 0 Then
Rng.Offset(0, xOffsetColumn).Value = Now
Rng.Offset(0, xOffsetColumn).NumberFormat = "mm-dd-yyyy, hh:mm:ss"
End If
Else
Rng.Offset(0, xOffsetColumn).ClearContents
End If
Next
Application.EnableEvents = True
End If
End Sub

Need this to work with a button press

I found this code on this site that works for what I'm trying to do with a sign out log with one exception - it works as a worksheet update function right now and I need it to only work when a button is pressed. How would I modify this code so that it can be a macro that would be assigned to a button? Any help would be greatly appreciated.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim A As Range, B As Range, Inte As Range, r As Range
Set A = Range("A:A")
Set Inte = Intersect(A, Target)
If Inte Is Nothing Then Exit Sub
Application.EnableEvents = False
For Each r In Inte
If r.Offset(0, 1).Value = "" Then
r.Offset(0, 1).Value = Date
End If
Next r
Application.EnableEvents = True End Sub
If you want to keep checking for values in column A only, then
Sub clickMe()
Dim A As Range, Inte As Range, r As Range
Set A = Range("A:A")
Set Inte = Intersect(A, Selection)
If Inte Is Nothing Then Exit Sub
For Each r In Inte
If r.Offset(0, 1).Value = "" Then
r.Offset(0, 1).Value = Date
End If
Next r
End Sub
If the column does not matter and the button should enter a date to the right of the selected cell, then
Sub clickMe()
Dim r As Range
For Each r In Selection
If r.Offset(0, 1).Value = "" Then
r.Offset(0, 1).Value = Date
End If
Next r
End Sub

2013 Excel VBA remove contents of a cell when deleting another

Below is the vba code I am using to auto-populate the date in column 3 when a number is entered in column 1. I need the date to be removed when the number in Column 1 is deleted.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim A As Range, B As Range, Inte As Range, r As Range
Set A = Range("A:A")
Set Inte = Intersect(A, Target)
If Inte Is Nothing Then Exit Sub
Application.EnableEvents = False
For Each r In Inte
r.Offset(0, 2).Value = Date
Next r
Application.EnableEvents = True
End Sub
It was having a problem because the deletion of column 3 triggers another changestate, so I just put something at the top saying if the change isn't in column 1 then don't worry bout it. This should work:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 1 Then
Dim A As Range, B As Range, Inte As Range, r As Range
Set A = Range("A:A")
Set Inte = Intersect(A, Target)
'If Inte Is Nothing Then Target.Offset(0, 3 - Target.Column).Value = "YES"
If Target.Offset(0, 1 - Target.Column).Value = "" Then
Target.Offset(0, 3 - Target.Column).Clear
Exit Sub
End If
'If Inte Is Nothing Then Exit Sub
Application.EnableEvents = False
For Each r In Inte
r.Offset(0, 2).Value = Date
Next r
Application.EnableEvents = True
End If
End Sub

Combining 2 "Private Sub Worksheet_Change(ByVal Target As Range)" into 1

I am creating an Excel spreadsheet. I have 2 separate functions that I need to combine but I am not sure how to smash them together. I know I can only have 1 change event. The first function will unprotect the sheet (column c is locked), auto populate column C when data is entered in to column A or erase C when A is erased and re-protect when complete. The second will return the cell focus to the next row, column A, when data is entered into A and B. Separately they work as needed.
Private Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
Unprotect Password:="my password"
If Target.Column = 1 Then
Dim A As Range, B As Range, Inte As Range, r As Range
Set A = Range("A:A")
Set Inte = Intersect(A, Target)
If Target.Offset(0, 1 - Target.Column).Value = "" Then
Target.Offset(0, 3 - Target.Column).Clear
Exit Sub
End If
Application.EnableEvents = False
For Each r In Inte
r.Offset(0, 2).Value = Date & " " & Time
r.Offset(0, 2).NumberFormat = "m/d/yyyy h:mm am/pm"
Next r
Application.EnableEvents = True
End If
Protect Password:="my password"
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo Whoa
Application.EnableEvents = False
If Not Target.Cells.CountLarge > 1 Then
If Not Intersect(Target, Columns(1)) Is Nothing Then
Target.Offset(, 1).Select
ElseIf Not Intersect(Target, Columns(2)) Is Nothing Then
Target.Offset(1, -1).Select
End If
End If
Letscontinue:
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume Letscontinue
End Sub
How about this, seems to do what you want, as I understand the question.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rngIntersect As Range
Dim rngCell As Range
On Error GoTo TidyUp
Application.EnableEvents = False
If Target.Column = 1 Then
Set rngIntersect = Intersect(Range("A:A"), Target)
For Each rngCell In rngIntersect
If rngCell.Value = "" Then
rngCell.Offset(0, 2).Value = ""
Else
rngCell.Offset(0, 2).Value = Date & " " & Time
rngCell.Offset(0, 2).NumberFormat = "m/d/yyyy h:mm am/pm"
End If
Next rngCell
End If
If Target.Column < 3 And Target.Value <> "" Then ' lose the 'And Target.Value <> ""' as desired
Cells(Target.Row + Target.Rows.Count, 1).Select
End If
TidyUp:
Set rngIntersect = Nothing
Set rngCell = Nothing
Application.EnableEvents = True
End Sub
I'd also suggest using UserInterfaceOnly in your worksheet.Protect, then you don't have to unprotect the sheet for VBA to act on the sheet.
Implement it in two Sub-Procedures on a modul, then just call both of them in the Event-Procedure.