Excel: Show Ancestors
Some programs like MS Project show the hierarchy structure when filtering (i.e. they "show ancestors"). Excel does not do this - it understands indents and grouping (outlining), but it filters things out based on the cell, and doesn't show the hierarchy from lines above.
Attached is a macro that is aware of the Excel Outlining (grouping). Note: You can create the groupings automatically from the indents or the spaces using the Indent Macros.
It needs to be added to the Sheet that you wish to have the AutoFilter on as it relies on Events.
A common example is you paste from MS Project to Excel, then filter the Resources. If you use this spreadsheet, you can show the hierarchy of the relevant tasks.
Private Sub Worksheet_Change(ByVal Target As range)
Dim KeyCells As range
Dim KeyColumn As Integer
Dim Criteria As String
' The variable KeyCells contains the cells that will
' cause an alert when they are changed.
' Assumes the row above the autofilter contains the criteria
Set KeyCells = AutoFilter.range.Offset(-1).Rows(1)
If Not Application.Intersect(KeyCells, range(Target.address)) Is Nothing Then
Debug.Print "-------------------------"
Debug.Print "Cell " & Target.address & " has changed."
' Work out which column number it is
Debug.Print "Column " & Target.Column & " has changed"
'Debug.Print "Autofilter first column:" & AutoFilter.range.Column
KeyColumn = Target.Column - AutoFilter.range.Column + 1
On Error GoTo finish
If Target.Value = "" Then
AutoFilter.range.AutoFilter field:=KeyColumn ' Clear the filter
Else
AutoFilter.range.AutoFilter field:=KeyColumn, Criteria1:="=*" & Target.Value & "*", Operator:=xlAnd
Call showAncestors(Target.Offset(1), Target.Value)
End If
End If
finish:
End Sub
Sub showAncestors(Optional start As range, Optional Criteria As String = "yes")
' Shows the ancestors based on a criteria
Dim rng As range
Debug.Print "-------------------------"
Set rng = start.Resize(AutoFilter.range.Rows.Count) ' Grow column to end
Debug.Print "range: " & rng.address
For i = 2 To rng.Rows.Count ' Go down rows, skipping header
' If rng(i) <> Criteria Then ' It doesn't match the criteria
' rng(i).EntireRow.Hidden = True ' Filter it out
' End If
If InStr(1, rng(i), Criteria) Then ' It matches the criteria
Debug.Print rng(i).address
indent = rng(i).EntireRow.OutlineLevel ' Save the level
For j = i - 1 To 2 Step -1 ' Check rows above to see if its less
If rng(j).EntireRow.OutlineLevel < indent Then
indent = rng(j).EntireRow.OutlineLevel ' Save this level
rng(j).EntireRow.Hidden = False ' Unhide this row as it's an ancestor
End If
Next
End If
Next
End Sub