UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

I'm really struggling with JSON and SwiftUI in my project, and what I think is called Nesting?

Forums > SwiftUI

Hi Everyone,

I've been learning how to implement a JSON database that is also local to my project. I'm keeping it local while I build out the rest of my app/project.

A part of this app is "accounts", that will often times have multiple "contacts" at each one. The accounts are really crucial here. So say for example it's a chain of stores, that all need to have their own employees. In JSON, I believe this is called nesting. Is that correct?

In my project, I've so far been able to get an account view to present just one contact. So how the app works is that you click on an accont from a list, and that next view presents with all of its important data. Some of this data happens to be who works at each of these locations.

What I'm struggling with is trying to get more than one person to appear in this 'contacts' area of the app.

I will provide a sample below of what I have so far. I think I've done an ok job, and that this has something to do with how I've implemented the contacts field in the list.


// Account as Singular as it represents the array of data for ONE account
struct Account: Identifiable, Codable {
    var id = UUID()
    let company: String
    let address: String
    let city: String
    let postalCode: String
    let phoneOne: String
    let phoneTwo: String
    let emailAddress: String
    let website: String
    let contacts: contactData
    let quotes: quoteData
    let notes: noteData
}

//Goes to contacts
struct contactData: Codable {
    let firstName: String
    let lastName: String
    let companyName: String
    let positionDepartment: String
    let accountManager: String
    let email: String
    let cellNumber: String
    let officeNumber: String
    let billingAddress: String
    let city: String
    let province: String
    let postalCode: String
}
....

struct AccountList {

    static var activeAccounts =  [

        //First
        Account(
            company: "First Coffee House",
            address: "xxxxxxxx Main Ave",
            city: "xxxxxxx",
            postalCode: "D4F 5D3",
            cellNumber: "xxx-xxx-xxxxx",
            officeNumber: "xxx-xxx-xxxxx",
            emailAddress: "xxxxx@xxxxxx.com",
            website: " ",

            contacts: contactData.init (
                firstName: "Al",
                lastName: "Carter",
                companyName: "xx xxxxxxxx xxxxxxx",
                positionDepartment: "Inside",
                accountManager: "xxxxxx",
                email: "xxxxx@xxxxxx.xxxx",
                cellNumber: "xxx-xxx-xxxxx",
                officeNumber: "xxx-xxx-xxxxx",
                billingAddress: "xxxxx Main Rd",
                city: "xxxxxxx",
                province: "xx",
                postalCode: "F3D 6S3"),

            contacts: contactData.init (
                firstName: "Bob ",
                lastName: "Smith",
                companyName: "xx xxxxxxxx xxxxxxx",
                positionDepartment: "Counter",
                accountManager: "xxxxxx",
                email: "xxxxx@xxxxxx.xxxx",
                cellNumber: "xxx-xxx-xxxxx",
                officeNumber: "xxx-xxx-xxxxx",
                billingAddress: "xxxxx Main Rd",
                city: "xxxxxxxxx",
                province: "xx",
                postalCode: "F3D 6S3"),

That is the rougly the model I'm working with. Below is the view that gets me to the point of presenting "Al Carter". I've tried several thins to get it to also present "Bob Smith".

            VStack {

                Section {

                    ForEach(Array(arrayLiteral: account.contacts.firstName.count), id: \.self) { _ in

                        SubTextFields(leftSideField: "\(account.contacts.positionDepartment)", rightSideField: ("\(account.contacts.firstName) \(account.contacts.lastName)"))
                    }
                }
            }

Any help here or if someone could point me in the correct direction of what I should read up on, would be really helpful. I've been strugglin with this since Wednesday.

Anty help is always appreciated! Cheers!

2      

Your contacts field in Account should be an array. (And you should rename contactData to ContactData, since the Swift convention is for types to be named with a capital letter.)

There are some other issues in your code.

  1. Account.contacts should be an array of ContactData rather than a singular instance. Similarly, quotes and notes should presumably be arrays of their types too.
  2. You have phoneOne and phoneTwo in your Account struct but when you create an Account you are using cellNumber and officeNumber, which belong to ContactData, not Account.
  3. Since Account.contacts should be an array of ContactData, you need to initialize it as an Array when you create activeAccounts. Currently, you are just creating multiple contacts properties.
  4. To display your contacts, you need to loop through them in the ForEach but you are actually looping through an array you construct from the count of contacts. So that array looks something like [2] instead of an array of contacts.
  5. You are statically initializing activeAccounts instead of reading it in from JSON, so we can only make some assumptions about how it will work. If you provide some sample JSON data, we can determine if you've got your structs declared properly.

Take a look at the below code. This is my attempt to illustrate how to achieve what you are trying. It may not match exactly with what you want since you didn't give us sample JSON or a full View struct to play with, but it should hopefully help you figure out what you need to do.

import SwiftUI

struct Account: Identifiable, Codable {
    var id = UUID()
    let company: String
    let address: String
    let city: String
    let postalCode: String
    let phoneOne: String
    let phoneTwo: String
    let emailAddress: String
    let website: String
    //1 contacts should be an array of ContactData
    //  since there will be mpore than one contact person
    let contacts: [ContactData]
    //removed some things for ease of example
    //let quotes: [QuoteData] <-- should be an array as well
    //let notes: [NoteData] <-- should be an array as well
}

struct ContactData: Identifiable, Codable {
    var id = UUID() //added so we can loop with ForEach
    let firstName: String
    let lastName: String
    let companyName: String
    let positionDepartment: String
    let accountManager: String
    let email: String
    let cellNumber: String
    let officeNumber: String
    let billingAddress: String
    let city: String
    let province: String
    let postalCode: String
}

struct AccountList: Codable {
    var accounts: [Account]

    static let activeAccounts: [Account] = [
        Account(
            company: "First Coffee House",
            address: "xxxxxxxx Main Ave",
            city: "xxxxxxx",
            postalCode: "D4F 5D3",
            phoneOne: "xxx-xxx-xxxxx", //you had this declared as phoneOne but called it as cellNumber
            phoneTwo: "xxx-xxx-xxxxx", //you had this declared as phoneTwo but called it as officeNumber
            emailAddress: "xxxxx@xxxxxx.com",
            website: "",
            contacts: [ //contacts should be an array of ContactData
                ContactData(
                    firstName: "Al",
                    lastName: "Carter",
                    companyName: "xx xxxxxxxx xxxxxxx",
                    positionDepartment: "Inside",
                    accountManager: "xxxxxx",
                    email: "xxxxx@xxxxxx.xxxx",
                    cellNumber: "xxx-xxx-xxxxx",
                    officeNumber: "xxx-xxx-xxxxx",
                    billingAddress: "xxxxx Main Rd",
                    city: "xxxxxxx",
                    province: "xx",
                    postalCode: "F3D 6S3"
                ),
                ContactData(
                    firstName: "Bob ",
                    lastName: "Smith",
                    companyName: "xx xxxxxxxx xxxxxxx",
                    positionDepartment: "Counter",
                    accountManager: "xxxxxx",
                    email: "xxxxx@xxxxxx.xxxx",
                    cellNumber: "xxx-xxx-xxxxx",
                    officeNumber: "xxx-xxx-xxxxx",
                    billingAddress: "xxxxx Main Rd",
                    city: "xxxxxxxxx",
                    province: "xx",
                    postalCode: "F3D 6S3"
                )
            ]
        )
    ]
}

struct AccountView: View {
    @State private var accounts = AccountList.activeAccounts

    var body: some View {
        VStack {
            Section {
                //loop through each account
                ForEach(accounts) { acct in 
                    //then through each contact in the account
                    ForEach(acct.contacts) { contact in 
                        //simple for the sake of example and because I don't have your
                        //SubTextFields view
                        VStack {
                            Text("\(contact.firstName) \(contact.lastName)")
                            Text(contact.companyName)
                        }
                    }
                }
            }
        }
    }
}

2      

Holy moly! Thank you so much for taking the time to write this out for me. I knew there was a couple of things wrong with my formating/syntax.

I'll let you know how it goes - Cheers!

2      

Any chance you can give me one more bit of advice please? As it standsa right now, I've got the view to return the data of contacts, but it's returning all of the contacts from the JSON database. The contacts are meant to be pulled from their specific accounts.

I've tried hard to figure this one out, but I'm probably a bit out of my depth here.

Any insights or articles I could read that would put me in the right direction?

Thank you again!

2      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.