VBA: Change Event Not Firing - excel

if any cell in column k has a value of "Yes" then offset (0,1) become empty,
Else if any cell in column k has a value of "No" then offset (0,2) become empty.
The problem is that the event is not firing. The code is placed in the worksheet.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("k:k")) Is Nothing Then
On Error GoTo safe_exit
Application.EnableEvents = False
Dim Cell As Range
For Each Cell In Intersect(Target, Range("k:k"))
If Cell.Value = "Yes" Then
Cell.Offset(0, 1).ClearContents
ElseIf Cell.Value = "No" Then
Cell.Offset(0, 2).ClearContents
End If
Next Cell
End If
safe_exit:
Application.EnableEvents = True
End Sub

The Code were correct. While debugging "The current state" of Application.EnableEvents was not switched back to enabled. Thanks everyone for the contributions. CLR & Tim Williams

Related

Is there a function that deletes a cells value if I delete the value of another cell in the same row?

I'm currently setting up a small inventory tool and since I'm new to vba I got stuck.
So I got a table where you can register all the ingoing and outgoing goods and so far I've included a macro which automatically puts the date into the row if the cells in the ingoing and outgoing columns are changed.
What I want to do now is that if I delete a value in the outgoing/ingoing columns the date will disappear too.
That's my code so far:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
On Error GoTo Ende
Application.EnableEvents = False
For Each rng In Application.Intersect(Columns("D"), Target).Cells
If rng.Offset(0, -2).Value = "" Then
rng.Offset(0, -2).Value = Date
End If
Next rng
Ende:
Application.EnableEvents = True
End Sub
Anyone got an idea?
Quck and dirty fix - add another for loop that checks if the target cell is empty:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
On Error GoTo Ende
Application.EnableEvents = False
For Each rng In Application.Intersect(Columns("D"), Target).Cells
If rng.Offset(0, -2).Value = "" Then
rng.Offset(0, -2).Value = Date
End If
Next rng
For Each rng In Application.Intersect(Columns("D"), Target).Cells
If rng = "" Then
rng.Offset(0, -2).Value = ""
End If
Next rng
Ende:
Application.EnableEvents = True
End Sub

Change cell color base on another cells data but keep it that way if data changes again

I have been looking for days to solve this and have only come up with half the solution.
What I can do:
I would simply like to have one cell turn green inside with an x inserted when another cells data has the word "Complete" inside it.
What I cannot do:
I would like that same cell that turned green with an x inserted into it when the word "Complete" is changed to "Rework" to stay green with an x.
So Cell A1 is blank then in cell B1 the word "Complete" is added. Then cell A1 changes to green and has an x inside it. If later B1 changes to "Rework" I would like A1 to stay green with the x inside. So I can know that at one time the status of B1 was at one time "Complete"
I have been trying Conditional Formatting with rules but cannot get it to stay. I think the "Stop If True" check box within would be part of the solution but not sure what the code would be.
I already have a different macro running on this sheet so if the answer is a macro I will need it to be added to it. Below is the macro in the sheet already. Thank you.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("N:N,Y:Y"), Range("10:" & Rows.Count)) Is Nothing Then
If Target.Count < Columns.Count Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
Dim r As Range
For Each r In Intersect(Target, Range("N:N,Y:Y"), Range("10:" & Rows.Count))
With r.Offset(0, 1)
.Value = Now 'use Now to retain the time as well as the date
.NumberFormat = "mm/dd/yy" 'change to what you prefer
End With
Next r
End If
End If
bm_Safe_Exit:
Application.EnableEvents = True
End Sub
Ideally you'd split this up into separate subs to handle each of the change types, but this should give you an idea:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range, r as Range
'skip full-row changes (row insert/delete?)
If Target.Columns.Count = Columns.Count Then Exit Sub
Set rng = Intersect(Target, Range("N:N,Y:Y"), Range("10:" & Rows.Count))
If Not rng Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
For Each r In rng.Cells
With r.Offset(0, 1)
.Value = Now 'use Now to retain the time as well as the date
.NumberFormat = "mm/dd/yy" 'change to what you prefer
End With
Next r
End If
Set rng = Intersect(Target, Range("B:B"), Range("10:" & Rows.Count))
If Not rng Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
For Each r In rng.Cells
If r.Value = "Complete" Then
With r.Offset(0, -1)
.Value = "x"
.Interior.Color = vbGreen
End With '<<EDIT thanks #BruceWayne
End If
Next r
End If
bm_Safe_Exit:
Application.EnableEvents = True
End Sub
You'll need two worksheet events, and some If statements. The following should help you get started, unless I'm overlooking something.
Dim oldVal as String ' Public variable
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'Debug.Print Target.Address
If Target.Cells.Count <> 1 Then Exit Sub
oldVal = Target.Value
End Sub
The above will make note of the oldValue.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim newVal As String
newVal = Target.Value
If newVal = oldVal Then
Debug.Print "Same Values"
ElseIf oldVal = "Complete" And newVal = "Rework" Then
Debug.Print "Stay green with X"
ElseIf oldVal = "" And (newVal = "Complete" Or newVal = "complete") Then
Debug.Print "Change cell to Green, add an 'X'"
Target.Interior.ColorIndex = 10
Target.Value = Target.Value & " x"
End If
End Sub
Then, add/tweak those If statements as necessary, and add the color changing/reverting code to the appropriate block.
(There may of course be a better mousetrap, but I think this should get you going).

Automatic Date and Time get refreshed on pressing "Delete" Key in Excel

I am using a simple code to enter date and time automatically in 2 separate cells in the excel sheet, however, they change automatically if I enter a new value in the cell or just press "Delete" Key. Below is the code I am using:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column <> 5 Then Exit Sub
Application.EnableEvents = False
Target.Offset(0, -2).Value = Date
Application.EnableEvents = True
If Target.Column <> 5 Then Exit Sub
Application.EnableEvents = False
Target.Offset(0, -1).Value = Time
Application.EnableEvents = True
End Sub
I need the date and time to remain static until I delete them from their respective cells. How can I achieve this?
This will preserve the date/time once they have been entered:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column <> 5 Then Exit Sub
Application.EnableEvents = False
If Target.Offset(0, -2).Value = "" And Target.Offset(0, -2).Value = "" Then
Target.Offset(0, -2).Value = Date
Target.Offset(0, -1).Value = Time
End If
Application.EnableEvents = True
End Sub
EDIT#1:
This version will allow you to both set and clear multiple cells in column E:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim r As Range, i1 As Long, i2 As Long
If Target.Column <> 5 Then Exit Sub
With ActiveSheet.UsedRange
i2 = .Rows.Count + .Row - 1
i1 = .Row
End With
Application.EnableEvents = False
For Each r In Intersect(Target, Range("E" & i1 & ":E" & i2))
If r.Offset(0, -2).Value = "" And r.Offset(0, -1).Value = "" And r.Value <> "" Then
r.Offset(0, -2).Value = Date
r.Offset(0, -1).Value = Time
End If
Next r
Application.EnableEvents = True
End Sub
Clearing a cell that is already empty will not cause a time/date recording.
Stepping through your code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column <> 5 Then Exit Sub
"If the target's column is not 5 then exit the subroutine" This is cool.
Application.EnableEvents = False
Flipping this to false insures that this code won't run again until this value is set to true. Worksheet_Change needs enableevents to be on. So now if the cell that changed was in Column E then Worksheet_Change will be kept from executing again. This makes sense to keep infinite loops from happening as cells are changed via this code.
Target.Offset(0, -2).Value = Date
Set the cell that is two columns back from the target cell to the current date.
Application.EnableEvents = True
Set enableEvents back on. This is good since you probably don't want to leave this off.
If Target.Column <> 5 Then Exit Sub
Why are we checking this again? Target.Column hasn't changed since last time, and if it was already <>5 then we wouldn't be here to test it. This line is superfluous.
Application.EnableEvents = False
OK.. Well we just turned this on, but now we are turning this off again. Just leave it off.
Target.Offset(0, -1).Value = Time
Set the value 1 column to the left of the target cell to the current time. Coolios.
Application.EnableEvents = True
Turn enableEvents back on. This makes sense here.
End Sub
Rewriting this to remove the redundant toggles and superflous target.Column check:
Private Sub Worksheet_Change(ByVal Target As Range)
'make sure this is column 5 that was changed. Like if anything changed in
' column 5, then run the rest of this.
If Target.Column <> 5 Then Exit Sub
'Make sure we don't infinite loop if we accidently trigger a change to
' column 5 in this code.
Application.EnableEvents = False
' Set two cells to the left to the current date
' and one cell to the left to the current time
Target.Offset(0, -2).Value = Date
Target.Offset(0, -1).Value = Time
'turn events back on.
Application.EnableEvents = True
End Sub
So.. Everytime you make a change in Column 5, the date and time change. IF you want it so that it only changes a row's date and time once. Then check to see if date and time are already set for the row:
Private Sub Worksheet_Change(ByVal Target As Range)
'make sure this is column 5 that was changed. Like if anything changed in
' column 5, then run the rest of this.
If Target.Column <> 5 Then Exit Sub
'Check to see if the date and time are already set for this row:
' If they are, then exit subroutine.
If target.offset(0,-2).value <> "" OR target.offset(0,-1).value <> "" Then Exit Sub
'Make sure we don't infinite loop if we accidently trigger a change to
' column 5 in this code.
Application.EnableEvents = False
' Set two cells to the left to the current date
' and one cell to the left to the current time
Target.Offset(0, -2).Value = Date
Target.Offset(0, -1).Value = Time
'turn events back on.
Application.EnableEvents = True
End Sub

Offset to different column after entering data in cell

I have two tables. Both tables are the same size, located in columns I:X and AB:AQ (offset by 19 columns start-to-start).
I want when I enter a number in a cell within the left table, to go 19 columns to the right after pressing enter. Then, once entering text into the active cell in the right table, return 19 cells to the left table.
I found this question/answer, but I wasn't able to apply it.
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(9)) Is Nothing Then
Target.Offset(, 19).Select
ElseIf Not Intersect(Target, Columns(10)) Is Nothing Then
Target.Offset(, 19).Select
ElseIf Not Intersect(Target, Columns(11)) Is Nothing Then
Target.Offset(, 19).Select
ElseIf Not Intersect(Target, Columns(12)) Is Nothing Then
Target.Offset(, 19).Select
'etc...
ElseIf Not Intersect(Target, Columns(42)) Is Nothing Then
Target.Offset(, -19).Select
ElseIf Not Intersect(Target, Columns(43)) Is Nothing Then
Target.Offset(, -19).Select
End If
End If
Letscontinue:
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume Letscontinue
End Sub
As an alternative, if it can recognize that the cell entered is within columns I:X and just offset 19 columns after pressing enter (and then the reverse), this would be fine.
A second alternative, if it is easier, changing the function of the Page Up and Page Down keys, I would not need to check which column I am in.
Lastly, this should only work on a particular sheet Tracking.
Something like this should work for you. Make sure the code is in the 'Tracking' worksheet code module:
And here is the code you would use:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rngChange1 As Range
Dim rngChange2 As Range
Set rngChange1 = Range("I:X")
Set rngChange2 = Range("AB:AQ")
Application.EnableEvents = False
If Not Intersect(rngChange1, Target) Is Nothing Then
Target.Offset(, 19).Value = Target.Value
End If
If Not Intersect(rngChange2, Target) Is Nothing Then
Target.Offset(, -19).Value = Target.Value
End If
Application.EnableEvents = True
End Sub

Add cell A to cell B and reset cell A to 0

I need to add cell A to cell B of the same row and then reset cell A to zero. I did some searching and found this code that works perfectly, but I need to have it work for an entire column not just one row.
So, all of column A should add to column B, but only on the same row. Here is the code I found:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If Target.Address = Range("a1").Address Then
Range("b1") = Range("b1") + Range("a1")
Range("a1").ClearContents
End If
Application.EnableEvents = True
End Sub
And:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim A1 As Range
Set A1 = Range("A1")
If Intersect(Target, A1) Is Nothing Then
Else
Application.EnableEvents = False
With A1
.Offset(0, 1) = .Offset(0, 1) + .Value
.ClearContents
End With
Application.EnableEvents = True
End If
End Sub
Both sets of code work just fine to add cell A to B and reset A to zero, but I want this to work for the entire (column A and B) and all by row.
That is a picture of what I would like. I hope that this was clear and easy to understand. I appreciate any help that anyone can provide. I really appreciate it. Thank you.
Give this a try:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim T As Range, r As Range
Set T = Intersect(Target, Range("A:A"))
If T Is Nothing Then Exit Sub
Application.EnableEvents = False
For Each r In T
With r
.Offset(0, 1).Value = .Offset(0, 1).Value + .Value
.ClearContents
End With
Next r
Application.EnableEvents = True
End Sub

Resources