VBA Multiple Target.Address (OR) for the Same Action - excel

In a worksheet I have two drop-down lists (cells C7 and C68) which each have a dependent drop-down in the cell below. I have a code (below) which will clear the cell of the dependent drop-down if I change the selection in the above list (so that the lists do not mis-match), however I can only get this to work for the one drop-down in the sheet. How can I amend this to that it works if I alter either of the cells with the "Parent" list?
.
Existing code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$C$7" Then
If Target.Validation.Type = 3 Then
Application.EnableEvents = True
Target.Offset(1, 0).Value = ""
End If
End If
exitHandler:
Application.EnableEvents = True
Exit Sub

I suggest using only 1 dropdown list (which user actually selects) and then 2nd "linked cell" is using vlookup from some kind of data transformation list.

All fixed - for anyone who also has this problem, the correct code was:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$C$7" Or Target.Address = "$C$68" Then
If Target.Validation.Type = 3 Then
Application.EnableEvents = False
Target.Offset(1, 0).Value = ""
End If
End If
exitHandler:
Application.EnableEvents = True
Exit Sub
End Sub

Related

Excel VBA Target.Address being modified and causing Error 13 type mismatch

Prototypical post: New to VBA, unable to resolve an issue after having read multiple posts/websites, and now turning to all the fantastic people here who's posts have gotten me this far.
I have a worksheet with data validation in column C (list; forced-choice Yes/No options). If user selects "No" in C7, then C9:C11 need to automatically and immediately populate as "No." I have gotten this to work by the following:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$C$7" And Target.Value = "No" Then
Range("$C$9").Value = "No"
Range("$C$10").Value = "No"
Range("$C$11").Value = "No"
End If
End Sub
I also have a text box on the same worksheet (i.e., Sheet5) that when clicked fires a macro which clears the contents of C6:C7. This Reset macro is in a module under General.
Sub C_B_Reset()
Sheet5.Range("C6:C7").ClearContents
End Sub
Individually, these work fine, but when both exist it results in Type 13 error at the Target.Address after the Reset macro is fired. After firing the Reset macro, the "If Target.Address" portion resolves to the range referenced in the Reset macro (i.e., C6:C7). Because "If Target.Address" expects a single, absolute cell reference (e.g., $C$7), it is throwing the mismatch code because it instead is resolving to (C6:C7) when the mouse is hovered over it.
Even if the Reset macro is completely deleted, the same issue happens if the following is used in the Target.Address code:
Range("$C$9:$C$11").Value = "No"
The Target.Address then resolves to "$C$9:$C$11" and throws the Type 13 mismatch error.
It appears that if "Range" is used to refer to a range of cells in any other macro, it automatically gets assigned as Target.Address. However, this doesn't happen if Range only refers to single cells (which is why there are separate lines for C9 to C11 in the Worksheet_Change code).
I'm sure I'm using incorrect terminology, but I hope I explained it well enough, because I sure would appreciate some help.
Thanks for taking a look,
"Excel VBA Target.Address being modified and causing Error 13 type mismatch"
Target.Address isn't the problem here... Target is the cell(s) that were changed, so Target.Address will be $C$6:$C$7 when you clear both C6 and C7.
The main problem is this:
... And Target.Value = "No" ...
This will fail with a Type Mismatch error when Target is a multi-cell range, because then Target.Value is a 2D Variant array, which you can't compare to "No".
Also, the normal approach is to use Intersect instead of considering Target.Address.
If you're only concerned about C7, then perhaps write like this:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Me.Range("C7")) Is Nothing Then
If Me.Range("C7").Value = "No" Then
On Error GoTo SafeExit
Application.EnableEvents = False ' Avoid re-triggering the event
Me.Range("C9:C11").Value = "No"
End If
End If
SafeExit:
Application.EnableEvents = True
End Sub
Consider:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$C$7" And Target.Value = "No" Then
Application.EnableEvents = False
Range("$C$9").Value = "No"
Range("$C$10").Value = "No"
Range("$C$11").Value = "No"
Application.EnableEvents = True
End If
End Sub
and:
Sub C_B_Reset()
Application.EnableEvents = False
Sheet5.Range("C6:C7").ClearContents
Application.EnableEvents = True
End Sub
EDIT#1:
Try this event macro instead:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$C$7" Then
If Target.Value = "No" Then
Application.EnableEvents = False
Range("$C$9").Value = "No"
Range("$C$10").Value = "No"
Range("$C$11").Value = "No"
Application.EnableEvents = True
End If
End If
End Sub

How to simplify; dozens of Excel Tabs with the same underlying VBA Code

I have 51 unique tabs in a workbook. Each tab has a bit of code that will update the 52nd tab when certain cells are changed on the 51. Bottom line, it's an audit history of the 2 cells on each of the 51 tabs.
I've pieced together the following code that I drop onto each worsheets VBA section. The problem is that I have to do this for every single sheet in the workbook. I'd think that I should be able to have just a single common call to the meat of the VBA...
Dim PreVal
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Address = "$D$1" Or Target.Address = "$D$2" Then
PreVal = Target.Value
End If
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$D$1" Then
If Target.Value <> PreVal Then
SomethingSomewhere = Value
PreVal = Target.Value
End If
End If
If Target.Address = "$D$2" Then
If Target.Value <> PreVal Then
SomethingSomewhere = Value
PreVal = Target.Value
End If
End If
End Sub
It works wonderfully, just managing any changes needs to be done on every single sheet..
BTW, the SomethingSomewhere equals Value sets the app user name, sheet name, preval, target value, and date time into columns on the logging page
Create a subroutine that contains the logic and then create the application you drop on to each sheet. This application will call the subroutine. Now, when you change the subroutine, all of the sheets will pickup the same modification.
Instead of using the Worksheet events, use their corresponding Workbook events: Workbook.SheetSelectionChange and Workbook.SheetChange. These fire whenever any worksheet has a selection change or cell change.
Add these to the ThisWorkbook code module.
Dim PreVal
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
If Target.Address = "$D$1" Or Target.Address = "$D$2" Then
PreVal = Target.Value
End If
End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
On Error GoTo SafeExit
Application.EnableEvents = False
If Target.Address = "$D$1" Or Target.Address = "$D$2" Then
If Target.Value <> PreVal Then
SomethingSomewhere = Value
PreVal = Target.Value
End If
End If
SafeExit:
Application.EnableEvents = True
End Sub
You can modify these to ignore the logging page by checking Sh.Name, for example.

How do I fix non target cells from activating the sub Worksheet_Change(ByVal Target As Range)

My spread sheet has target cells and cells that I want to be able to enter manual data without the Worksheet Change to activate or run. How do I allow these open user cells to be populated without the private sub running??
More information sample code. There are many code sections like this in the same format.
Private sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = True
If Intersect(Target, Range("$B$8:$k$9")) Is Nothing Then
GoTo NEXT10
'Application.EnableEvents = False
End If
Application.EnableEvents = True
MsgBox Target.Address
'-------------------------------------------------------------------
'Application.EnableEvents = True
Application.EnableEvents = False
If Target.Address = "$B$8" Then
If Target.Value >= 0 Then
Range("B9") = Range("B8").Value * 42
End If
ElseIf Target.Address = "$B$9" Then
Range("B8") = Range("B9").Value / 42
End If
Application.EnableEvents = True
End Sub
The problem is if I enter, delete value or text in any empty cells on the worksheet, it activates the Worksheet_Change (ByVal Target ....).I use the If Intersect(Target,Range($B8$:$k$8) Is Nothing to bypass the target if no change. This format is used for other target ranges of important. But I do not understand why when any cell is changed the program runs?? Can this be avoid so various manual entries can be performed? For example text notes, labels, etc.
The Next10 is the start of another section of code but with diferent target address. If the target addess indicated is not intersected, it goes the check the next intersection.

VBA - Change cell value when clicked from/to yes/no for merged cells

I have created a form that will give the user the choice to pick from 7 different options whcih will all be default blank. When they click the cell next to the option it will change from blank to "yes" and when clicked again it will remove the text and so on. The issue I have its the cell that is clickable from blank to "yes" is merged between R33 and S33. The code works on the cell R33 alone but not when I merge them. Can you help me out with this please?
Private Sub Worksheet_SelectionChange(ByVal Target As Excel.Range)
Application.EnableEvents = False
If Target.Cells.Count = 1 Then
If Not Intersect(Target, Range("R33")) Is Nothing Then
Select Case Target.Value
Case ""
Target.Value = "yes"
Case "yes"
Target.Value = ""
End Select
Range("A1").Select
End If
End If
Application.EnableEvents = True
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Excel.Range)
On Error GoTo Worksheet_SelectionChange_Error
Application.EnableEvents = False
Debug.Print Target.Cells.Count 'just FYI, remove it later
If Not Intersect(Target.Cells(1), Range("R33").MergeArea) Is Nothing Then
Select Case Target.Cells(1)
Case "yes"
Target.Cells(1) = vbNullString
Case vbNullString
Target.Cells(1) = "yes"
End Select
End If
Range("A1").Select
Application.EnableEvents = True
On Error GoTo 0
Exit Sub
Worksheet_SelectionChange_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ")
Application.EnableEvents = True
End Sub
The merged cells are a bit evil in Excel, but if you play around a bit you can achieve what you need:
Target.Cells.Count is equal to the number of merged cells, thus it is never 1. I have deleted it;
Target.Cells(1) is the way to refer the first cell of the MergedArea;
Range("R33").MergeArea is a good way to check the intersect;
As sometimes while executing _SelectionChange event, you may get an error and then leave the Application.EnableEvents = False, it is a good practice to use an Error Catcher, which sets it back to True;

Worksheet_Change to hide rows in Excel

I have a macro that is supposed to hide a row in excel when a value of a given cell is "ODD" (the word, not an odd number). I've tried two different formats; neither gives any visible error but neither hides the row.
Sub Worksheet_Change(ByVal target As Range)
If target.Address <> "$B$2" Then Exit Sub
ElseIf Range("B2").Value = "ODD" Then
Rows("5:5").EntireRow.Hidden = False
Else
Rows("5:5").EntireRow.Hidden = True
End If
End If
End Sub
The other code I had is:
Select Case Range("B2").Value
Case Is = "ODD": Rows("5:5").EntireRow.Hidden = False
Case Else: Rows("5:5").EntireRow.Hidden = True
End Select
It was modified from a more advanced case statement and I just left it that way at first.
The Rows("5:5") would be better as Rows(5). The method you used would be better as Range("5:5").
Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$B$2" Then
Rows(5).EntireRow.Hidden = (UCase(Target.Value) = "ODD")
End If
End Sub
Since comparing B2 to ODD already produces a True or False, you can dispense with the If/Else/End If. Text comparisons in VBA are usually case sensitive, hence the need for UCase to force case insensitivity.
You are missing a key code line If Not Application.Intersect(cell, Range(Target.Address)) Is Nothing Then Try the following
Private Sub Worksheet_Change(ByVal Target As Range)
Dim cell As Range
Set cell = Range("B2")
If Not Application.Intersect(cell, Range(Target.Address)) Is Nothing Then
If Range("B2").Value = "ODD" Then
Rows("5:5").EntireRow.Hidden = False
Else
Rows("5:5").EntireRow.Hidden = True
End If
End If
End Sub
First make sure your Change Sub is stored in the Worksheet module of the Sheet you want this to perform on. Then you have a slight syntax error with your If Statements:
Private Sub Worksheet_Change(ByVal target As Range)
If target is Nothing Then Exit Sub
If target.Address <> "$B$2" Then Exit Sub
If Range("B2").Value = "ODD" Then
Rows("5:5").EntireRow.Hidden = True
Else
Rows("5:5").EntireRow.Hidden = False
End If
End Sub
When you put the If...Then... on one line, it actually closes the If (no End If needed) Also, I flipped your True and False statements to match your requirement in your question.

Resources