The objective of this code is so every time cell E6:E36 changes from "Yes" or to "Enter Non Final Action Taken Date" I want it to run my macro.
It works only when E6 is marked to match the next value. How do I make it so it is not dependent on the previous cells value?
I'm new with VBA so I'm a bit lost. Any help would be greatly appreciated. See current code below:
Private Sub Worksheet_Change(ByVal Target As range)
Application.EnableEvents = False 'pervent triggering another change event
On Error GoTo ERR_HANDLING
If Not Intersect(Target, range("E6:E36")) Is Nothing Then
Select Case range("E6,E7,E8,E9,E10,E11,E12,E13,E14,E15,E16,E17,E18,E19,E20,E21,E22,E23,E24,E25,E26,E27,E28,E29,E30,E31,E32,E33,E34,E35,E36")
Case "Yes": EnterDate_of_last_Submission
End Select
End If
If Not Intersect(Target, range("E6,E7,E8,E9,E10,E11,E12,E13,E14,E15,E16,E17,E18,E19,E20,E21,E22,E23,E24,E25,E26,E27,E28,E29,E30,E31,E32,E33,E34,E35,E36")) Is Nothing Then
Select Case range("E6,E7,E8,E9,E10,E11,E12,E13,E14,E15,E16,E17,E18,E19,E20,E21,E22,E23,E24,E25,E26,E27,E28,E29,E30,E31,E32,E33,E34,E35,E36")
Case "Enter Non Final Action Taken Date": EnterNonFinal_Date
End Select
End If
On Error GoTo 0
ERR_HANDLING:
Application.EnableEvents = True
If Err.Number <> 0 Then
Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContex
End If
End Sub
You need to loop here and compare cell-by-cell, something like the following:
Private Sub Worksheet_Change(ByVal Target As range)
Dim rngToCheck as Range
Set rngToCheck = Intersect(Target, Me.Range("E6:E36"))
If rngToCheck Is Nothing Then Exit Sub
On Error GoTo SafeExit
Application.EnableEvents = False
Dim rng as Range
For Each rng in rngToCheck
Select Case rng.Value
Case "Yes"
EnterDate_of_last_Submission
Case "Enter Non Final Action Taken Date"
EnterNonFinal_Date
End Select
Next
SafeExit:
Application.EnableEvents = True
End Sub
Most likely EnterDate_of_last_Submission and EnterNonFinal_Date should be rewritten to take a Range parameter, namely the cell the date is entered in (which it looks like would correspond to rng.Offset(,1) with your current setup.
I'm trying to make use of the Worksheet_Change event in VBA to return the value of the adjacent cell if current cell value is nothing, within provided range. I.e. IF current cell F3 is empty, then return contents in cell G3. This formula only applies to cells in range F3 to F37.
Here is my current code for which when any cell in range is empty, the code doesn't seem to evaluate (i.e. copy data from adjacent cell), and remains empty.
Any help would be greatly appreciated. Thanks!
Private Sub Worksheet_Change(ByVal Target As Range)
Dim myCell As Range
Set myCell = Range("F3:F37")
If Not Application.Intersect(myCell, Range(Target.Address)) Is Nothing Then
Target.Value = Cell.Offset(0, 1).Value
End If
End Sub
Modified to:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim myCell As Range
Application.DisplayAlerts = False
Application.EnableEvents = False
Set myCell = Range("F3:F37")
If Not Application.Intersect(myCell, Range(Target.Address)) Is Nothing Then
If Target.Value = "" Then
Target.Value = Target.Offset(0, 1).Value
End If
End If
Application.EnableEvents = True
Application.DisplayAlerts = True
End Sub
If you use Application.EnableEvents = False in an event make sure you use proper error handling and enable events again in case of any error within the event (VBA Error Handling – A Complete Guide). Otherwise your events will stay turned off in case of an error until you close the Excel application completely.
Note that Application.EnableEvents affects the whole application that means all Excel files that are opened in that instance of the application. So not having proper error handling here might have a bigger impact on other projetcts than you think.
Another trap you fell into, is that Target can be a Range (not only a single cell). So for example if you copy/paste a range that affects multiple cells in F3:F37 your Target is not a single cell and therefore Target.Value = "" does not work. You need a loop through all the affected cells:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim CheckRange As Range
Set CheckRange = Me.Range("F3:F37") 'Make sure you use "Me" to refer to the same worksheet as Target (and the change event is in)
Dim AffectedCells As Range 'get the cells of CheckRange that were changed
Set AffectedCells = Application.Intersect(CheckRange, Target)
Application.EnableEvents = False
On Error GoTo ENABLE_EVENTS 'make sure you never end up in a condition where events stay disabled
If Not AffectedCells Is Nothing Then
Dim Cell As Range
For Each Cell In AffectedCells 'loop throug all the affected cells
If Cell.Value = "" Then
Cell.Value = Cell.Offset(0, 1).Value
End If
Next Cell
End If
'no exit sub here!
ENABLE_EVENTS:
Application.EnableEvents = True
If Err.Number <> 0 Then 'make sure to re-raise an error message if there was an error (otherwise you won't ever notice that there was one), because the `On Error GoTo` statement muted the error message.
Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
'above line to raise the original error message
'or at least show a message box:
'MsgBox "There was an error. Tell your Developer to fix it.", vbCritical
End If
End Sub
Note that I removed Application.DisplayAlerts because there is nothing in the code that would display any alerts, so I see no need to use it in this case here.
I have programming, with major help from others, that works great for two separate workbooks. The problem is that I can't seem to have them both work within the same workbook and I don't know why.
We have a large contact database (4800 rows) workbook with a lot of sorting macros. I use the following to allow the user to double-click a cell to select or de-select a contact. This is under the Excel Objects, Sheet1 (MASTER):
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
'Limit Target count to 1
If Target.Count > 1 Then Exit Sub
'Isolate Target to a specific range
If Intersect(Target, Range("SelectionMaster")) Is Nothing Then Exit Sub
'set Target font tp "marlett"
Target.Font.Name = "marlett"
'Check value of target
If Target.Value < "a" Then
Target.Value = "a" 'Sets target Value = "a"
Cancel = True
Exit Sub
End If
If Target.Value = "a" Then
Target.Value = "r"
Cancel = True
Exit Sub
End If
If Target.Value = "r" Then
Target.ClearContents 'Sets Target Value = ""
Cancel = True
Exit Sub
End If
End Sub
In another workbook, I tested the following for locking a particular row if an 'X' is placed in Column AZ (end of contact data). This is under the Excel Objects, Sheet1 (Sheet1):
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim LR As Long
If Not Target.Column = 52 Then Exit Sub
If Target.Count > 1 Then Exit Sub
If UCase(Target.Value) = "X" Then
ActiveSheet.Unprotect
Target.EntireRow.Locked = True
ActiveSheet.Protect
End If
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Locked Then
If MsgBox("Row is locked. Do you want to change the value ?", vbYesNo) = vbYes Then
ActiveSheet.Unprotect
Target.EntireRow.Locked = False
Cells(ActiveCell.Row, 52).Value = ""
ActiveSheet.Protect
End If
End If
End Sub
In the Database file, I have certain rows that identify the contact's category that I would like to have locked. All other cells can be changed. If I copy over the 2nd code to the database file, it doesn't work correctly. Instead it locks all of the cells and prompts the message box regardless of an 'X' in Column AZ. Can these two not co-exist or what is this newb doing wrong?
I'm receiving a type 13 mismatch error with Excel VBA. This script checks two columns and locks cells in a column once a change is made, or doesn't lock it if the user clicks the cell and clicks off without any changes. Line 5 is apparently the culprit. Any help is much appreciated.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim A As Range
Set A = Union(Range("I:I"), Range("J:J"))
If Intersect(Target, A) Is Nothing Then Exit Sub
If Target.Value = "" Then Exit Sub
ActiveSheet.Unprotect Password:="YourPassword"
Target.Locked = True
ActiveSheet.Protect Password:="YourPassword"
End Sub
Target is the cell or cells that have been changed. If Target is more than a single cell (e.g. pasted block of values, etc) then Target does not have a .Value. Add If Target.Count > 1 Then Exit Sub to the top of the code or loop through Target, examining each cell within Target for the .Value.
Example of the latter,
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Union(Range("I:I"), Range("J:J"))) Is Nothing Then
On Error GoTo bm_Safe_Exit
ActiveSheet.Unprotect Password:="YourPassword"
Application.EnableEvents = True
Dim ij As Range
For Each ij In Intersect(Target, Union(Range("I:I"), Range("J:J")))
If ij.Value <> "" Then
ij.Locked = True
End If
Next ij
End If
bm_Safe_Exit:
ActiveSheet.Protect Password:="YourPassword"
Application.EnableEvents = True
End Sub
Additionally, it is not considered a 'best practise' to use the ActiveSheet property in a Worksheet_Change event macro.
I have been trying to have two independent codes change my worksheet based on either a cell value or a data validation selection. To try to highlight what my intent is I have a database of Steel Structural members I am trying to create a worksheet that the end user will select if they want US or Metric Units. Based on that selection I need either row 11 or 12 to be hidden. I already have a macro attached to the worksheet that will enter the user's selection from a data validation list into subsequent columns. To further explain my end goal: Row 11 is the Members in US units and 12 is the Metric Units. If the end user selects US they will not see the Metric Row, and vise versa.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo exitHandler
Dim rngDV As Range
Dim iCol As Integer
If Target.Count > 1 Then GoTo exitHandler
On Error Resume Next
Set rngDV = Cells.SpecialCells(xlCellTypeAllValidation)
On Error GoTo exitHandler
If rngDV Is Nothing Then GoTo exitHandler
If Intersect(Target, rngDV) Is Nothing Then
'do nothing
Else
Application.EnableEvents = False
If Target.Column = 3 Then
If Target.Value = "" Then GoTo exitHandler
If Target.Validation.Value = True Then
iCol = Cells(Target.Row, Columns.Count).End(xlToLeft).Column + 2
Cells(Target.Row, iCol).Value = Target.Value
Else
MsgBox "Invalid entry"
Target.Activate
End If
End If
End If
exitHandler:
Application.EnableEvents = True
If Target.Address = "$AS$7" Then
Rows("11").Hidden = (Target.Value = "Metric")
Rows("12").Hidden = (Target.Value = "US Standard")
End If
End Sub
I had them as two Worksheet_Change events and had a compiler error, and I have tried to break the two programs into individual sub routines ie:
Private Sub Worksheet_Change(ByVal Target As Range)
SelectStructural Target
HideRow Target
End Sub
Sub SelectStructural (ByVal Target As Range)
...
End Sub
Sub HideRow (ByVal Target As Range)
...
End Sub
Where ... is representative of the previouly mentioned code. And in that case as with above the macro which inputs the member into subsequent columns works but not the row hide routine.
Many thanks in advance.
Here is what I would do to fix your problem. I wouldn't have a worksheet_change event for this at all, because every time anyone types a thing, this code will have to run. Have some other place where the user selects US or Metric and when THAT changes, you can have the event go off.
Determine the point where the user enters US or Metric.
Sub MetricCheck_Change(ByVal Target As Range)
Dim userChoice as String
userChoice = LCase(Sheets("Sheet1").Range("A1")) 'Convert a user input to lowercase
If userChoice = "us" Then
Call UsSub
ElseIf userChoice = "metric" Then
Call MetricSub
Else
MsgBox("Neither US or Metric has been selected. Please select to continue.")
End If
End Sub
Have a sub that Shows the US row, and hides the Metric. Just record a macro that does just that, and put it here.
Sub UsSub()
'Show the US Row
'Hide the Metric Row
End Sub
Do the opposite for the Metric Sub
Sub MetricSub
'Hide the US Row
'Show the Metric Row
End Sub