Reputation: 589
OUTLINE:
I have a data model that contains an array of video names that are attached to each ProductModel
.
So for example: ProductModel
1 would contain videos video1
, video2
. However, ProductModel
2 would contain videos video3
, video4
and video5
. As well as the name of the videos I also have a thumbnail and description that link in with the video names.
My data model looks like this:
NOTE: There are other multiple ProductModels, but for the purpose of keeping the code short I have only shown one.
struct ProductModel: Identifiable {
var id = UUID()
var video: [String]
var videoThumbnail: [String]
var videoDescription: [String]
}
let productData: [ProductModel] = [
ProductModel(
video: ["video1", "video2"],
videoThumbnail: ["thumbnail1", "thumbnail2"],
videoDescription: ["description1", "description2"]
),
ProductModel(
video: ["video3", "video4", "video5"],
videoThumbnail: ["thumbnail3", "thumbnail4", "thumbnail5"],
videoDescription: ["description3", "description4", "description5:]
),
]
PROBLEM:
When trying to list the arrays using a ForEach I keep getting errors. I have tried 2 different ways but I keep getting errors and can't see where I am going wrong. Any guidance would be appreciated.
ForEach method 01:
ForEach(0..<product.video.count){ item in
Button(action: {
// PLAY VIDEO
}) {
VStack{
Image(product.thumbnail[item]) // VIDEO THUMBNAIL
Text(product.video[item]) // VIDEO NAME
Text(product.videoDescription[item]) // VIDEO DESCRIPTION
}
}
}
ForEach method 02:
ForEach(Array(zip(product.video, product.videoThumbnail, product.videoDescription)), id: \.0) { item in
Button(action: {
// PLAY VIDEO
}) {
VStack{
Image(item.1) // VIDEO THUMBNAIL
Text(item.0) // VIDEO NAME
Text(item.2) // VIDEO DESCRIPTION
}
}
}
Upvotes: 1
Views: 865
Reputation: 29632
///This way relies on the index for the videos and related info always matching. It is an easy way to have mixmatch information
struct NestedList: View {
var body: some View {
List{
ForEach(0..<productData.count, id: \.self){ productsIdx in
ForEach(0..<productData[productsIdx].video.count, id: \.self){ videoIdx in
Button(action: {
print(
"playing" + productData[productsIdx].video[videoIdx])
}, label: {
HStack{
Text(productData[productsIdx].videoThumbnail[videoIdx])
Text(productData[productsIdx].videoDescription[videoIdx])
}
})
}
}
}
}
}
The more concise way to do this is to isolate the video information to a model so it all sticks together regardless of the order. As mentioned in the comments.
struct ProductModel: Identifiable {
var id = UUID()
var videos: [VideoModel]
}
struct VideoModel: Identifiable {
let id = UUID()
var video: String
var videoThumbnail: String
var videoDescription: String
}
var productData: [ProductModel]{
var videos : [VideoModel] = []
for n in 1...6{
videos.append(VideoModel(video: "video\(n)", videoThumbnail: "thumbnail\(n)", videoDescription: "description\(n)"))
}
return [ProductModel(videos: videos)]
}
struct NestedList2: View {
var body: some View {
List{
ForEach(productData, id: \.id){ product in
ForEach(product.videos, id: \.id){ video in
Button(action: {
print(
"playing" + video.video)
}, label: {
HStack{
Text(video.videoThumbnail)
Text(video.videoDescription)
}
})
}
}
}
}
}
The for
loop is just to automate the creation of the array. The first variable below is interchangeable with your productData
and the second shows the equivalent to the build format of the array with the new structure.
var productData: [ProductModel]{
var videos: [String] = []
var thumbnails: [String] = []
var descriptions: [String] = []
for n in 1...6{
videos.append("video\(n)")
thumbnails.append("thumbnail\(n)")
descriptions.append("description\(n)")
}
return [ProductModel(video: videos, videoThumbnail: thumbnails, videoDescription: descriptions)]
}
let productData: [ProductModel] = [ProductModel(videos: [
VideoModel(video: "video1", videoThumbnail: "thumbnail1", videoDescription: "description1"),
VideoModel(video: "video2", videoThumbnail: "thumbnail2", videoDescription: "description2"),
VideoModel(video: "video3", videoThumbnail: "thumbnail3", videoDescription: "description3"),
VideoModel(video: "video4", videoThumbnail: "thumbnail4", videoDescription: "description4"),
VideoModel(video: "video5", videoThumbnail: "thumbnail5", videoDescription: "description5"),
VideoModel(video: "video6", videoThumbnail: "thumbnail6", videoDescription: "description6")
])]
Different ways of accomplishing a sample array the loop has less copy and paste .
You would create your own [VideoModel]
using the method that most benefits your use case.
Upvotes: 2