Search code examples
arraysswiftlistviewswiftuiswiftui-navigationlink

SwiftUI NavigationLink will not display dynamic data


I am trying to create a navigationLink that pushes to some dynamic list view, unfortunately the view I'm pushing to isn't showing the corresponding data.

My data is parsed from quite complex JSON which has arrays within arrays. I'm new to coding and the only way I can figure to access the nested data is to specify a particular element within the arrays, but by doing that i essentially have created a static list view in the view I'm pushing to.

I would really appreciate a nudge in the right direction. Ive been pulling my hair out. Thanks in advance.

struct MakeList: View {
    var body: some View {
        HStack {
            NavigationView{
                List(vehicleData.makes) { i in
                    HStack {
                        NavigationLink(destination: ModelList()){
                            Image(i.models[0].badges[0].logoName)
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                                .frame(width: 50, height: 50)
                            Text(i.makesName)
                        }
                    }
                }.navigationTitle("Make")
            }
        }
    }
}
struct ModelList: View {
    var body: some View {
        List(vehicleData.makes[0].models) { i in
            Text(i.modelName)
            Text(i.badges[0].series ?? "no series")
        }.navigationTitle("Models")
    }
}

Getting data:

        func load<T: Decodable>(_ filename: String) -> T {
    let data: Data
    
    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
    else {
        fatalError("Couldn't find \(filename) in main bundle.")
    }
    
    do {
        data = try Data(contentsOf: file)
    } catch {
        fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
    }
    
    do {
        let decoder = JSONDecoder()
        return try decoder.decode(T.self, from: data)
    } catch {
        fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
    }
}


var vehicleData: VehicleStruct = load("vehicleValuationData - nested version.json")

// MARK: - VehicleStruct
struct VehicleStruct: Codable, Identifiable {
    var id = UUID()
    let makes: [MakeStruct]
    
    enum CodingKeys: String, CodingKey {
        case makes
    }
}
// MARK: - Make
struct MakeStruct: Codable, Identifiable {
    var id = UUID()
    let makesName: String
    let models: [ModelStruct]
    
    enum CodingKeys: String, CodingKey {
        case makesName
        case models
    }
}
// MARK: - Model
struct ModelStruct: Codable, Identifiable {
    var id = UUID()
    let modelName: String
    let badges: [BadgeStruct]
    
    enum CodingKeys: String, CodingKey {
        case modelName
        case badges
    }
}
// MARK: - Badge
struct BadgeStruct: Codable, Identifiable {
    var id = UUID()
    let badgeName: String
    let series: String?
    let year: Int
    let fuel: String
    let driveType: String
    let bodyType: String
    let transmission: String
    let manualDeduction: Int
    let priceWhenNew: Int
    let depreciationForKms, algorithmValuation: Double
    let valuerValuation: Int
    let valo: Double
    let logoName: String
    
    enum CodingKeys: String, CodingKey {
        case badgeName
        case series
        case year
        case fuel
        case driveType
        case bodyType
        case transmission
        case manualDeduction
        case priceWhenNew
        case depreciationForKms
        case algorithmValuation
        case valuerValuation
        case valo
        case logoName
    }
}

JSON example

{
  "makes": [
    {
      "makesName": "Alfa Romeo",
      "models": [
        {
          "modelName": "147",
          "badges": [
            {
              "badgeName": "Twin Spark",
              "series": null,
              "year": 2004,
              "fuel": "Petrol",
              "driveType": "2WD",
              "bodyType": "Small Hatch",
              "transmission": "Automatic",
              "manualDeduction": -250,
              "subtraction1": null,
              "subtraction1Difference": 0,
              "add1": "Sunroof",
              "add1Difference": 250,
              "add2": null,
              "add2Difference": 0,
              "add3": null,
              "add3Difference": 0,
              "add4": null,
              "add4Differnece": 0,
              "avgAnnualKms": 15000,
              "age": 16,
              "averageKmsForYear": 240000,
              "priceWhenNew": 0,
              "depreciationForKms": 0,
              "algorithmValuation": 0,
              "valuerValuation": 500,
              "valo": 500,
              "logoName": "Alfa"
            }
          ]
        }...

Solution

  • Just pass the corresponding object of type MakeStruct to your subview ModelList:

    NavigationLink(destination: ModelList(make: i)){
        Image(i.models[0].badges[0].logoName)
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: 50, height: 50)
        Text(i.makesName)
    }
    
    struct ModelList: View {
        let make: MakeStruct
    
        var body: some View {
            List(self.make.models) { i in
                Text(i.modelName)
                Text(i.badges[0].series ?? "no series")
            }.navigationTitle("Models")
        }
    }