Common problem, I have worked through all answers I've found and finally got it almost working.
I have a list of discount options, let's call them named range F, down 1 column. User filters out the discounts they don't want to apply. I need to unfilter, do work, and refilter as the user selected.
I create an array with only visible cells, by loop and union of ranges. This works correctly, but generates a non-contiguous array usually.
When I run this, I don't get an error. However, the entry below the break in the contiguous array is not refiltered.
Just realised it's the transpose that doesn't like non-contiguous arrays - still need assistance and doubtless others have same issue so leaving as is
What's the easiest, most painless (it's nearly Friday), way to persuade Criteria1 to include the last elements in my non-contiguous array?
Sub Filters()
'Dimension variables
Dim Rng As Range
Dim i, Lim As Integer
Dim w As Worksheet
Dim Op As Variant
Set w = ActiveSheet
'Set Lim as total number of rows in named range "F" (only 1 cell in use but same effect)
Lim = Range("F").Rows.Count
'Data has header row so skip to row 2
i = 2
'Loop through i up to limit
Do While i <= Lim
'If the row is not hidden by the filters the user chose
If Range("F")(i, 1).EntireRow.Hidden = False Then
'Check if the range is nothing - if it is, union will not work to itself
'Union requires non-empty arguments
If Rng Is Nothing Then
'Set the Rng to include the current cell from "F"
Set Rng = Range("F")(i, 1)
Else
'If Rng has some value, add the current cell to it by Union
Set Rng = Application.Union(Rng, Range("F")(i, 1))
End If
End If
'Increment i
i = i + 1
Loop
If w.AutoFilter.Filters.Item(1).Operator <> False Then Op = w.AutoFilter.Filters.Item(1).Operator
'This gives the correct range, but most often non-contiguous
MsgBox Range("F").Address
'Remove AutoFilter
w.AutoFilterMode = False
'Insert Code Here
'Put filters back
'Check for Rng being non-empty (pointless running code if it is)
If Not IsEmpty(Rng) Then
'If there is an operator then use the array
If Op Then
'Found this option useful here - can transpose the array values which generates an array Criteria1 can use
'Always xlFilterValues as there will always be more than 2 options
'Also the options are taken from the worksheet live so won't change between times so specifying them precisely as strings is ok
Range("F").AutoFilter Field:=1, Criteria1:=Application.Transpose(Rng.Value), _
Operator:=xlFilterValues
Else
'Just filter the range but leave all options available
Range("F").AutoFilter Field:=1
End If
End If
End Sub
Answered by using a second counter to count successful entries that should be included as criteria, and writing them to a range in another worksheet. Then set the range to be that new (contiguous) range in the new worksheet.
Now works like a charm at last. Only took me all day to find syntax that worked with Criteria, and figure that you can only use xlOr for up to 2 criteria, otherwise it's xlfiltervalues...
Final working code as generic as I can get it to be as helpful as possible:
Sub Filters()
'Dimension variables
Dim Rng As Range
Dim i, j, Lim As Integer
Dim w As Worksheet
Dim Op As Variant
Set w = ActiveSheet
'Set Lim as total number of rows in named range "F" (only 1 cell in use but same effect)
Lim = Range("F").Rows.Count
'Data has header row so skip to row 2
i = 2
'Loop through i up to limit
Do While i <= Lim
'If the row is not hidden by the filters the user chose
If Range("F")(i, 1).EntireRow.Hidden = False Then
'Check if the range is nothing - if it is, union will not work to itself
'Union requires non-empty arguments
If Rng Is Nothing Then
'Set the Rng to include the current cell from "F"
Set Rng = Range("F")(i, 1)
Sheets("Sheet2").Range("A75").Value = Range("F")(i, 1).Value
j = j + 1
Else
Sheets("Sheet2").Range("A1").Offset(j, 0).Value = Range("F")(i, 1).Value
j = j + 1
End If
End If
'Increment i
i = i + 1
Loop
'If there's an operator, save it as variable Op (if needed)
If w.AutoFilter.Filters.Item(1).Operator <> False Then Op = w.AutoFilter.Filters.Item(1).Operator
'Remove AutoFilter
w.AutoFilterMode = False
'Insert Code Here
'Pause between the two halves
MsgBox ""
'Put filters back
'Check for Rng being non-empty (pointless running code if it is)
If Not IsEmpty(Rng) Then
'If there is an operator then use the range
If Op Then
'Found this option useful here - can transpose the array values
'Always xlFilterValues as there will always be more than 2 options
'Also the options are taken from the worksheet live so won't change between times so specifying them precisely as strings is ok
Range("F").AutoFilter Field:=1, Criteria1:=Application.Transpose(Sheets("Sheet2").Range("A75").Resize(j, 1).Value), _
Operator:=xlFilterValues
Else
'Just filter the range but leave all options available
Range("F").AutoFilter Field:=1
End If
End If
End Sub