dependent validation lists fire worksheet change event

ajm

Well-known Member
Joined
Feb 5, 2003
Messages
2,011
Office Version
  1. 365
Platform
  1. Windows
is it possible to have a worksheet change event triggered by the selection of an option button? where i am at today: i have an event that fires when the user selects from two validation lists on the worksheet. the second validation list (customer accounts) is dependent upon the first (account managers). the resulting selection, of account manager and one of their accounts, is then used to filter two pivot tables to compare this years to last years sales.

the worksheet change event fires when either of the two cells is changed. the code is below:
Code:
Private Sub Worksheet_Change(ByVal Target As Range)
    Dim critRange As Range, c As Range, ws As Worksheet, PT As PivotTable
    Set critRange = Range("C2:C3")
    If Intersect(Target, critRange) Is Nothing Then GoTo CleanUp

    Dim pi As PivotItem
    Dim i As Long, j As Long
    Dim strFields() As String, strValue As String
    Dim graphSheets As Variant
    strFields = Split("Master Account Manager;Debtor Normal Name", ";")
    Set graphSheets = Sheets(Array("Rep Sales Data", "TY Sales Data"))
    
    On Error GoTo CleanUp
    Application.EnableEvents = False
    Application.ScreenUpdating = False

    For Each ws In graphSheets 'Sheets(Array("Rep Sales Data", "TY Sales Data"))
        'With Worksheets("Rep Sales Data").PivotTables("PivotTableRepSaleData")
        For i = 1 To critRange.Rows.Count
            strValue = critRange(i).Value
            For Each PT In ws.PivotTables
            With PT.PivotFields(strFields(i - 1))
                Select Case .Orientation
                Case xlPageField
                    .ClearAllFilters
                    For Each pi In .PivotItems
                        If pi.Value = strValue Then
                            .CurrentPage = strValue
                            Exit For
                        Else
                            .CurrentPage = "(All)"
                        End If
                    Next pi
                Case Else
                    .PivotItems(strValue).Visible = True
                    For j = 1 To .PivotItems.Count
                        If .PivotItems(j) <> strValue And _
                           .PivotItems(j).Visible = True Then
                            .PivotItems(j).Visible = False
                        End If
                    Next j
                End Select
            End With
            Next PT
        Next i
    Next ws

    Application.Calculate
CleanUp:
    Application.EnableEvents = True
End Sub

how do i get the second list (customers) to reset to All when the account manager is changed? the underlying pivot tables reset the second filter to all when the worksheet event runs but this doesn't carry through to my active worksheet.

<!-- Please do not remove this header -->
<!-- Table easily created from Excel with ASAP Utilities (http://www.asap-utilities.com) -->
<table border="1" bordercolor="#C0C0C0" bordercolordark="#FFFFFF" cellspacing="0" cellpadding="2" align="left">
<tr><th bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"> </font></th><th bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"> </font></th><th bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"> </font></th><th bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"> </font></th></tr>
<tr><td bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"> </font></td><td bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000">Master Account Manager</font></td><td bgcolor="#FFFFFF" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"><b>UNALLOCATED</b></font></td><td bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"> </font></td></tr>
<tr><td bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"> </font></td><td bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000">Select Customer Group</font></td><td bgcolor="#FFFFFF" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000">AKSU KEBAB</font></td><td bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"> </font></td></tr>
<tr><td bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"> </font></td><td bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000">Select Customer Account</font></td><td bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"> </font></td><td bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"> </font></td></tr>
<tr><td bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"> </font></td><td bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"> </font></td><td bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"> </font></td><td bgcolor="#FFFFFF" align="right" valign="bottom" style="white-space: nowrap"><font face="Tahoma" size="2" color="#000000"> </font></td></tr>
</table>

so, when the Master Account Manager is changed, the cell below it should reset to "All" rather than holding the previously selected customer name.
 

Excel Facts

Easy bullets in Excel
If you have a numeric keypad, press Alt+7 on numeric keypad to type a bullet in Excel.
Hello,


Yes, an option button can be an event.


Using an ActiveX option button, right click the option button and select veiw code.

<font face=Courier New><SPAN style="color:#00007F">Private</SPAN> <SPAN style="color:#00007F">Sub</SPAN> OptionButton1_Click()<br><br><SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">Sub</SPAN></FONT>
 
Upvote 0
thanks for that jeff. i missed that first line when i edited my inital post. i forgot to delete it. i think using something to "reset" my second validation list will be a better method for my immediate needs
 
Last edited:
Upvote 0
i have struggled for the last couple of days to amend this worksheet change event and am at my wits end. currently, the code is used to change the filters on two pivot tables
when the user changes the selections in two cells on sheet "Annual Results".
the cells contain Account Manager and then the customers managed by the selected account manager. the values in the second are dependent upon the selection in the first cell.
I do not completely understand the way the code works so have been unsuccesful with the change attempts i have made. the result i want to achieve is that when the account manager is changed, the customer list in the second cell displays the value "All". then, if the user chooses to proceed they may select a particular customer from the particular account manager's list. basically, if they want to look at the account managers efforts overall, they would just select the relevant name in the first drop down. this would effectively clear the filters in the Customer accounts field (Debtor Normal Name) in both pivot tables. If the user wanted to see how a particular customer account is being managed, they would first select the account manager and then continue to select the customer form the second validation list.

any help would be greatly appreciated.
 
Upvote 0
I have not used pivot tables. I have looked at the code and it gets confusing with all the variables and references to pivot table properties and objects of which I haven't used.


You mentioned two pivot tables. What sheet is each pivot table on?

What sheet is this code on? (if on a different sheet than you customer p/t)

Is there a specific cell that when changed should trigger the customers filter to all?



I have some ideas, but I can't say any one will absolutly work.
:rolleyes:
 
Upvote 0
hi repairman. it is confusing, and at first, even more so. the code for pivot tables is new to me but it could be very useful i think.

what this code does is
Code:
Private Sub Worksheet_Change(ByVal Target As Range)
    Dim critRange As Range, c As Range, ws As Worksheet, PT As PivotTable
    Set critRange = Range("C2:C3") '/// changes in these two will fire this event
    If Intersect(Target, critRange) Is Nothing Then GoTo CleanUp '/// if change not the target range, go to Clean UP

    Dim pi As PivotItem
    Dim i As Long, j As Long
    Dim strFields() As String, strValue As String
    Dim graphSheets As Variant
    
    strFields = Split("Master Account Manager;Debtor Normal Name", ";") '///don't properly understand Split, except
    '/// it seems to allow the variable strFields to accept variable from both C2 & C3
    Set graphSheets = Sheets(Array("Rep Sales Data", "TY Sales Data")) '/// pivot tables on these sheets

    On Error GoTo CleanUp
    Application.EnableEvents = False
    Application.ScreenUpdating = False

    For Each ws In graphSheets
        For i = 1 To critRange.Rows.Count '/// critRange is two cells C2 & C3, so C2 = 1 and C3 =2
            strValue = critRange(i).Value '///first loop gives (i) the value of 1, 2nd loop 2
            For Each PT In ws.PivotTables '/// for each of the pivot tables on each of the sheets in the array

                With PT.PivotFields(strFields(i - 1)) '/// i think this somehow ties in to the use of split above
                '/// as split definition refers to a zero based, one dimensional array?
                    Select Case .Orientation '/// not really sure
                    Case xlPageField '///if case is xlpagefield, clear all filters
                        .ClearAllFilters
                        For Each pi In .PivotItems '///now look at items in val list (c2)
                            If pi.Value = strValue Then
                                .CurrentPage = strValue '///make the page filter equal to selection from val list
                                Exit For
                            Else
                                .CurrentPage = "(All)" '///reverts to All until there is a match
                            End If
                        Next pi

                    Case Else
                        .PivotItems(strValue).Visible = True
                        For j = 1 To .PivotItems.Count
                            If .PivotItems(j) <> strValue And _
                               .PivotItems(j).Visible = True Then
                                .PivotItems(j).Visible = False '///not entirely sure here except that if a change has been made to C3
                                '/// this loops through each pivot item in the available list and if it differs to C3, hide it.
                            End If
                        Next j
                    End Select
                End With
            Next PT
        Next i
    Next ws

    Application.Calculate
CleanUp:
    Application.EnableEvents = True
End Sub

so, my validation drop downs are on sheet "Annual Results" and so holds the change event code. the cells C2 (Master Account Manager) and C3 (Debtor Normal Name) on this sheet trigger the event. the pivot tables are on two sheets entitled, "TY Sales Data", and "Rep Sales Data".

I look forward to hearing your ideas. many thanks for having a look
 
Upvote 0
Hello ajm,

Here may be the first attempt of many. May we learn form out mistakes. :)

If nothing else we will keep bumping this to the top. I am certain this can be done and if not by either of us stumbling upon the solution, then surely another whom is more familiar with p/t code.

If I have time tomorrow I will try to simulate a workbook so I could test the code. If the WB is not proprietary and does not contain sensitive information, maybe upload to box.net or other site.

I have tried a seperate logical test to isolate cell C2 for change and if so, changed C3 to the string "All".

I am not sure if this will change the filter on the pivot table, just seemed like a good starting point to me.

<font face=Courier New><SPAN style="color:#00007F">Private</SPAN> <SPAN style="color:#00007F">Sub</SPAN> Worksheet_Change(<SPAN style="color:#00007F">ByVal</SPAN> Target <SPAN style="color:#00007F">As</SPAN> Range)<br>    <SPAN style="color:#00007F">Dim</SPAN> critRange <SPAN style="color:#00007F">As</SPAN> Range, c <SPAN style="color:#00007F">As</SPAN> Range, ws <SPAN style="color:#00007F">As</SPAN> Worksheet, PT <SPAN style="color:#00007F">As</SPAN> PivotTable<br>    <SPAN style="color:#00007F">Set</SPAN> critRange = Range("C2:C3") <SPAN style="color:#007F00">'/// changes in these two will fire this event</SPAN><br>    <SPAN style="color:#00007F">If</SPAN> Intersect(Target, critRange) <SPAN style="color:#00007F">Is</SPAN> <SPAN style="color:#00007F">Nothing</SPAN> <SPAN style="color:#00007F">Then</SPAN> <SPAN style="color:#00007F">GoTo</SPAN> CleanUp <SPAN style="color:#007F00">'/// if change not the target range, go to Clean UP</SPAN><br><br><SPAN style="color:#007F00">''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''</SPAN><br>    <SPAN style="color:#00007F">If</SPAN> <SPAN style="color:#00007F">Not</SPAN> Intersect(Target, Range("C2")) <SPAN style="color:#00007F">Is</SPAN> <SPAN style="color:#00007F">Nothing</SPAN> <SPAN style="color:#00007F">Then</SPAN> Range("C3").Value = "All"<br><SPAN style="color:#007F00">''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''</SPAN><br>    <br>    <SPAN style="color:#00007F">Dim</SPAN> pi <SPAN style="color:#00007F">As</SPAN> PivotItem<br>    <SPAN style="color:#00007F">Dim</SPAN> i <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>, j <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN><br>    <SPAN style="color:#00007F">Dim</SPAN> strFields() <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">String</SPAN>, strValue <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">String</SPAN><br>    <SPAN style="color:#00007F">Dim</SPAN> graphSheets <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Variant</SPAN><br>    <br>    strFields = Split("Master Account Manager;Debtor Normal Name", ";") <SPAN style="color:#007F00">'///don't properly understand Split, except</SPAN><br>    <SPAN style="color:#007F00">'/// it seems to allow the variable strFields to accept variable from both C2 & C3</SPAN><br>    <SPAN style="color:#00007F">Set</SPAN> graphSheets = Sheets(Array("Rep Sales Data", "TY Sales Data")) <SPAN style="color:#007F00">'/// pivot tables on these sheets</SPAN><br><br>    <SPAN style="color:#00007F">On</SPAN> <SPAN style="color:#00007F">Error</SPAN> <SPAN style="color:#00007F">GoTo</SPAN> CleanUp<br>    Application.EnableEvents = <SPAN style="color:#00007F">False</SPAN><br>    Application.ScreenUpdating = <SPAN style="color:#00007F">False</SPAN><br><br>    <SPAN style="color:#00007F">For</SPAN> <SPAN style="color:#00007F">Each</SPAN> ws <SPAN style="color:#00007F">In</SPAN> graphSheets<br>        <SPAN style="color:#00007F">For</SPAN> i = 1 <SPAN style="color:#00007F">To</SPAN> critRange.Rows.Count <SPAN style="color:#007F00">'/// critRange is two cells C2 & C3, so C2 = 1 and C3 =2</SPAN><br>            strValue = critRange(i).Value <SPAN style="color:#007F00">'///first loop gives (i) the value of 1, 2nd loop 2</SPAN><br>            <SPAN style="color:#00007F">For</SPAN> <SPAN style="color:#00007F">Each</SPAN> PT <SPAN style="color:#00007F">In</SPAN> ws.PivotTables <SPAN style="color:#007F00">'/// for each of the pivot tables on each of the sheets in the array</SPAN><br><br>                <SPAN style="color:#00007F">With</SPAN> PT.PivotFields(strFields(i - 1)) <SPAN style="color:#007F00">'/// i think this somehow ties in to the use of split above</SPAN><br>                <SPAN style="color:#007F00">'/// as split definition refers to a zero based, one dimensional array?</SPAN><br>                    <SPAN style="color:#00007F">Select</SPAN> <SPAN style="color:#00007F">Case</SPAN> .Orientation <SPAN style="color:#007F00">'/// not really sure</SPAN><br>                    <SPAN style="color:#00007F">Case</SPAN> xlPageField <SPAN style="color:#007F00">'///if case is xlpagefield, clear all filters</SPAN><br>                        .ClearAllFilters<br>                        <SPAN style="color:#00007F">For</SPAN> <SPAN style="color:#00007F">Each</SPAN> pi <SPAN style="color:#00007F">In</SPAN> .PivotItems <SPAN style="color:#007F00">'///now look at items in val list (c2)</SPAN><br>                            <SPAN style="color:#00007F">If</SPAN> pi.Value = strValue <SPAN style="color:#00007F">Then</SPAN><br>                                .CurrentPage = strValue <SPAN style="color:#007F00">'///make the page filter equal to selection from val list</SPAN><br>                                <SPAN style="color:#00007F">Exit</SPAN> <SPAN style="color:#00007F">For</SPAN><br>                            <SPAN style="color:#00007F">Else</SPAN><br>                                .CurrentPage = "(All)" <SPAN style="color:#007F00">'///reverts to All until there is a match</SPAN><br>                            <SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">If</SPAN><br>                        <SPAN style="color:#00007F">Next</SPAN> pi<br><br>                    <SPAN style="color:#00007F">Case</SPAN> <SPAN style="color:#00007F">Else</SPAN><br>                        .PivotItems(strValue).Visible = <SPAN style="color:#00007F">True</SPAN><br>                        <SPAN style="color:#00007F">For</SPAN> j = 1 <SPAN style="color:#00007F">To</SPAN> .PivotItems.Count<br>                            <SPAN style="color:#00007F">If</SPAN> .PivotItems(j) <> strValue And _<br>                               .PivotItems(j).Visible = <SPAN style="color:#00007F">True</SPAN> <SPAN style="color:#00007F">Then</SPAN><br>                                .PivotItems(j).Visible = <SPAN style="color:#00007F">False</SPAN> <SPAN style="color:#007F00">'///not entirely sure here except that if a change has been made to C3</SPAN><br>                                <SPAN style="color:#007F00">'/// this loops through each pivot item in the available list and if it differs to C3, hide it.</SPAN><br>                            <SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">If</SPAN><br>                        <SPAN style="color:#00007F">Next</SPAN> j<br>                    <SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">Select</SPAN><br>                <SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">With</SPAN><br>            <SPAN style="color:#00007F">Next</SPAN> PT<br>        <SPAN style="color:#00007F">Next</SPAN> i<br>    <SPAN style="color:#00007F">Next</SPAN> ws<br><br>    Application.Calculate<br>CleanUp:<br>    Application.EnableEvents = <SPAN style="color:#00007F">True</SPAN><br><SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">Sub</SPAN><br><br></FONT>
 
Upvote 0
Jeff,

I tried the isolation method as you have written above. However, while it changes the displayed value in C3 to "All", it only effects the first pivot table on "Rep Sales Data" tab. The Master Account Manager is correctly changed to the selection made in C2, but the Debtor Normal Name is not changed. Nothing on the second PT on "TY Sales Data" tab is changed. so essentially, the isolation that you suggested changes the initial account manager field on the first pivot table and then also the text that shows in C3 on the Annual Results tab.

I have joined box.net and once i get home, will activate the account and load up an example workbook for us to play with.

cheers ajm
 
Upvote 0
Jeff, i have had a breakthrough. using two combo boxes instead of validation lists, i have bastardised the code originally written and now have two macros: the first looks at the Master Account Manager and also sets the linked cell of the second to "0". i put an iferror formula

=IFERROR(INDEX(SalesNameNormNameListActive,D3),"All Accounts")

in C3 to show the user that if they don't go on to make a second selection (Debtor), they will see "All Accounts" for the chosen Master Account Manager.

Then the second combo box just changes the pivot items visible in the Debtor Normal Name field of the pivot tables.

Code:
Sub ChooseMAM()

    Dim critRange As Range, c As Range, ws As Worksheet, PT As PivotTable, pi As PivotItem
    Set critRange = Worksheets("Annual Results").Range("C2")
    Dim strFields As String, strFields2 As String
    Dim graphSheets As Variant
    strFields = Worksheets("Annual Results").Range("b2").Value
    strFields2 = "Debtor Normal Name"

    strValue = critRange.Value
    Worksheets("Annual Results").Range("D3").Value = "0"

    Set graphSheets = Sheets(Array("Rep Sales Data", "TY Sales Data"))

    For Each ws In graphSheets
        For Each PT In ws.PivotTables
            With PT.PivotFields(strFields2)
                .ClearAllFilters
            End With

            With PT.PivotFields(strFields)
                .ClearAllFilters
                For Each pi In PT.PivotFields(strFields).PivotItems
                    If pi.Value = strValue Then
                        .CurrentPage = strValue
                        Exit For
                    Else
                        .CurrentPage = "(All)"
                    End If
                Next pi
            End With
        Next PT
    Next ws


End Sub

Sub ChooseAccount()

    Dim AccountRange As Range, c As Range, ws As Worksheet, PT As PivotTable, pi As PivotItem
    Dim strDebtorName As String, strFields2 As String
    Dim graphSheets As Variant
    Dim j As Long

    strFields2 = "Debtor Normal Name"
    Set AccountRange = Worksheets("Annual Results").Range("c3")
    strDNValue = AccountRange.Value

    Set graphSheets = Sheets(Array("Rep Sales Data", "TY Sales Data"))

    For Each ws In graphSheets
        For Each PT In ws.PivotTables

            With PT.PivotFields(strFields2)
                For Each pi In PT.PivotFields(strFields2).PivotItems

                    For j = 1 To .PivotItems.Count
                        If .PivotItems(j) <> strDNValue And _
                           .PivotItems(j).Visible = True Then
                            .PivotItems(j).Visible = False
                        End If
                    Next j

                Next pi
            End With
        Next PT
    Next ws


End Sub

its past 5pm here so i will leave the tidy up of this until tomorrow. it still needs further refinement and testing properly, but should get me across the line so i can put this one to bed.

do you see any potential problems going this route instead of the worksheet change event way?

cheers

ajm

PS how do you get your code to show up so nicely on the boards? i use code tags with the square brackets but it still looks like garbage next to your lines.
 
Upvote 0

Forum statistics

Threads
1,215,831
Messages
6,127,147
Members
449,364
Latest member
AlienSx

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top