I am trying to run a macro that will fill in the date and time when something has been updated, but I need to have it happen twice in the same row.
I have it set up to fill in column B+C when initials are entered in column A, but I would like to to run when someone enters another value in column N
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.Value > 0 Then
r.Offset(0, 1).Value = Date
r.Offset(0, 1).NumberFormat = "mm-dd-yy"
r.Offset(0, 2).Value = Time
r.Offset(0, 2).NumberFormat = "hh:mm AM/PM"
Else
r.Offset(0, 1).Value = ""
r.Offset(0, 2).Value = ""
End If
Next r
End Sub
You just need to test what the Address/location of the Target range is:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Select Case Target.Column
Case 1 ' "A"
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
For Each r In Inte
If r.Value > 0 Then
r.Offset(0, 1).Value = Date
r.Offset(0, 1).NumberFormat = "mm-dd-yy"
r.Offset(0, 2).Value = Time
r.Offset(0, 2).NumberFormat = "hh:mm AM/PM"
Else
r.Offset(0, 1).Value = ""
r.Offset(0, 2).Value = ""
End If
Next r
Case 14 ' "N"
' Do something else
End Select
Application.EnableEvents = True ' <-- Don't forget to turn this back on!
End Sub
Further, since such an approach can get unwieldy, it's often a good idea to break down your methods. (Smaller methods are almost always better.)
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Select Case Target.Column
Case 1, ' "A"
Call AddDatesAfterInitialsEntered(Target)
Case 14 ' "N"
' Do something else
End Select
Application.EnableEvents = True ' <-- Don't forget to turn this back on!
End Sub
Private Sub AddDatesAfterInitialsEntered(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
For Each r In Inte
If r.Value > 0 Then
r.Offset(0, 1).Value = Date
r.Offset(0, 1).NumberFormat = "mm-dd-yy"
r.Offset(0, 2).Value = Time
r.Offset(0, 2).NumberFormat = "hh:mm AM/PM"
Else
r.Offset(0, 1).Value = ""
r.Offset(0, 2).Value = ""
End If
Next r
End Sub
Related
The macro that follows works alright if I put it in sheet1. However I would like to put this macro in sheet2. Unfortunately it doesn't make the job from sheet2, only from Sheet1. Can you please help me to make it run from Sheet2?
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Dim sRes As Variant
On Error GoTo haveError
Set rng = Application.Intersect(Sheet1.Range("I15:I18"), Target)
If Not rng Is Nothing Then
If rng.Cells.count = 1 Then
sRes = Application.VLookup(rng.Value, _
Sheet2.Range("A56:B58"), 2, True)
'turn off events before updating the worksheet
Application.EnableEvents = False
rng.Offset(0, 1).Value = IIf(IsError(sRes), "???", sRes)
Select Case rng.Offset(0, 1).Value
Case "Low Risk": rng.Offset(0, 2).Value = Date + 180
Case "Medium Risk": rng.Offset(0, 2).Value = Date + 150
Case "High Risk": rng.Offset(0, 2).Value = Date + 120
End Select
Application.EnableEvents = True
End If '<< edit added missing line here
End If
Exit Sub
haveError:
Application.EnableEvents = True '<< ensures events are reset
End Sub
The answer to this question it is simpler than I thought:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Dim rng1 As Range
Dim sRes As Variant
Dim sRes1 As Variant
On Error GoTo haveError
Set rng = Application.Intersect(Sheet1.Range("I15:I18"), Target)
Set rng1 = Application.Intersect(Sheet1.Range("I20:I23"), Target)
If Not rng Is Nothing Then
If rng.Cells.count = 1 Then
sRes = Application.VLookup(rng.Value, _
Sheet2.Range("A56:B58"), 2, True) 'Waterlow
'turn off events before updating the worksheet
Application.EnableEvents = False
rng.Offset(0, 1).Value = IIf(IsError(sRes), "???", sRes)
Select Case rng.Offset(0, 1).Value
Case "Low Risk": rng.Offset(0, 2).Value = Date + 180
Case "Medium Risk": rng.Offset(0, 2).Value = Date + 150
Case "High Risk": rng.Offset(0, 2).Value = Date + 120
End Select
Application.EnableEvents = True
End If '<< edit added missing line here
ElseIf Not rng1 Is Nothing Then
If rng1.Cells.count = 1 Then
sRes1 = Application.VLookup(rng1.Value, _
Sheet3.Range("A28:B30"), 2, True) 'MUST
'turn off events before updating the worksheet
Application.EnableEvents = False
rng1.Offset(0, 1).Value = IIf(IsError(sRes1), "???", sRes1)
Select Case rng1.Offset(0, 1).Value
Case "Low Risk": rng1.Offset(0, 2).Value = Date + 180
Case "Medium Risk": rng1.Offset(0, 2).Value = Date + 150
Case "High Risk": rng1.Offset(0, 2).Value = Date + 120
End Select
Application.EnableEvents = True
End If '<< edit added missing line here
End If
Exit Sub
haveError:
Application.EnableEvents = True '<< ensures events are reset
End Sub
It is only a matter to combine two procedures. A simple Elseif make it run (work :)) the macro.
Thanks to all of you for trying to help me.
I discovered this Event macro and it is exactly what I need. However I have multiple points of data entry that need to generate a static date and timestamp. I have not been successful in running multiple instances of this macro.
Example: I enter data in A, date and time generate in C,D. Then I enter data in J, date and time generate in M,N. etc.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim A As Range, B As Range, Inte As Range, r As Range
Set A = Range("D:D")
Set Inte = Intersect(A, Target)
If Inte Is Nothing Then Exit Sub
Application.EnableEvents = False
For Each r In Inte
If r.Value > 0 Then
r.Offset(0, -3).Value = Date
r.Offset(0, -3).NumberFormat = "dd-mm-yyyy"
r.Offset(0, -2).Value = Time
r.Offset(0, -2).NumberFormat = "hh:mm:ss AM/PM"
Else
r.Offset(0, -3).Value = ""
r.Offset(0, -2).Value = ""
End If
Next r
Application.EnableEvents = True
End Sub
To include column J, Change:
Set A = Range("D:D")
to:
Set A = Range("D:D,J:J")
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
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
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.