"Compile Error: ambiguous name detected: Worksheet_Change" notification - excel

I retrieved a helpful VBA command from the internet which allows me to change an arbitrary cell in Excel which acts as a filter for my pivot table. When I try to reuse this same command on the same sheet but for a different filter, I get a "Compile Error: ambiguous name detected: Worksheet_Change" notification and the code stops working... I tried to change "End Sub" to "Exit Sub" which did not work, and I am hoping someone can point me in the right direction here.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Target.Address = Range("D2").Address Then Exit Sub
Dim PT As PivotTable
Dim ptItem As PivotItem
On Error Resume Next
For Each PT In Worksheets("Tier Comps").PivotTables
With PT.PivotFields("Product")
If .EnableMultiplePageItems = True Then
.ClearAllFilters
End If
Set ptItem = .PivotItems(Target.Value)
If Not ptItem Is Nothing Then
.CurrentPage = Target.Value
End If
End With
Next
Exit Sub
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Target.Address = Range("D3").Address Then Exit Sub
Dim PT As PivotTable
Dim ptItem As PivotItem
On Error Resume Next
For Each PT In Worksheets("Tier Comps").PivotTables
With PT.PivotFields("Country Tier")
If .EnableMultiplePageItems = True Then
.ClearAllFilters
End If
Set ptItem = .PivotItems(Target.Value)
If Not ptItem Is Nothing Then
.CurrentPage = Target.Value
End If
End With
Next
End Sub
Hoping to have two separate cells modify two separate filters for one pivot table on the same sheet.

Please take a full read through --> https://stackoverflow.com/help/minimal-reproducible-example
One of the best parts about working through the process of making an MCVE is a lot of the time during the process of writing the question you will solve it yourself as you strip out more code to find the issue.
Here is a simplified answer, modify the MsgBox portion with your actual code.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("D2")) Is Nothing Then
MsgBox "Cell D2 Change Event"
End If
If Not Intersect(Target, Range("D3")) Is Nothing Then
MsgBox "Cell D3 Change Event"
End If
Exit Sub
Also, just for completeness sake. The issue is you can't have two subs with the same name. Another issue to look out for that I ran into is don't name Modules the same name as the sub. I usually add an _. Eg Module = Test_Sub and then Private Sub TestSub()

Related

Should I better modify some codes for .ClearContents?

I have simple macros for clearing cells on "Sheet1", which have drop down lists.
Sub reset1()
Range("D20:E21").ClearContents
Range("D8:E9").ClearContents
Range("D6:E7").ClearContents
End Sub
Sub reset2()
Range("D20:E21").ClearContents
Range("D8:E9").ClearContents
End Sub
Then I call these macros on "Sheet1" if the cell values change
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$D$4" Then
Call reset1
End If
If Target.Address = "$D$6" Then
Call reset2
End If
End Sub
This code is written on the "Sheet1".
Normally it works but sometimes reset1() doesn't work.
I should then save and reopen the excel or run the macro manually.
Should I better modify some codes?
First problem is that with Range("D20:E21") it is not clear in which worksheet that range should be. Always specify the worksheet like Worksheets("Sheet1").Range("D20:E21").
Second problem is that if you .ClearContents in a Worksheet_Change event this is a cell change and triggers another Worksheet_Change event and so on. So it is recommended to disable events Application.EnableEvents = False before changing cells in Worksheet_Change event.
Third problem is that if you test Target.Address = "$D$4" and you copy paste a range where D4 is included your code will not run even if your cell D4 changed. Therefore you always need to work with Intersect.
Option Explicit
Sub Reset1(ByVal ws As Worksheet)
ws.Range("D20:E21,D8:E9,D6:E7").ClearContents
' alternative:
' Union(ws.Range("D20:E21"), ws.Range("D8:E9"), ws.Range("D6:E7")).ClearContents
End Sub
Sub Reset2(ByVal ws As Worksheet)
ws.Range("D20:E21,D8:E9").ClearContents
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
On Error Goto ENABLE_EVENTS ' in any case an error happens make sure events are enabeld again
If Not Intersect(Target, Me.Range("D4")) Is Nothing Then
Reset1 Me ' here we tell Reset1 to take `Me` as worksheet. Me refers to the worksheet `Target` is in.
End If
If Not Intersect(Target, Me.Range("D6")) Is Nothing Then
Reset2 Me
End If
ENABLE_EVENTS:
Application.EnableEvents = True
If Err.Number Then
Err.Raise Err.Number
End If
End Sub

How to fix msgbox showing up twice When Cell Formula Result Changes?

I want a msgbox to show up only once when formula result changes in my table range ("K2:K5"). Right now it shows twice.
In this range I have excel-formulas. Formula: H12*10
These formulas is refering to a dropdown-list (a list that I've created from "data validation" on the excel menu Data-tab).
The dropdown-list is located in cell H12.
The values in the dropdown is refering to range(D15:D17)
I've noticed though that the msgbox shows up once when I remove the dropdown and manualy type in values in H12.
Thankful for any help on this
Private Sub Worksheet_Calculate()
Dim Xrg As Range
Set Xrg = Range("K2:K5")
If Not Intersect(Xrg, Range("K2:K5")) Is Nothing Then
MsgBox "Hi"
End If
End Sub
I have also tried to add Application.enableEvents to the code but no success.
Private Sub Worksheet_Calculate()
Dim Xrg As Range
Set Xrg = Range("K2:K5")
Application.EnableEvents = False
If Not Intersect(Xrg, Range("K2:K5")) Is Nothing Then
MsgBox "Hi"
End If
Application.EnableEvents = True
End Sub
Your current code has no added value on a Worksheet_Calculate event due to comparing two exact same ranges and see if they intersect. That would always be the case. Your code would have the same effect as:
Private Sub Worksheet_Calculate()
MsgBox "Hi"
End Sub
Might you have more functions in your worksheet that could trigger this event unwanted outside range K2:K5, you should look into the Worksheet_Change event and return a messagebox when your referenced cell has changed value.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$H$12" Then MsgBox "Hi"
End Sub
Choose either one, but don't use both cause you'll end up with two msgbox's

Which arguments should be used when calling a sub with parameters (ByVal Target As Range)

I'm making a macro on VBA that is attached to a data validation list in excel. When a certain option is selected from the list I want it to run a macro assigned to that selection. However I am repeatedly getting the error 'Compile error. Argument is not optional.' I understand I need to add parameters after calling the macro but anything I enter results in 'Object required' or 'expected )'
This code is in my worksheet. The line 'Case "Fifteen": Macro1' is the one with the error.
Private Sub Worksheet_change(ByVal Target As Range)
If Not Intersect(Target, Range("P4")) Is Nothing Then
Select Case Range("P4")
Case "Fifteen": Macro1
End Select
End If
End Sub
The following code is located in a module - It is used to copy values from the cells in one worksheet to another.
Sub Macro1(ByVal Target As Range)
Dim r1 As Range, r2 As Range
Set r1 = Sheets("Calculator").Range("C18:D19")
Set r2 = Sheets("Answers").Range("I14:J15")
If Intersect(Target, r1) Is Nothing Then Exit Sub
Application.EnableEvents = False
r2.Value = r1.Value
Application.EnableEvents = True
End Sub
Any idea's what the Argument parameters should be? I thought it would be along the lines of Case "Fifteen":Macro1("C18:D19") or Case "Fifteen":Macro1(r1), but no luck was had.
The code in the module works when it is on its own so I don't think there would be any issues with it.
Any help is greatly appreciated. I looked around and couldn't find an answer.
Thanks for the help. By removing the intersect lines it now works as intended. The final code is below.
Private Sub Worksheet_change(ByVal Target As Range)
Select Case Range("P4")
Case "Fifteen": Macro1
End Select
End If
End Sub
Sub Macro1()
Dim r1 As Range, r2 As Range
Set r1 = Sheets("Calculator").Range("C18:D19")
Set r2 = Sheets("Answers").Range("I14:J15")
Application.EnableEvents = False
r2.Value = r1.Value
Application.EnableEvents = True
End Sub

Hide rows section of code not working with other macro code

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

excel VBA run macro automatically whenever a cell is changed

Is there a simple way to get Excel to automatically execute a macro whenever a cell is changed?
The cell in question would be in Worksheet("BigBoard").Range("D2")
What I thought would be a simple Google inquiry is proving to be more complicated - every sample involved intersects (whatever those are) or color formatting or any other number of things that appear to be irrelevant.
Yes, this is possible by using worksheet events:
In the Visual Basic Editor open the worksheet you're interested in (i.e. "BigBoard") by double clicking on the name of the worksheet in the tree at the top left. Place the following code in the module:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Me.Range("D2")) Is Nothing Then Exit Sub
Application.EnableEvents = False 'to prevent endless loop
On Error Goto Finalize 'to re-enable the events
MsgBox "You changed THE CELL!"
Finalize:
Application.EnableEvents = True
End Sub
Another option is
Private Sub Worksheet_Change(ByVal Target As Range)
IF Target.Address = "$D$2" Then
MsgBox("Cell D2 Has Changed.")
End If
End Sub
I believe this uses fewer resources than Intersect, which will be helpful if your worksheet changes a lot.
In an attempt to find a way to make the target cell for the intersect method a name table array, I stumbled across a simple way to run something when ANY cell or set of cells on a particular sheet changes. This code is placed in the worksheet module as well:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.Count > 0 Then
'mycode here
end if
end sub
In an attempt to spot a change somewhere in a particular column (here in "W", i.e. "23"), I modified Peter Alberts' answer to:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Target.Column = 23 Then Exit Sub
Application.EnableEvents = False 'to prevent endless loop
On Error GoTo Finalize 'to re-enable the events
MsgBox "You changed a cell in column W, row " & Target.Row
MsgBox "You changed it to: " & Target.Value
Finalize:
Application.EnableEvents = True
End Sub
I was creating a form in which the user enters an email address used by another macro to email a specific cell group to the address entered. I patched together this simple code from several sites and my limited knowledge of VBA. This simply watches for one cell (In my case K22) to be updated and then kills any hyperlink in that cell.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
' The variable KeyCells contains the cells that will
' cause an alert when they are changed.
Set KeyCells = Range("K22")
If Not Application.Intersect(KeyCells, Range(Target.Address)) _
Is Nothing Then
Range("K22").Select
Selection.Hyperlinks.Delete
End If
End Sub

Resources