Reputation: 1399
I'm trying to display elements from a top level array in a list view. The data model is constructed in a way that it's an array of events and then within that array there's an array of venues associated with the individual events.
In the main view, I know how to display an individual event title by it's index, but I'm not sure how to use ForEach to list all the different events.
Passports.swift (Data model)
import Foundation
import SwiftUI
struct Passport: Identifiable {
let id : Int
let passportPremium: Bool
let passportActive: Bool
let passportTitle: String
let passportDates: String
let venues: [Venue]
}
struct Venue: Identifiable {
let id = UUID()
let title : String
let venueArea: String
let venueItems: [venueItem]
}
struct venueItem {
let title: String
let productDescription: String
let productPrice: Double
let productType: String
let newStatus: Bool
let diningPlan: Bool
let kidFriendly: Bool
let vegetarian: Bool
let glutenFree: Bool
let featuredProduct: Bool
let containsAlcohol: Bool
}
extension Passport {
static func all() -> [Passport] {
return [
Passport (
id: 1001,
passportPremium: false,
passportActive: true,
passportTitle : "Event 1",
passportDates: "October 20 - November 3, 2019",
venues: [
Venue (
title: "Bavaria Holiday Kitchen",
venueArea: "Germany Pavilion",
venueItems: [
venueItem (
title: "Potato Dumpling",
productDescription: "Potato Dumpling with Mushroom Sauce",
productPrice: 0.00,
productType: "Food",
newStatus: false,
diningPlan: false,
kidFriendly: true,
vegetarian: false,
glutenFree: false,
featuredProduct: false,
containsAlcohol: false
)
] // End VenueItems
) // End Venue
] // End Venues
),
Passport (
id: 1002,
passportPremium: false,
passportActive: true,
passportTitle : “Event 2“,
passportDates: "October 20 - November 3, 2019",
venues: [
Venue (
title: "Bavaria Holiday Kitchen",
venueArea: "Germany Pavilion",
venueItems: [
venueItem (
title: "Potato Dumpling",
productDescription: "Potato Dumpling with Mushroom Sauce",
productPrice: 0.00,
productType: "Food",
newStatus: false,
diningPlan: false,
kidFriendly: true,
vegetarian: false,
glutenFree: false,
featuredProduct: false,
containsAlcohol: false
)
] // End VenueItems
) // End Venue
] // End Venues
)// End Individual Passport
] // End Return
}
}
PassportsView.swift
import SwiftUI
struct PassportsView: View {
var model = Passports.all()
var body: some View {
NavigationView {
ForEach(self.model) { item in
NavigationLink (destination: PassportDetails(passportTitle: item.passportTitle, venues: item.venues, venueProd: []) ) {
HStack {
VStack(alignment: .leading) {
Text(item.passport[0].passportTitle)
.fontWeight(.semibold)
.foregroundColor(Color.white)
Text(item.passport[0].passportDates)
.foregroundColor(Color.white)
}.frame(width: 400, height: 120)
.background(Color("wPurple"))
.cornerRadius(6)
}
}.padding(.horizontal)
}
}
}
}
PassportDetails.swift
struct PassportDetails: View {
var passportTitle: String
var venues: [Venue]
var venueProd: [venueItem]
var body: some View {
List {
ForEach(self.venues) { gc in
Section(header: Text(gc.title)) {
ForEach(gc.venueItems, id: \.title) { gi in
GeometryReader { geometry in
VStack(alignment: .leading) {
HStack {
Text(gi.title)
.frame(width: geometry.size.width / 1.5, alignment: .leading)
.fixedSize(horizontal: false, vertical: true)
.padding(.top, 10)
Spacer()
Text("$\(gi.productPrice, specifier: "%.2f")")
.multilineTextAlignment(.trailing)
}.padding(.top, 8)
HStack {
Text(gi.productDescription)
.font(.footnote)
.foregroundColor(Color.gray)
.frame(width: geometry.size.width / 1.5, alignment: .leading)
.fixedSize(horizontal: false, vertical: true)
.padding(.bottom, 8)
Spacer()
}.padding(.bottom, 8)
}
}.padding(.vertical)
}
}
}
}.listStyle(GroupedListStyle())
.navigationBarTitle(Text(passportTitle), displayMode: .inline)
}
}
So obviously "Text(item.passport[0].passportTitle)" is going to show the first item in the array, but I want to display all passportTitles and passportDates in the top array as well as passing the information on to the details view using the NavigationLink.
Upvotes: 3
Views: 2720
Reputation: 9463
Based on your description, you want a two level data model and view hierarchy:
Passport
struct)Venue
struct)Your current data model is three level (Passports
containing Passport
containing Venue
).
If we remove the extraneous Passports
struct, we can clean up your static .all()
function and PassportsView
struct.
extension Passport {
static func all() -> [Passport] {
return [
Passport (
id: 1001,
passportPremium: false,
passportActive: true,
passportTitle : "Wine Festival",
passportDates: "October 20 - November 3, 2020",
venues: [
Venue (
title: "Bavaria Holiday Kitchen",
venueArea: "Germany Pavilion",
venueItems: [
venueItem (
title: "Potato Dumpling",
productDescription: "Potato Dumpling with Mushroom Sauce",
productPrice: 0.00,
productType: "Food",
newStatus: false,
diningPlan: false,
kidFriendly: true,
vegetarian: false,
glutenFree: false,
featuredProduct: false,
containsAlcohol: false
)
])
])
]
}
}
Here's the updated view:
struct PassportsView: View {
var model = Passport.all()
var body: some View {
NavigationView {
ForEach(self.model) { passport in
NavigationLink (destination: PassportDetails(passportTitle: passport.passportTitle, venues: passport.venues, venueProd: []) ) {
HStack {
VStack(alignment: .leading) {
Text(passport.passportTitle)
.fontWeight(.semibold)
.foregroundColor(Color.white)
Text(passport.passportDates)
.foregroundColor(Color.white)
}.frame(width: 400, height: 120)
.background(Color("wPurple"))
.cornerRadius(6)
}
}.padding(.horizontal)
}
}
}
}
Upvotes: 2