How can I use conditional statements inside ForEach in swiftUI or is it possible?
What is Expected
My expectation is showing the correct food Items according to the ID(foodItem), Since i'm able to get all the food items inside the model class
Use-Case
I'm using a ForEach inside a GridView to display show different food Items, I have all my food items inside my model, and am passing a variable "foodItem" so, that the grid view get to know what type of food I need to show
Current Issue
Since I have the id for food Item I'm using a conditional statement inside the forEach to show the correct foodItem, but the Xcode is giving me an error, 2 errors.
Code of what I have done
LazyVGrid(columns: columns, spacing: 20) {
ForEach(
if(foodType == 1){
model.foodItems
}else if ( foodType == 2){
model.drinkItems
}
else{
model.dessers
}
id: \.self) { item in
VStack{
GridImageView(item.image)
Text(item.food)
}
}
}
.padding(.horizontal)
My Model class
import Foundation
class Model: ObservableObject {
let foodItems = [
FoodItems(food: "Rice",
image: "ricee"),
FoodItems(food: "Fish Curry",
image: "fishcurry"),
FoodItems(food: "Fish Curry 2",
image: "Fish Curry 2"),
FoodItems(food: "Egg Curry",
image: "eggcurry")
]
let drinkItems = [
DrinkItems(food: "Cola",
image: "cola"),
DrinkItems(food: "Pepsi",
image: "pepsi"),
DrinkItems(food: "Limca",
image: "limca"),
]
let dessers = [
Desserts(food: "strawberry",
image: "strawberry"),
Desserts(food: "chocolate",
image: "chocolate"),
]
}
Thanks in advance
CodePudding user response:
You could use a different approach than trying to use conditional statements that do not work inside a ForEach
.
Use a general model for your data (Food
), and use a filter
to select the
type
you want to display, such as in this example code:
struct ContentView: View {
@StateObject var model = Model()
@State var foodType = 1
var body: some View {
// for testing
Button("Change type") {
foodType = foodType 1
if foodType > 3 { foodType = 1 }
}.buttonStyle(.bordered)
ForEach(model.foodItems.filter{$0.type == foodType}) { item in
VStack{
Text(item.food)
// image....
}
}
}
}
struct Food: Identifiable, Hashable {
let id = UUID()
var type: Int
var food: String
var image: String
}
class Model: ObservableObject {
let foodItems = [
Food(type: 1, food: "Rice", image: "ricee"),
Food(type: 1, food: "Fish Curry", image: "fishcurry"),
Food(type: 1, food: "Fish Curry 2", image: "Fish Curry 2"),
Food(type: 1, food: "Egg Curry", image: "eggcurry"),
Food(type: 2, food: "Cola", image: "cola"),
Food(type: 2, food: "Pepsi", image: "pepsi"),
Food(type: 2, food: "Limca", image: "limca"),
Food(type: 3, food: "strawberry", image: "strawberry"),
Food(type: 3, food: "chocolate", image: "chocolate")
]
}
Better still, use enum for the type
.
CodePudding user response:
You can make use of a protocol here and use a an array containing items matching that protocol in your ForEach
Example protocol
protocol Food {
var food: String { get }
var image: String { get }
}
And then conform all your types to this protocol
struct FoodItems: Food {
let food: String
let image: String
}
and so on
Next we add a function in the model class that returns the correct kind of food given a type parameter
func food(type: Int) -> [Food] {
switch type {
case 1:
return foodItems
case 2:
return drinkItems
default:
return dessers
}
}
and then you call this function from your view
LazyVGrid(columns: columns, spacing: 20) {
ForEach(model.food(type: foodType), id: \.food) { item in
VStack {
GridImageView(item.image)
Text(item.food)
}
}
}