I have three slicers operating on a pivot table and pivot chart in excel. However, the filters placed from the two other slicers has to be cleared, when one of the slicers is pressed, assuring that only one slicer is operating at the same time. I think this has to be solved using VBA, listening for a click then executing code, other than that I have no idea as I have never worked with Excel or VBA before.
Anyone got any suggestions on how I would do this?
Working out what Slicer got clicked is very tricky indeed, because the only application event that gets raised by clicking on a slicer is the PivotTable_Update event. This event tells us which PivotTable the slicer is connected to, but not which field in that PivotTable got filtered. So if you have multiple silcers connected to a PivotTable, you can't tell which one was just clicked on.
I came up with a very convoluted workaround that I posted at http://dailydoseofexcel.com/archives/2014/07/10/what-caused-that-pivottableupdate-episode-iv/ that will get you part the way there: it will tell you which field in a PivotTable just got updated, and then you just need to iterate through all the slicers connected to that PivotTable and clear them if they don't have the same sourcename.
I'll see if I can code something up in due course, but I'm pretty busy at present so I can't promise a fast resolution.
Note that you can assign a macro directly to a slicer that gets triggered when a user clicks on it, and from that you can determine which slicer it is. But unfortunately that macro interferes with the slicer itself: a user can no longer actually operate the slicer to actually change anything.
---UPDATE---
Here's some code that does what you want. There's a lot of different modules here, because the routine code calls quite a few other generic routines I use. And at it's heart is a routine that works out which particular field of a PivotTable gets updated, and that doesn't care if multilpe fields are filtered.
You call it with this event handler, which goes in the ThisWorkbook module for the book in the Visual Basic Editor:
Private Sub Workbook_SheetPivotTableUpdate(ByVal Sh As Object, ByVal Target As PivotTable)
Slicers_OneSlicerOnly Target
End Sub
And that calls these other functions in turn. You don't have to amend anything, and this works on any PivotTables or Slicers you add to this workbook.
Function Slicers_OneSlicerOnly(target As PivotTable)
Dim sField As String
Dim slr As Slicer
Dim sSlicer As String
Dim bEnableEvents As Boolean
Dim bScreenUpdating As Boolean
Dim bManualupdate As Boolean
Dim lCalculation As Long
Dim bRecordLayout As Boolean
Dim sLayout_New As String
Dim sLayout_Old As String
Dim lng As Long
With Application
bEnableEvents = .EnableEvents
bScreenUpdating = .ScreenUpdating
lCalculation = .Calculation
.EnableEvents = False
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
bManualupdate = target.ManualUpdate
target.ManualUpdate = True
sField = Pivots_FieldChange(target)
If sField <> "" Then
For Each slr In target.Slicers
sSlicer = slr.SlicerCache.SourceName
If sSlicer <> sField Then
If Not target.PivotFields(sSlicer).AllItemsVisible Then
target.PivotFields(sSlicer).ClearAllFilters
bRecordLayout = True
End If
End If
Next slr
End If
target.ManualUpdate = bManualupdate
If bRecordLayout Then
PivotChange_RecordLayout target, sLayout_New
With target
lng = InStr(.Summary, "[Layout]")
sLayout_Old = Mid(.Summary, lng + Len("[Layout]"), InStr(.Summary, "[/Layout]") - Len("[Layout]") - lng)
.Summary = Replace(.Summary, "[Layout]" & sLayout_Old & "[/Layout]", "[Layout]" & sLayout_New & "[/Layout]")
End With
End If
With Application
.EnableEvents = bEnableEvents
.ScreenUpdating = bScreenUpdating
.Calculation = lCalculation
End With
End Function
Public Function Pivots_FieldChange(target As PivotTable) As String
' Description: Works out what caused a PivotTableUpdate event, and if caused by someone changing a filter returns the
' name of the PivotField that was filtered.
' Programmer: Jeff Weir
' Contact: weir.jeff#gmail.com or jeff.weir#HeavyDutyDecisions.co.nz
' Inputs: PivotTable
' Outputs: String
' Name/Version: Date: Ini: Modification:
' PivotChange_20140712 20140712 JSW Initial programming as per http://dailydoseofexcel.com/archives/2014/07/10/what-caused-that-pivottableupdate-episode-iv/
' PivotChange_20140723 20140423 JSW Restructured code as per http://dailydoseofexcel.com/archives/2014/07/23/broken-arrow/
' PivotChange_20140802 20140802 JSW Added: If sLastUndoStackItem = "Filter" Or sLastUndoStackItem = "Slicer Operation" Then
' so that Filter routines only get called in response to filtering
' Pivots_FieldChange 20151016 JSW Changed the way info is saved in .summary
Dim sLastUndoStackItem As String
Dim sField As String
Dim sPossibles As String
Dim sLayout_New As String
Dim sLayout_Old As String
On Error Resume Next 'in case the undo stack has been wiped or doesn't exist
sLastUndoStackItem = Application.CommandBars(14).FindControl(ID:=128).List(1) 'Standard Commandbar, undo stack
On Error GoTo 0
If sLastUndoStackItem = "Filter" Or sLastUndoStackItem = "Slicer Operation" Then
sField = PivotChange_CompareLayout(target, sLayout_New, sLayout_Old)
If sField = "" Then sField = PivotChange_EliminationCheck(target, sPossibles)
If sField = "" Then sField = PivotChange_UndoCheck(target, sPossibles)
If sLayout_Old = "" Then
target.Summary = "[Layout]" & sLayout_New & "[/Layout]"
Else
target.Summary = Replace(target.Summary, "[Layout]" & sLayout_Old & "[/Layout]", "[Layout]" & sLayout_New & "[/Layout]")
End If
End If
Pivots_FieldChange = sField
Debug.Print Now() & vbTab & "Pivots_FieldChange:" & vbTab & sField
End Function
Function PivotChange_RecordLayout(pt As PivotTable, ByRef sLayout_New As String) As Boolean
Dim pf As PivotField
For Each pf In pt.PivotFields
With pf
Select Case .Orientation
Case xlRowField, xlColumnField
sLayout_New = sLayout_New & .Name & "|" & .VisibleItems.Count & "|" & .VisibleItems(1).Name & "||"
Case xlPageField
'pf.VisibleItems.Count doesn't work on PageFields
'So for PageFields we’ll record what that PageField’s filter currently displays.
'#DEV# Maybe it's quick to iterate through the .VisibleItems collection (if there is one) and count?
sLayout_New = sLayout_New & .Name & "|" & .LabelRange.Offset(, 1).Value & "|" & .EnableMultiplePageItems & "||"
End Select
End With
Next pf
End Function
Function PivotChange_CompareLayout(pt As PivotTable, ByRef sLayout_New As String, ByRef sLayout_Old As String) As String
Dim i As Long
Dim lng As Long
Dim vLayout_Old As Variant
Dim vLayout_New As Variant
PivotChange_RecordLayout pt, sLayout_New
With pt
lng = InStr(.Summary, "[Layout]")
If lng > 0 Then
sLayout_Old = Mid(.Summary, lng + Len("[Layout]"), InStr(.Summary, "[/Layout]") - Len("[Layout]") - lng)
If sLayout_Old <> sLayout_New Then
vLayout_Old = Split(sLayout_Old, "||")
vLayout_New = Split(sLayout_New, "||")
For i = 0 To UBound(vLayout_Old)
If vLayout_Old(i) <> vLayout_New(i) Then
PivotChange_CompareLayout = Split(vLayout_Old(i), "|")(0)
Exit For
End If
Next i
End If
Else:
'Layout has not yet been recorded.
'Note that we only update .Summary at the end of the main function,
' so we don't wipe the UNDO stack before the PivotChange_UndoCheck routine
End If
End With
End Function
Function PivotChange_EliminationCheck(pt As PivotTable, ByRef sPossibles As String) As String
'Check all the visible fields to see if *just one of them alone* has
' neither .AllItemsVisible = True nor .EnableMultiplePageItems = false.
' If that's the case, then by process of elimination, this field
' must be the one that triggered the change, as changes to any of the
' others would have been identified in the code earlier.
Dim pf As PivotField
Dim lngFields As Long
lngFields = 0
On Error Resume Next ' Need this to handle DataFields and 'Values' field
For Each pf In pt.PivotFields
With pf
If .Orientation > 0 Then 'It's not hidden or a DataField
If .EnableMultiplePageItems And Not .AllItemsVisible Then
If Err.Number = 0 Then
'It *might* be this field
lngFields = lngFields + 1
sPossibles = sPossibles & .Name & ";"
Else: Err.Clear
End If
End If
End If
End With
Next
On Error GoTo 0
If lngFields = 1 Then PivotChange_EliminationCheck = Left(sPossibles, Len(sPossibles) - 1)
End Function
Function PivotChange_UndoCheck(pt As PivotTable, sPossibles) As String
Dim i As Long
Dim dicFields As Object 'This holds a list of all visible pivotfields
Dim dicVisible As Object 'This contains a list of all visible PivotItems for a pf
Dim varKey As Variant
Dim pf As PivotField
Dim pi As PivotItem
Dim bidentified As Boolean
Dim lngVisibleItems As Long
Application.EnableEvents = False
'Create master dictionary
Set dicFields = CreateObject("Scripting.Dictionary")
'Cycle through all pivotfields, excluding totals
For i = 0 To UBound(Split(sPossibles, ";")) - 1
'Create dicVisible: a dictionary for each visible PivotField that contain visible PivotItems
Set dicVisible = CreateObject("Scripting.Dictionary")
Set pf = pt.PivotFields(Split(sPossibles, ";")(i))
With pf
If .Orientation <> xlPageField Then
For Each pi In .VisibleItems
With pi
dicVisible.Add .Name, .Name
End With
Next pi
Else:
'Unfortunately the .visibleitems collection isn't available for PageFields
' e.g. SomePageField.VisibleItems.Count always returns 1
' So we'll have to iterate through the pagefield and test the .visible status
' so we can then record just the visible items (which is quite slow)
For Each pi In .PivotItems
With pi
If .Visible Then
dicVisible.Add .Name, .Name
End If
End With
Next pi
End If 'If .Orientation = xlPageField Then
'Write dicVisible to the dicFields master dictionary
dicFields.Add .Name, dicVisible
End With
Next i
Application.Undo
For Each varKey In dicFields.keys
Set pf = pt.PivotFields(varKey)
Set dicVisible = dicFields.Item(varKey)
'Test whether any of the items that were previously hidden are now visible
If pf.Orientation <> xlPageField Then
For Each pi In pf.VisibleItems
With pi
If Not dicVisible.exists(.Name) Then
PivotChange_UndoCheck = pf.Name
bidentified = True
Exit For
End If
End With
Next
Else 'pf.Orientation = xlPageField
lngVisibleItems = dicVisible.Count
i = 0
For Each pi In pf.PivotItems
With pi
If .Visible Then
If Not dicVisible.exists(.Name) Then
PivotChange_UndoCheck = pf.Name
bidentified = True
Exit For
Else: i = i + 1 'this is explained below.
End If
End If
End With
Next
' For non-PageFields, we know that the number of .VisibleItems hasn't changed.
' But we *don't* know that about Pagefields, and an increase in the amount of
' .VisibleItems won't be picked up by our Dictionary approach.
' So we'll check if the overall number of visible items changed
If Not bidentified And i > lngVisibleItems Then
PivotChange_UndoCheck = pf.Name
Exit For
End If
End If
If bidentified Then Exit For
Next
'Resore the original settings
With Application
.CommandBars(14).FindControl(ID:=129).Execute 'Standard Commandbar, Redo command
.EnableEvents = True
End With
End Function
End Sub
Related
Sometimes our workbooks at work get so overloaded with named ranges, which we don't even use, that the tool we normally use to remove names, or even the name manager, will no longer function. I did some digging around here and after finding this post: VBA Remove 100k + named ranges, I started using the below code:
Sub dlname()
Dim j As Long
For j = 20000 To 1 Step -1
If j <= ActiveWorkbook.Names.Count Then
ActiveWorkbook.Names(j).Delete
End If
Next j
ActiveWorkbook.Save
End Sub
For the most part this gets the job done (very slowly) however it periodically just stops working, and I'd prefer for this to be done on a loop until the job is done with the workbook being saved every time. If I use code that doesn't try and do the job in chunks then I just get a memory error so I'm pretty sure it needs to be done piece meal.
Sorry I am not a coder so I'm unsure how to update. Any help would be appreciated.
Thanks,
I don't see anything really "wrong" with your code - it could be tidied up a bit, but the essential process is the same:
'remove all names from activeworkbook
Sub RemoveNames()
With ActiveWorkbook.Names
Do While .Count > 0
.Item(1).Delete
Loop
End With
End Sub
'create a lot of names for testing...
Sub AddNames()
Dim i As Long
For i = 1 To 10000
ActiveWorkbook.Names.Add "Test_" & Format(i, "0000000"), ActiveSheet.Cells(i, 1)
Next i
End Sub
The process of deleting UNUSED names can be complicated. This is an example of searching through all the defined names in a workbook and deleting ONLY those NOT USED in a formula.
The bit at the top and bottom of the routine will greatly speed up the process...
Option Explicit
Sub DeleteAllUnusedNames()
'--- disable all interactions for SPEED
With Application
.EnableEvents = False
.DisplayAlerts = False
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
Dim totalNames As Long
Dim namesDeleted As Long
Dim definedName As Variant
For Each definedName In ThisWorkbook.names
Dim nameIsUsed As Boolean
nameIsUsed = True
totalNames = totalNames + 1
Dim sheet As Worksheet
For Each sheet In ThisWorkbook.Sheets
If Not NameIsInFormula(definedName.name, sheet) Then
nameIsUsed = False
Exit For
End If
Next sheet
If Not nameIsUsed Then
namesDeleted = namesDeleted + 1
definedName.Delete
End If
Next definedName
Debug.Print totalNames & " names found, " & namesDeleted & " deleted"
'--- re-enable all interactions
With Application
.EnableEvents = True
.DisplayAlerts = True
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End With
End Sub
Public Function NameIsInFormula(ByVal thisName As String, _
ByRef thisSheet As Worksheet) As Boolean
On Error Resume Next
Dim cellsWithFormulas As Range
Set cellsWithFormulas = thisSheet.Cells.SpecialCells(xlCellTypeFormulas)
If cellsWithFormulas Is Nothing Then
NameIsInFormula = False
Exit Function
End If
On Error GoTo 0
Dim cellsFound As Range
Set cellsFound = cellsWithFormulas.Find(What:=thisName, LookIn:=xlFormulas, _
LookAt:=xlPart, MatchCase:=False, _
SearchFormat:=False)
'--- optional if you want to see where it is...
' If Not cellsFound Is Nothing Then
' Debug.Print vbTab & thisName & " found in " & _
' thisSheet.name & "!" & cellsFound.Address
' End If
NameIsInFormula = (Not cellsFound Is Nothing)
End Function
I have a macro in my Excel Workbook that I run reports on.
I want to add in the pastespecial Function below but don't know where to place it in the script further down. It keeps giving me errors. I've tried almost every line.
I also want to add an extract phrase function added in as well. There is some text I want removed from one column at the beginning of every cell eg: alpha/beta/kappa
Help please. Thank you.
++++++++++++++++++++++++++++++++
Copy and Value Paste to Different Sheet
This example will Copy & Paste Values for single cells on different worksheets
1
2
Sheets("Sheet1").Range("A1").Copy
Sheets("Sheet2").Range("B1").PasteSpecial Paste:=xlPasteValues
++++++++++++++++++++++++++++++++++++++
My code below where I want to insert the above pastespecial function:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Option Explicit
Function GetHeadersDict() As Scripting.Dictionary
' We must activate the Microsoft Scripting Runtime from Tools --References
Dim result As Scripting.Dictionary
Set result = New Scripting.Dictionary
With result
.Add "Track #", False
.Add "Date", False
.Add "Status", False
.Add "Shoes", False
.Add "Description", False
End With
Set GetHeadersDict = result
End Function
Function FindHeaderRange(ByVal ws As Worksheet, ByVal header As String) As Range
Set FindHeaderRange = ws.Cells.Find(header, , , xlWhole)
End Function
Sub clearDataNotFormulasSheet2()
Sheets("Results").Range("A2:k96").ClearContents
End Sub
Sub copyColumnData()
On Error GoTo ErrorMessage
Dim ws1 As Worksheet, ws2 As Worksheet
Set ws1 = ThisWorkbook.Sheets("Report")
Set ws2 = ThisWorkbook.Sheets("Results")
clearDataSheet2
Dim numRowsToCopy As Long
numRowsToCopy = ws1.Cells(RowIndex:=Rows.Count, ColumnIndex:=1).End(xlUp).Row - 1
'MsgBox "The no of rows to copy is " & numRowsToCopy
Dim destRowOffset As Long
destRowOffset = ws2.Cells(RowIndex:=Rows.Count, ColumnIndex:=1).End(xlUp).Row
'MsgBox "The next Blank row is " & destRowOffset
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim dictKey As Variant
Dim header As String
Dim numColumnsToCopy As Long
Dim Report As Range
Dim dest As Range
Dim headersDict As Scripting.Dictionary
Set headersDict = GetHeadersDict()
For Each dictKey In headersDict
header = dictKey
If headersDict.Item(header) = False Then
Set Report = FindHeaderRange(ws1, header)
If Not (Report Is Nothing) Then
Set dest = FindHeaderRange(ws2, header)
If Not (dest Is Nothing) Then
headersDict.Item(header) = True
' Look at successive headers to see if they match
' If so, copy these columns altogether to make the macro faster
For numColumnsToCopy = 1 To headersDict.Count
'MsgBox numColumnsToCopy
If Report.Offset(ColumnOffset:=numColumnsToCopy).Value = dest.Offset(ColumnOffset:=numColumnsToCopy).Value Then
headersDict.Item(Report.Offset(ColumnOffset:=numColumnsToCopy).Value) = True
Else
Exit For
End If
Next numColumnsToCopy
Report.Offset(RowOffset:=1).Resize(RowSize:=numRowsToCopy, ColumnSize:=numColumnsToCopy).Copy _
dest.Offset(RowOffset:=destRowOffset)
End If
End If
End If
Next dictKey
Dim msg As String
For Each dictKey In headersDict
header = dictKey
If headersDict.Item(header) = False Then
msg = msg & vbNewLine & header
End If
Next dictKey
ExitSub:
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
If msg <> "" Then
MsgBox "The following headers were not copied:" & vbNewLine & msg
End If
Exit Sub
ErrorMessage:
MsgBox "An error has occurred: " & Err.Description
Resume ExitSub
End Sub
Private Sub CommandButton1_Click()
End Sub
I had the same issue of yours just replace Report.Offset(RowOffset:=1).Resize(RowSize:=numRowsToCopy, ColumnSize:=numColumnsToCopy).Copy _ dest.Offset(RowOffset:=destRowOffset)
with
Report.Offset(RowOffset:=1).Resize(RowSize:=numRowsToCopy,ColumnSize:=numColumnsToCopy).Copy
dest.Offset(RowOffset:=destRowOffset).PasteSpecial Paste:=xlPasteValues
How to make suggestions in Excel data validation list while typing. There are constraints in my request:
The list of items should be in another sheet, and must not be above in hidden rows.
Typing a phrase should narrow the list to all the items which contain the phrase.
Search should be case insensitive.
So after typing am we should hypothetically have a suggestion to pick up from Amelia, Camila, Samantha, provided that those girls' names are on the item list.
I have found a good solution here, however it does not filter the items with contains clause but begins with. I sum up the proposed solution here shortly.
We insert a Combo Box (ActiveX Control) to a sheet.
We right click on a sheet name > View code > and paste the VBA code in the sheet VBA editor:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'Update by Extendoffice: 2018/9/21
Dim xCombox As OLEObject
Dim xStr As String
Dim xWs As Worksheet
Dim xArr
Set xWs = Application.ActiveSheet
On Error Resume Next
Set xCombox = xWs.OLEObjects("TempCombo")
With xCombox
.ListFillRange = ""
.LinkedCell = ""
.Visible = False
End With
If Target.Validation.Type = 3 Then
Target.Validation.InCellDropdown = False
Cancel = True
xStr = Target.Validation.Formula1
xStr = Right(xStr, Len(xStr) - 1)
If xStr = "" Then Exit Sub
With xCombox
.Visible = True
.Left = Target.Left
.Top = Target.Top
.Width = Target.Width + 5
.Height = Target.Height + 5
.ListFillRange = xStr
If .ListFillRange = "" Then
xArr = Split(xStr, ",")
Me.TempCombo.List = xArr
End If
.LinkedCell = Target.Address
End With
xCombox.Activate
Me.TempCombo.DropDown
End If
End Sub
Private Sub TempCombo_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Select Case KeyCode
Case 9
Application.ActiveCell.Offset(0, 1).Activate
Case 13
Application.ActiveCell.Offset(1, 0).Activate
End Select
End Sub
I could not find a way to modify to change the search option from 'begins with' to contains.
The questions about autocomplete or autosuggest in validation list have been asked so far.
Excel data validation with suggestions/autocomplete
Excel 2010: how to use autocomplete in validation list
But neither of them contained answers which would satisfied the constraints I imposed.
Test file for download is here.
Try to add the following event (additionally the the other 2). Every time you enter something the code refreshes the ComboBox list.
Private Sub TempCombo_Change()
With Me.TempCombo
If Not .Visible Then Exit Sub
.Clear 'needs property MatchEntry set to 2 - fmMatchEntryNone
.Visible = False 'to refresh the drop down
.Visible = True
.Activate
Dim xStr As String, xArr As Variant
xStr = TempCombo.TopLeftCell.Validation.Formula1
xStr = Right(xStr, Len(xStr) - 1)
xArr = Split(xStr, Application.International(xlListSeparator))
Dim itm As Variant
For Each itm In xArr
If InStr(1, itm, .Value, vbTextCompare) > 0 Or .Value = "" Then
.AddItem itm
End If
Next itm
.DropDown
End With
End Sub
To overcome your first constraint, maybe you can assign a range to your combo box:
Dim xCombox As OLEObject
Dim xStr As String
Dim xWs As Worksheet
Dim xArr
Dim i As Range
Set xWs = Application.ActiveSheet
On Error Resume Next
Set xCombox = xWs.OLEObjects("Combotest")
With Sheets("Test_list2")
Set i = .Range("A2:A" & .Range("A" & .Rows.Count).End(xlUp).Row)
End With
Combotest.ListFillRange = i.Address
Set xWs = Application.ActiveSheet
On Error Resume Next
Set xCombox = xWs.OLEObjects("Combotest")
With xCombox
.LinkedCell = "F2"
.Visible = True
End With
.
.
.
.
End Sub
I am trying to show / hide pivot items based on a drop down selection.
If you see the code below, cell S3 is a drop down with options - All, Jan, Feb.. Dec. When I change the drop down, I want to show only the pivot items of the selected month.
What is happening here is, once I set an item visibility to false, I am not able to make it visible again. So, the for each loop below simply ignores those items that have been hidden earlier
Private Sub Worksheet_Change(ByVal Target As Range)
Dim pt As PivotTable, counter
Dim pi As PivotItem, msg, mname
Application.EnableEvents = False
If Target.Address = "$S$3" Then
Application.EnableEvents = False
Set pt = Sheet3.PivotTables(1)
mname = Sheet2.Range("S3").Value
pt.RefreshTable
For Each pi In pt.PivotFields("Values").PivotItems
If InStr(pi, mname) > 0 Or mname = "All" Then
pi.Visible = True
Else
pi.Visible = False
End If
Next pi
End If
Application.EnableEvents = True
End Sub
Screenshot of my Pivot Table
Try the code below (explanation inside the code as commnets):
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim pt As PivotTable
Dim pi As PivotItem
Dim pf As PivotField
Dim msg As String, mname As String
'Dim counter ' <-- not used in this piece of code
If Target.Address = "$S$3" Then
Application.EnableEvents = False
' set the PivotTable object
Set pt = Sheet3.PivotTables(1)
mname = Target.Value ' <-- you can use the Target object
pt.RefreshTable
' set the PivotField object
Set pf = pt.PivotFields("Values")
pf.ClearAllFilters ' clear all previous filters from "Values"
' if value is "All", show all items, (no need to run the loop)
If mname <> "All" Then
For Each pi In pf.PivotItems
If Not pi.Name Like "*" & mname & "*" Then ' only if the value is not like the month >> hide the PivotItem
pi.Visible = False
End If
Next pi
End If
End If
Application.EnableEvents = True
End Sub
I am trying to help a bookstore with its Xmas sales! I use a PivotTable connected to an OLAP Cube, with a lot of product references, with valuable information as sales of last week, inventory level etc.
I want to display only the data (sales and inventory levels) for the books on a current commercial actions (about 400 books) to check if inventory level is enough.
I have a slicer with ISBN numbers, with more than a million captions, and I want to manipulate that slice with VBA to display only the books I want.
List of the ISBN that I want to be displayed are in sheet "Catalogue EOY", column 3. I try to build an array with the right slicer names, to be used with the VisibleSlicerItemsList statement, but I get a message "Object required" on that line (last line). In my example, I have limited the list of books to the first 50 items.
Any idea how I can solve this?
Sub ShowProductList()
Dim ProductList(0 To 50) As Variant
Dim i
Dim Sc As SlicerCache
Dim sL As SlicerCacheLevel
Set Sc = ActiveWorkbook.SlicerCaches("Slicer_ISBN")
Set sL = Sc.SlicerCacheLevels(1)
For i = 2 To 52
ProductList(i - 2) = Chr(34) & "[DIM Artikel].[ISBN].&[" & _
Worksheets("Catalogue EOY").Cells(i, 3).Value & "]" & Chr(34)
Next i
sL.VisibleSlicerItemsList = ProductList
End Sub
Sub f()
Dim piv As PivotItem, pivf As PivotField, pivt As PivotTable, ProductList() As Variant, filterrng As Range, rng As Range
'the range where your background data is
Set filterrng = Worksheets("filter_criteria").Range("C2:C52") 'the range where your product list is
ReDim ProductList(filterrng.Cells.Count - 1)
For Each rng In filterrng
ProductList(i) = rng.Value2
i = i + 1
Next rng
Set pivt = Sheets("piv").PivotTables("PivotTable1") 'your pivottable, define it properly
Set pivf = pivt.PivotFields("ISBN") 'the pivot field
On Error Resume Next
For Each pvi In pivf.PivotItems
pvi.Visible = False
pvi.Visible = Application.Match(pvi.Name, ProductList, False) > -1 'if it's in the range, then make it visible, otherwise hide it
Next pvi
End Sub
Not the answer you want but the one you need.
You need to loop through each SlicerItem and test it against your list to choose to select it or not, here is how :
Sub ShowProductList()
With Application
.EnableEvents = False 'stop executing this code until we are done
.DisplayAlerts = False
.ScreenUpdating = False
'.Calculation = xlCalculationManual
End With
Dim ProductList(0 To 50) As Variant
Dim i As Long
Dim Sc As SlicerCache
Dim sI As SlicerItem
Dim sL As SlicerCacheLevel
Dim inLisT As Boolean
Set Sc = ActiveWorkbook.SlicerCaches("Slicer_ISBN")
Set sL = Sc.SlicerCacheLevels(1)
For i = 2 To 52
ProductList(i - 2) = Chr(34) & "[DIM Artikel].[ISBN].&[" & _
Worksheets("Catalogue EOY").Cells(i, 3).Value & "]" & Chr(34)
Next i
Sc.ClearManualFilter
For Each sI In Sc.SlicerItems
inLisT = False
For i = LBound(ProductList) To UBound(ProductList)
If sI.Name <> ProductList(i) Then
Else
inLisT = False
Exit For
End If
Next i
If inLisT Then
sI.Selected = True
Else
sI.Selected = False
End If
Next sI
With Application
.EnableEvents = True 'stop executing this code until we are done
.DisplayAlerts = True
.ScreenUpdating = True
'.Calculation = xlCalculationAutomatic
End With
End Sub