Home > Enterprise >  Loading table values inside a collection of class objects
Loading table values inside a collection of class objects

Time:04-08

i'm struggling with vba class syntax. I have a table showing me a sort of contacts book, with name, surname, street and zip. When a person has multiple addresses, there is a new row without name and surname but with new street and zip.

I'm trying to store all the data inside a collection with Person and Address class.

Inside my module i try to load the table in the collection. In the first if branch, i make sure that the first cell of the line isn't empty, meaning that it is a new person so i need to create a new collection item. In the else branch i enter when the first cell of the line is empty, meaning that it's just an address that i need to add to the previous collection item. What am i doing wrong?

The code runs correctly on the first iteration of my for cycle but then it gets stuck on the second run of the loop, getting stopped on the class_terminate of my person class.

is it correct the way i store data in the collection?

Address

Option Explicit

Private pStreet As String
Private pZip As Integer

Public Property Let Street(val As String)
   pStreet = val
End Property
Public Property Get Street() As String
   Street = pStreet
End Property
Public Property Let Zip(val As Integer)
   pZip = val
End Property
Public Property Get Zip() As Integer
   Zip = pZip
End Property

Person

Private pName As String
Private pSurname As String
Private pAddresses As New Collection

Public Property Let Name(val As String)
    pName = val
End Property
Public Property Get Name() As String
    Name = pName
End Property

Public Property Let Surname(val As String)
    pSurname = val
End Property
Public Property Get Surname() As String
    Surame = pSurname
End Property

Private Sub Class_Initialize()
    Set pAddresses = New Collection
End Sub

Private Sub Class_Terminate()
    Set pAddresses = Nothing
End Sub

Public Sub addAddress(ByVal val As Address)
    pAddresses.Add val
End Sub

Public Property Get Addresses() As Collection
    Set Addresses = pAddresses
End Property

Public Property Get Address(ByVal Index As Long) As Address
    Set Address = pAddresses(Index)
End Property 

PersonFactory

Option Explicit

Public Function Create(ByVal Name As String, ByVal Surname As String, ByVal Street As String, ByVal Zip As Integer) As person
   Dim a As Address
   
   Set Create = New person
   Create.Name = Name
   Create.Surname = Surname
   
   Set a = New Address
   a.Street = Street
   a.Zip = Zip
   Create.Addresses.Add a
   
   Set Create = Nothing
   Set a = Nothing
   
End Function

ModuleTest

Private Sub testFilter()

    Dim nameCol, surnameCol, streetCol, zipCol As Integer

    nameCol = 1
    surnameCol = 2
    streetCol = 3
    zipCol = 4

    Dim coll As New Collection
    Sheets.Item("contacts").Select
    
    For i = 2 To getLastRow
        If Cells(i, nameCol).Value <> "" Then
            k = k   1
            Dim pf As PersonFactory
            Dim p As person
            Set pf = New PersonFactory
            Set p = pf.Create(CStr(Cells(i, nameCol).Value), CStr(Cells(i, surnameCol).Value), CStr(Cells(i, streetCol).Value), CInt(Cells(i, zipCol).Value))
            coll.Add p
            
            Set pf = Nothing
            Set p = Nothing
        Else
            Dim addr As Address
            Set addr = New Address
            addr.Street = CStr(Cells(i, streetCol).Value)
            addr.Zip = CInt(Cells(i, streetCol).Value)
            coll.Add addr
            
            Set addr = Nothing
        End If
    Next
End Sub

enter image description here

CodePudding user response:

I did a little refactoring of your test-module - see comments inline

Option Explicit

Private Enum en_colTable
    'value of enums are automatically increased by 1
    'if you change the order the value changes as well
    nameCol = 1
    surnameCol
    streetCol
    zipCol
End Enum


Private Sub testFilter()

    Dim colPersons As New Collection    'this name is more explicit about what the collection is
    
    Dim ws As Worksheet
    Set ws = Thisworkbook.Worksheets.Item("contacts")    'use a worksheet variable to be more explicit
    
    Dim pf As personFactory
    Dim p As person, addr As Address
    
    Set pf = New personFactory  'you need to do this only once
    
    Dim i As Long
    With ws
        For i = 2 To getLastRow
            If .Cells(i, nameCol).Value <> "" Then
                Set p = pf.Create(CStr(.Cells(i, nameCol).Value), _
                                 CStr(.Cells(i, surnameCol).Value), CStr(.Cells(i, streetCol).Value), CInt(.Cells(i, zipCol).Value))
                colPersons.Add p
                
            Else
                Set addr = New Address
                addr.Street = CStr(.Cells(i, streetCol).Value)
                addr.Zip = CInt(.Cells(i, streetCol).Value)
                p.Addresses.Add addr    'add address to person
            End If
        Next
    End With
End Sub

Regarding the ParentFactory: You must not set those created objects to nothing!!!

ParentFactory

Option Explicit

Public Function Create(ByVal Name As String, ByVal Surname As String, ByVal Street As String, ByVal Zip As Integer) As Person
   Dim a As Address
   
   Set Create = New Person
   Create.Name = Name
   Create.Surname = Surname
   
   Set a = New Address
   a.Street = Street
   a.Zip = Zip
   Create.Addresses.Add a
   
' Do not set these variables to nothing - if so they don't exist anylonger!!!!
'   Set Create = Nothing
'   Set a = Nothing
   
End Function
  • Related