Forum Discussion

BriceChapman's avatar
BriceChapman
Copper Contributor
Jan 10, 2024
Solved

Filtering Pivot Table with VBA

Hi everyone,

 

I am trying to filter a pivot table for values in a list with VBA, but I keep receiving errors that VBA is "Unable to set the visible property of the PivotItem class". I think this is because the pivot table does not always have all the items from the list, and when VBA sees that one of the items is missing it gives me this error. Here is the VBA I have:

 

Dim vArray As Variant
Dim i As Integer, j As Integer
Dim pvFld As PivotField
Set pvFld = ActiveSheet.PivotTables("PivotTable1").PivotFields("Processing Area")
vArray = Sheets("Deal Admin List").Range("D2:D4")
pvFld.ClearAllFilters

With pvFld
For i = 1 To pvFld.PivotItems.Count
j = 1
Do While j <= UBound(vArray, 1) - LBound(vArray, 1) + 1
If pvFld.PivotItems(i).Name = vArray(j, 1) Then
pvFld.PivotItems(pvFld.PivotItems(i).Name).Visible = True
Exit Do
Else
pvFld.PivotItems(pvFld.PivotItems(i).Name).Visible = False
End If
j = j + 1
Loop
Next i
End With

End Sub

 

 

I am trying to filter the "Processing Area" field for Houston, Chicago, and Delaware, (which is the list in D2:D4) but the "Processing Area" in the pivot table does not always have every value in the list from D2:D4, sometimes Houston is not in the pivot table, so is there a way to write the VBA so that it should filter "Processing Area" for any values that appear in the list without giving an error if one of those values is not there? Thank you, let me know if you need further clarification to assist.

  • BriceChapman A couple of questions/comments:

    1. Is the "Processing Area" field located in the Filters Area or the Rows Area of the pivot table?
    2. Is the "Unable to set the Visible property of the PivotItem class" error occurring on the line of code that sets the Visible property to True or False?

     

    If the error occurs when setting the Visible property to True, it's most likely because the Pivot Item no longer exists in the source table but has been retained as a Pivot Item due to the pivot table settings. One possible solution is to change this setting: right-click on the pivot table and select Pivot Table Options... then, on the Data tab, under "Retain items deleted from the data source", change the "Number of items to retain per field" from "Automatic" to "None". Then refresh the table to remove any pivot items that no longer exist.

     

    Alternatively, the problem can also be avoided in this case by omitting the code to set the Visible property to True. Since the procedure begins by clearing all filters from the Pivot Field (pvFld.ClearAllFilters), you only need to change the Visible property of each applicable Pivot Item to False. You could also improve performance by only setting the property once at the end of the loop, if the Pivot Item was not found in the entire list:

     

    Sub FilterPivotTableFromList()
        Dim vArray As Variant
        vArray = Worksheets("Deal Admin List").Range("D2:D4").Value
    
        Dim pvFld As PivotField, found As Boolean, i As Long, j As Long
        Set pvFld = ActiveSheet.PivotTables("PivotTable1").PivotFields("Processing Area")
        With pvFld
            .ClearAllFilters
            For i = 1 To .PivotItems.Count
                found = False
                For j = LBound(vArray, 1) To UBound(vArray, 1)
                    If .PivotItems(i).Name = vArray(j, 1) Then
                        found = True
                        Exit For
                    End If
                Next j
                If Not found Then .PivotItems(i).Visible = False
            Next i
        End With
    End Sub

     

    Having said that, the error may also occur when setting the Visible property to False, if NONE of the Pivot Items were found in the list, in which case the pivot table will not allow setting the Visible property of ALL Pivot Items in a Pivot Field to False. One lazy option would be to use On Error Resume Next, which would leave the last Pivot Item visible. Or you could write some additional code to handle this situation as follows:

     

    Sub FilterPivotTableFromList()
        Dim vArray As Variant
        vArray = Worksheets("Deal Admin List").Range("D2:D4").Value
    
        Dim pvFld As PivotField, found As Boolean, n As Long, i As Long, j As Long
        Set pvFld = ActiveSheet.PivotTables("PivotTable1").PivotFields("Processing Area")
        With pvFld
            .ClearAllFilters
            For i = 1 To .PivotItems.Count
                found = False
                For j = LBound(vArray, 1) To UBound(vArray, 1)
                    If .PivotItems(i).Name = vArray(j, 1) Then
                        found = True
                        n = n + 1
                        Exit For
                    End If
                Next j
                If i = .PivotItems.Count And n = 0 Then
                    .ClearAllFilters
                    MsgBox "Unable to filter by the list of pivot items", _
                        vbExclamation, "No items found"
                ElseIf Not found Then
                    .PivotItems(i).Visible = False
                End If
            Next i
            .EnableMultiplePageItems = True 'if located in the Filters Area of the pivot table
        End With
    End Sub

     

    Note: I also used .EnableMultiplePageItems = True in this last example, which may be required if the Pivot Field is located in the Filter Area of the pivot table.

6 Replies

  • djclements's avatar
    djclements
    Bronze Contributor

    BriceChapman A couple of questions/comments:

    1. Is the "Processing Area" field located in the Filters Area or the Rows Area of the pivot table?
    2. Is the "Unable to set the Visible property of the PivotItem class" error occurring on the line of code that sets the Visible property to True or False?

     

    If the error occurs when setting the Visible property to True, it's most likely because the Pivot Item no longer exists in the source table but has been retained as a Pivot Item due to the pivot table settings. One possible solution is to change this setting: right-click on the pivot table and select Pivot Table Options... then, on the Data tab, under "Retain items deleted from the data source", change the "Number of items to retain per field" from "Automatic" to "None". Then refresh the table to remove any pivot items that no longer exist.

     

    Alternatively, the problem can also be avoided in this case by omitting the code to set the Visible property to True. Since the procedure begins by clearing all filters from the Pivot Field (pvFld.ClearAllFilters), you only need to change the Visible property of each applicable Pivot Item to False. You could also improve performance by only setting the property once at the end of the loop, if the Pivot Item was not found in the entire list:

     

    Sub FilterPivotTableFromList()
        Dim vArray As Variant
        vArray = Worksheets("Deal Admin List").Range("D2:D4").Value
    
        Dim pvFld As PivotField, found As Boolean, i As Long, j As Long
        Set pvFld = ActiveSheet.PivotTables("PivotTable1").PivotFields("Processing Area")
        With pvFld
            .ClearAllFilters
            For i = 1 To .PivotItems.Count
                found = False
                For j = LBound(vArray, 1) To UBound(vArray, 1)
                    If .PivotItems(i).Name = vArray(j, 1) Then
                        found = True
                        Exit For
                    End If
                Next j
                If Not found Then .PivotItems(i).Visible = False
            Next i
        End With
    End Sub

     

    Having said that, the error may also occur when setting the Visible property to False, if NONE of the Pivot Items were found in the list, in which case the pivot table will not allow setting the Visible property of ALL Pivot Items in a Pivot Field to False. One lazy option would be to use On Error Resume Next, which would leave the last Pivot Item visible. Or you could write some additional code to handle this situation as follows:

     

    Sub FilterPivotTableFromList()
        Dim vArray As Variant
        vArray = Worksheets("Deal Admin List").Range("D2:D4").Value
    
        Dim pvFld As PivotField, found As Boolean, n As Long, i As Long, j As Long
        Set pvFld = ActiveSheet.PivotTables("PivotTable1").PivotFields("Processing Area")
        With pvFld
            .ClearAllFilters
            For i = 1 To .PivotItems.Count
                found = False
                For j = LBound(vArray, 1) To UBound(vArray, 1)
                    If .PivotItems(i).Name = vArray(j, 1) Then
                        found = True
                        n = n + 1
                        Exit For
                    End If
                Next j
                If i = .PivotItems.Count And n = 0 Then
                    .ClearAllFilters
                    MsgBox "Unable to filter by the list of pivot items", _
                        vbExclamation, "No items found"
                ElseIf Not found Then
                    .PivotItems(i).Visible = False
                End If
            Next i
            .EnableMultiplePageItems = True 'if located in the Filters Area of the pivot table
        End With
    End Sub

     

    Note: I also used .EnableMultiplePageItems = True in this last example, which may be required if the Pivot Field is located in the Filter Area of the pivot table.

    • BriceChapman's avatar
      BriceChapman
      Copper Contributor
      Thank you so much this works! I am using the second portion of code you sent and it works perfectly except when there are no pivot items in the list. It does not give the popup message box, it just gives me the error "Unable to set the Visible property of the PivotItem class". I dont think I need the pop up box, but I do still need to be able to filter for the list even if there is nothing there.

      I tried using the On Error Resume Next, but you were right that it just leaves the last selected pivot item but that will not work for what we need to do. Is there any other way to be able to filter for this list and even if all of their visible property's are false, it still filters without giving an error?

      Thank you so much for all your help!
      • djclements's avatar
        djclements
        Bronze Contributor

        BriceChapman If the Pivot Field is located in either the Rows or Columns area of the Pivot Table, you could add a "Labels Filter" equal to some random text string that doesn't exist as a Pivot Item (ie: "zzz"), which will return no records. For example, you could try something along these lines...

         

        Sub FilterPivotTableFromList()
            Dim vArray As Variant
            vArray = Worksheets("Deal Admin List").Range("D2:D4").Value
        
            Dim pvFld As PivotField, found As Boolean, i As Long, j As Long
            Set pvFld = ActiveSheet.PivotTables("PivotTable1").PivotFields("Processing Area")
        
            On Error GoTo ErrorHandler
            With pvFld
                .ClearAllFilters
                For i = 1 To .PivotItems.Count
                    found = False
                    For j = LBound(vArray, 1) To UBound(vArray, 1)
                        If .PivotItems(i).Name = vArray(j, 1) Then
                            found = True
                            Exit For
                        End If
                    Next j
                    If Not found Then .PivotItems(i).Visible = False
                Next i
            End With
            Exit Sub
        
        ErrorHandler:
            If Err.Description Like "*Visible property*PivotItem*" Then
            ' this method will NOT work if the PivotField is located in the Filters Area
                pvFld.PivotFilters.Add2 Type:=xlCaptionEquals, Value1:="zzz"
            Else
                MsgBox Err.Description, vbExclamation, "Runtime Error: " & Err.Number
            End If
        End Sub

         

        Please note the PivotFilters.Add2 method cannot be used on a Pivot Field that has been placed in the Filters area of the Pivot Table. Attempting to do so will result in the "Application-defined or object-defined error".

Resources