Excel 2013 - Load Empty Table to Array

bnj1776

Board Regular
Joined
Aug 20, 2014
Messages
67
The following code loads a table for "Contact Types" (Customer, Vendor, Shipper, etc.)

While trying to bulletproof the code I discovered that when the table is empty that this line generates an unexpected result:
row_ContactType = .Range.Rows.Count - 1 'Do not count the header"
The count will still be 1 even though the table is empty.


What I'm doing...

On the first attempt to load the table I am after "active records" only and perform this check after the auto filter:
row_ContactType = .AutoFilter.Range.SpecialCells(xlCellTypeVisible).Rows.Count - 1 'Do not count the header
This check of the table with an auto filter works. With no active records found it returns a zero count as expected.

Knowing that there are no active records, I attempt to read again for all records (active and inactive) without an auto filter.
However, if the table is actually empty, the count will still be "1" and attempting to load the table to the array will fail.

So I added the final test for an empty table and was able to insert a new row (see blue code below) when needed.

This is working, but I'm a bit confused as to why it works this way.
Such as why I'm still getting a count of "1" when there is a blank record that can not be loaded into the array?
Is there something I'm missing here that would clean up this code?

For the "working" code I have already moved the "Test for empty table" section to the top of the load data subroutine and removed the second row count check (red code).

Any information or ideas would be helpful.
Thanks,
Brian


Code:
[B]Private Sub UserForm_Activate()[/B]
'   Load the contact type file - retrieve the worksheet into a list object
    Set loContactType = tbl_ContactType.ListObjects("tblContactType")


'   Create an array of the table header row
    vContactTypeHeaders = loContactType.HeaderRowRange


'   Get the column numbers (as the columns may be moved)
    col_lContactTypeID = Array_GetHeaderColNum("lContactTypeID", vContactTypeHeaders)
    col_sStatus = Array_GetHeaderColNum("sStatus", vContactTypeHeaders)
    col_dtUpdated = Array_GetHeaderColNum("dtUpdated", vContactTypeHeaders)
    col_sName = Array_GetHeaderColNum("sName", vContactTypeHeaders)
    col_sDescription = Array_GetHeaderColNum("sDescription", vContactTypeHeaders)


    fmContactType_CheckBox_IncludeInactive.Value = False 'Inactived ContactType not included in inital load
    
    Call fmContactType_LoadData

    ... display screen...
End Sub


[B]Private Sub fmContactType_LoadData()[/B]
    Call fmContactType_LoadData_Clear
    
    If fmContactType_CheckBox_IncludeInactive.Value <> True Then 'get any records that are not inactive
    
'       Exclude Inactive Contact Types
        With loContactType
            .Sort.SortFields.Add Key:=Range("tblContactType[sStatus]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
            .Sort.SortFields.Add Key:=Range("tblContactType[sName]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
            .Sort.SortFields.Add Key:=Range("tblContactType[lContactTypeID]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
            With .Sort
                .Header = xlYes
                .MatchCase = False
                .Apply
            End With
            With .Range
                .AutoFilter Field:=col_sStatus, Criteria1:="<>" & sInactive 'hide inactive Contact Type
            End With
[COLOR=#008000]            row_ContactType = .AutoFilter.Range.SpecialCells(xlCellTypeVisible).Rows.Count - 1 'Do not count the header[/COLOR]
        End With
    
[COLOR=#008000]        If row_ContactType < 1 Then 'no active records found, swtich to show inactive
            vAnswer = MyMsgBox("No active customer types found." & vbCrLf & _
                "Checking for inactive customer types.", _
                vbCritical + vbOKOnly, sTitle)
            fmContactType_CheckBox_IncludeInactive.Value = True
            Call fmContactType_LoadData_Clear
        End If[/COLOR]
    
    End If
    
    If fmContactType_CheckBox_IncludeInactive.Value = True Then 'get all records including inactive
    
'       Incude Inactive Contact Types
        With loContactType
            .Sort.SortFields.Clear
            .Sort.SortFields.Add Key:=Range("tblContactType[sName]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
            .Sort.SortFields.Add Key:=Range("tblContactType[lContactTypeID]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
            With .Sort
                .Header = xlYes
                .MatchCase = False
                .Apply
            End With
            [COLOR=#ff0000]row_ContactType = .Range.Rows.Count - 1 'Do not count the header[/COLOR]
        End With
        
        If row_ContactType < 1 Then 'no records selected, add a new one   [B][COLOR=#ff0000]<<<< NEVER TRUE[/COLOR][/B]
            vAnswer = MyMsgBox("No customer types found." & vbCrLf & _
                "Attempting to add a new customer type record.", _
                vbCritical + vbOKOnly, sTitle)
            Call fmContactType_CommandButton_New_Click
        End If
    
    End If
    
[COLOR=#0000ff]'   Test for empty table
    Set RangeFound = loContactType.DataBodyRange
    If RangeFound Is Nothing Then
        row_ContactType = 1
        lContactTypeID = 1
        With loContactType
            .ListRows.Add Position:=row_ContactType, AlwaysInsert:=True
            With .DataBodyRange(row_ContactType)
                .Columns(col_lContactTypeID).Value = lContactTypeID
                .Columns(col_sStatus).Value = sActive
                .Columns(col_dtUpdated).Value = vbNullString
                .Columns(col_sName).Value = "New Record " & lContactTypeID
                .Columns(col_sDescription).Value = vbNullString
            End With
        End With
    End If[/COLOR]
        
'   Load the array from the filtered and sorted table
    vContactTypeBody = loContactType.DataBodyRange.SpecialCells(xlCellTypeVisible)
End Sub


[B]Private Sub fmContactType_LoadData_Clear()[/B]
    Dim iCol                             As Integer
    On Error Resume Next 'continue if no filters found
    loContactType.AutoFilter.ShowAllData 'clear any existing filters
    loContactType.Sort.SortFields.Clear 'clear any existing sorts
    For iCol = LBound(vContactTypeBody, 2) To UBound(vContactTypeBody, 2)
        loContactType.Range.AutoFilter Field:=iCol, VisibleDropDown:=False  'hide filters
    Next iCol
End Sub
 

Excel Facts

What does custom number format of ;;; mean?
Three semi-colons will hide the value in the cell. Although most people use white font instead.
I'm not sure I 100% follow the entire process, however, the following line appears like it will give you the actual number of TOTAL rows (VISIBLE+HIDDEN) that contain data (so 0 if the first row of the table is blank)

Code:
allRows = ActiveSheet.ListObjects("tblContactType").ListRows.Count

I believe the issue with it returning 1 is that a table by definition requires at least 1 row as a header and 1 row as data.
 
Upvote 0
Thanks BiocideJ.
It is just odd that if you delete every row of data from a table that Excel will add a blank row that is not really there.
Then testing for and dealing with an empty table seems to be such a pain.
Just not sure I follow Microsoft's logic on this one. Nothing new there.

I modified your suggestion just a bit and found that it is not counting the header, though it sure looks like it should as it is not the DataBodyRange being used.

Code:
Private Sub fmContactType_LoadData()
'   Test for emtpy table and add a blank record if needed
[B][COLOR=#008000]    If loContactType.ListRows.Count < 1 Then 'Header is not counted[/COLOR][/B]
        row_ContactType = 1
        lContactTypeID = 1
        With loContactType
            .ListRows.Add Position:=row_ContactType, AlwaysInsert:=True
            With .Range.Rows(row_ContactType + 1)
                .Columns(col_lContactTypeID).Value = lContactTypeID
                .Columns(col_sStatus).Value = sActive
                .Columns(col_dtUpdated).Value = vbNullString
                .Columns(col_sName).Value = "* New Record " & lContactTypeID
                .Columns(col_sDescription).Value = vbNullString
            End With
        End With
    End If
        
    Call fmContactType_LoadData_Clear
    
    If fmContactType_CheckBox_IncludeInactive.Value <> True Then 'get any records that are not inactive
    
'       Exclude Inactive Contact Types
        With loContactType
            .Sort.SortFields.Add Key:=Range("tblContactType[sStatus]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
            .Sort.SortFields.Add Key:=Range("tblContactType[sName]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
            .Sort.SortFields.Add Key:=Range("tblContactType[lContactTypeID]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
            With .Sort
                .Header = xlYes
                .MatchCase = False
                .Apply
            End With
            With .Range
                .AutoFilter Field:=col_sStatus, Criteria1:="<>" & sInactive 'hide inactive Contact Type
            End With
            row_ContactType = .AutoFilter.Range.SpecialCells(xlCellTypeVisible).Rows.Count - 1 'Do not count the header
        End With
    
        If row_ContactType < 1 Then 'no active records found, swtich to show inactive
            vAnswer = MyMsgBox("No active customer types found." & vbCrLf & _
                "Checking for inactive customer types.", _
                vbCritical + vbOKOnly, sTitle)
            fmContactType_CheckBox_IncludeInactive.Value = True
            Call fmContactType_LoadData_Clear
        End If
    
    End If
    
    If fmContactType_CheckBox_IncludeInactive.Value = True Then 'get all records including inactive
    
'       Incude Inactive Contact Types
        With loContactType
            .Sort.SortFields.Clear
            .Sort.SortFields.Add Key:=Range("tblContactType[sName]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
            .Sort.SortFields.Add Key:=Range("tblContactType[lContactTypeID]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
            With .Sort
                .Header = xlYes
                .MatchCase = False
                .Apply
            End With
        End With
        
    End If
    
'   Load the array from the filtered and sorted table
    vContactTypeBody = loContactType.DataBodyRange.SpecialCells(xlCellTypeVisible)
End Sub
 
Upvote 0

Forum statistics

Threads
1,223,214
Messages
6,170,771
Members
452,353
Latest member
strainu

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top