Reputation: 48
So this is the relevant part of the code:
i = Feuil1.Cells.Rows.count
i = Feuil1.Cells(i, 1).End(xlUp).Row
j = Feuil1.Cells(1, 1).End(xlToRight).Column
HelpAddress = Feuil1.Cells(i, j).Address
Set Table = Feuil1.ListObjects("FiltersTable")
HelpArr = Application.WorksheetFunction.Transpose(Table.ListColumns("Rubriques").DataBodyRange)
HelpArr2 = Application.WorksheetFunction.Transpose(Table.ListColumns("Departements").DataBodyRange)
HelpArr = UniqueNoEmpty(HelpArr)
HelpArr2 = UniqueNoEmpty(HelpArr2)
For i = LBound(HelpArr2) To UBound(HelpArr2)
HelpArr2(i) = CStr(HelpArr2(i)) & "*"
Next i
FilterArray2 = Array("*@*")
Set Wbk = Workbooks.Add
Set Ws = Wbk.Worksheets(1)
Feuil1.Activate
Feuil1.Range("A1" & ":" & Feuil1.Cells(1, j).Address).Copy
Ws.Cells(1, 1).PasteSpecial xlPasteValues
For Each Rubrique In HelpArr
FilterArray = Array(Rubrique & "*")
With Feuil1
On Error Resume Next
.ShowAllData
On Error GoTo 0
' .Range("A1" & ":" & HelpAddress).AutoFilter Field:=11
.Range("A1" & ":" & HelpAddress).AutoFilter Field:=11, Criteria1:=FilterArray, Operator:=xlFilterValues
.Range("A1" & ":" & HelpAddress).AutoFilter Field:=9, Criteria1:=FilterArray2, Operator:=xlFilterValues
' .Range("A1" & ":" & HelpAddress).AutoFilter Field:=4, Criteria1:=FilterArray3, Operator:=xlFilterValues, Operator:=xlOr
End With
For i = LBound(HelpArr2) To UBound(HelpArr2)
Feuil1.Range("A1" & ":" & HelpAddress).AutoFilter Field:=4
Feuil1.Range("A1" & ":" & HelpAddress).AutoFilter Field:=4, Criteria1:=HelpArr2(i), Operator:=xlFilterValues
Set FilteredRng = Feuil1.Range("A2" & ":" & HelpAddress).SpecialCells(xlCellTypeVisible)
If Not FilteredRng Is Nothing Then
FilteredRng.Copy
Set HelpRng = Ws.Cells(Ws.Cells.Rows.count, 1).End(xlUp)
Do While HelpRng.Value <> ""
Set HelpRng = HelpRng.Offset(1, 0)
Loop
Ws.Range(HelpRng.Address).PasteSpecial xlPasteValues
End If
Next i
Next Rubrique
The first line in Feuil1 is the row with the headers with filters.
The thing is that when the Criteria1 gives no rows as result, and so the only visible row is the row with the filters, in that case the visible range is nothing BUT FilteredRng is Nothing
gives False as result because for some reason FilteredRng is actually the first row with the filters.
I can't understand how this happens because the first row was not part of the range to begin with.
Furthermore it prevents me from catching the error using if FilteredRng is Nothing then
Now the workaround for this is if FilteredRng.rows.count = 1 and FilteredRng.row=1 then
but still I'd like to be able to catch the error by comparing with Nothing as the filter row / header row might change rows in different cases... and I have pre-built functions and subs that are for general case use where I compare to Nothing.
If anyone knows what's going on here or how to catch the 'No cells found' error I would really appreciate it.
UPDATE:
After updating the code following Rory's comments this is how the code looks like now:
On Error Resume Next
Feuil1.ShowAllData
On Error GoTo 0
i = Feuil1.Cells.Rows.count
i = Feuil1.Cells(i, 1).End(xlUp).Row
j = Feuil1.Cells(1, 1).End(xlToRight).Column
HelpAddress = Feuil1.Cells(i, j).Address
Set Wbk = Workbooks.Add
Set Ws = Wbk.Worksheets(1)
Feuil1.Activate
Feuil1.Range("A1:" & Feuil1.Cells(1, j).Address).Copy
Ws.Cells(1, 1).PasteSpecial xlPasteValues
Set Table = Feuil1.ListObjects("FiltersTable")
HelpArr = Application.WorksheetFunction.Transpose(Table.ListColumns("Rubriques").DataBodyRange)
HelpArr2 = Application.WorksheetFunction.Transpose(Table.ListColumns("Departements").DataBodyRange)
HelpArr = UniqueNoEmpty(HelpArr)
HelpArr2 = UniqueNoEmpty(HelpArr2)
For i = LBound(HelpArr2) To UBound(HelpArr2)
HelpArr2(i) = CStr(HelpArr2(i)) & "*"
Next i
FilterArray2 = Array("*@*")
For Each Rubrique In HelpArr
FilterArray = Array(Rubrique & "*")
With Feuil1
On Error Resume Next
.ShowAllData
On Error GoTo 0
' .Range("A1" & ":" & HelpAddress).AutoFilter Field:=11
.Range("A1" & ":" & HelpAddress).AutoFilter Field:=11, Criteria1:=FilterArray, Operator:=xlFilterValues
.Range("A1" & ":" & HelpAddress).AutoFilter Field:=9, Criteria1:=FilterArray2, Operator:=xlFilterValues
' .Range("A1" & ":" & HelpAddress).AutoFilter Field:=4, Criteria1:=FilterArray3, Operator:=xlFilterValues, Operator:=xlOr
End With
For i = LBound(HelpArr2) To UBound(HelpArr2)
Set FilteredRng = Nothing
Feuil1.Range("A1" & ":" & HelpAddress).AutoFilter Field:=4
Feuil1.Range("A1" & ":" & HelpAddress).AutoFilter Field:=4, Criteria1:=HelpArr2(i), Operator:=xlFilterValues
On Error Resume Next
Set FilteredRng = Feuil1.Range("A2" & ":" & HelpAddress).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not FilteredRng Is Nothing Then
' If FilteredRng.Rows.count = 1 And FilteredRng.Row = 1 Then
FilteredRng.Copy
Set HelpRng = Ws.Cells(Ws.Cells.Rows.count, 1).End(xlUp)
Do While HelpRng.Value <> ""
Set HelpRng = HelpRng.Offset(1, 0)
Loop
Ws.Range(HelpRng.Address).PasteSpecial xlPasteValues
End If
Next i
Next Rubrique
Upvotes: 1
Views: 690
Reputation: 48
Credit for this answer should go to Rory as it was his comments that provided the solution
So the answer to this was setting the range to nothing , applying the desired filters and then set the range using the SpecialCells properties.
Set FilteredRng = Nothing
Feuil1.Range("A1:" & HelpAddress).AutoFilter Field:=4
Feuil1.Range("A1:" & HelpAddress).AutoFilter Field:=4, Criteria1:=HelpArr2(i), Operator:=xlFilterValues
On Error Resume Next
Set FilteredRng = Feuil1.Range("A2:" & HelpAddress).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not FilteredRng Is Nothing Then
'Code here
End If
Upvotes: 0
Reputation: 16189
With a table the header row and databody (excluding header) ranges are available as properties of the table.
Option Explicit
Sub demo()
Dim wsf As WorksheetFunction
Dim wb As Workbook, ws As Worksheet, tbl As ListObject
Dim wbOut As Workbook, wsOut As Worksheet, rowOut As Long
Dim colRub As ListColumn, colDept As ListColumn
Dim arRub, arDept, i As Long
Set ws = Sheet1 ' or Feuil1
Set wsf = Application.WorksheetFunction
' get unique rubriques and departements
Set tbl = ws.ListObjects("FiltersTable")
With tbl
Set colRub = .ListColumns("Rubriques")
arRub = UniqueNoEmpty(wsf.Transpose(colRub.DataBodyRange))
Set colDept = .ListColumns("Departements")
arDept = UniqueNoEmpty(wsf.Transpose(colDept.DataBodyRange))
End With
' create workbook for reults
Set wbOut = Workbooks.Add
Set wsOut = wbOut.Worksheets(1)
tbl.HeaderRowRange.Copy wsOut.Range("A1")
rowOut = 1
Dim rubrique, dept, rngFiltered As Range
'Application.ScreenUpdating = False
With tbl
For Each rubrique In arRub
' apply rubrique filter
.Range.AutoFilter Field:=colRub.Index, Criteria1:=rubrique & "*"
.Range.AutoFilter Field:=9, Criteria1:="*@*"
For Each dept In arDept
' apply department filter
.Range.AutoFilter Field:=colDept.Index, Criteria1:=dept & "*"
' copy filtered data if any
Set rngFiltered = Nothing
On Error Resume Next
Set rngFiltered = .DataBodyRange.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If rngFiltered Is Nothing Then
'Debug.Print "No data for ", rubrique, dept
Else
rngFiltered.Copy
wsOut.Range("A" & rowOut + 1).PasteSpecial xlPasteValues
rowOut = wsOut.Cells(wsOut.Rows.Count, 1).End(xlUp).Row
End If
Next
Next
.Range.AutoFilter
End With
'Application.ScreenUpdating = True
MsgBox rowOut & " rows copied to " & wbOut.Name
End Sub
Function UniqueNoEmpty(ar)
Dim d, e: Set d = CreateObject("Scripting.Dictionary")
For Each e In ar
If Len(e) > 0 Then d(CStr(e)) = 1
Next
UniqueNoEmpty = d.keys
End Function
Upvotes: 0
Reputation: 54777
Option Explicit
Sub AutoFilterExample()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim ws As Worksheet: Set ws = wb.Worksheets("Sheet1")
If ws.AutoFilterMode Then ws.AutoFilterMode = False ' remove previous
Dim trg As Range: Set trg = ws.Range("A1").CurrentRegion ' Table Range
Dim dtrg As Range ' Data Range (refernce before the 'AutoFilter')
Set dtrg = trg.Resize(trg.Rows.Count - 1).Offset(1)
trg.AutoFilter 1, "Yes"
Dim vrg As Range ' Visible Range
On Error Resume Next
Set vrg = dtrg.SpecialCells(xlCellTypeVisible) ' use the data range ('dtrg')
On Error GoTo 0
ws.AutoFilterMode = False
If Not vrg Is Nothing Then
Debug.Print vrg.Address(0, 0)
Else
Debug.Print "Nope"
End If
End Sub
Upvotes: 1