I am trying to filter through data that I have retrieved from an API based on a model of car, I have a @State that holds an empty string initially and will update based on what the user has typed. I can't figure out how to filter the data based on the input inside of my existing ForEach loop, any help would be appreciated
import SwiftUI
struct HomeView: View {
@EnvironmentObject var users: Network
let columns = [
GridItem(.adaptive(minimum: 150))
]
@State var isActive: Bool = false
@State private var shouldAnimate = false
@State var show = false
@State private var searchText = ""
@Environment(\.colorScheme) var colorScheme
var searchResults: [Car] {
let searchModel = String(searchText)
return searchModel == nil ? users.users : users.users.filter{$0.model == searchModel}
}
var body: some View {
ScrollView {
if self.users.users.count > 0 {
Text("All \(self.users.users[1].make) vehicles")
.bold()
.textCase(.uppercase)
.font(.headline)
} else {
Spacer()
Spacer()
HStack(alignment: VerticalAlignment.center) {
Circle()
.fill(shouldAnimate ? Color.orange : Color.white)
.frame(width: 20, height: 20)
.scaleEffect(shouldAnimate ? 1.0 : 0.5)
.animation(
Animation.easeInOut(duration: 0.5).repeatForever(autoreverses: true), value: show)
Circle()
.fill(shouldAnimate ? Color.orange : Color.white)
.frame(width: 20, height: 20)
.scaleEffect(shouldAnimate ? 1.0 : 0.5)
.animation(
Animation.easeInOut(duration: 0.5).repeatForever(autoreverses: true).delay(0.3),
value: show)
Circle()
.fill(shouldAnimate ? Color.orange : Color.white)
.frame(width: 20, height: 20)
.scaleEffect(shouldAnimate ? 1.0 : 0.5)
.animation(
Animation.easeInOut(duration: 0.5).repeatForever(autoreverses: true).delay(0.6),
value: show)
}
Spacer()
VStack {
Text("Retrieving the Data...")
.foregroundColor(Color.white)
.textCase(.uppercase)
}
}
SearchBar(text: $searchText)
.padding(.top, -30)
LazyVGrid(columns: columns, spacing: 10) {
ForEach(searchResults) { car in
if car.year >= 2017 {
HStack(alignment: .top) {
VStack {
Image(systemName: "car.fill")
.resizable()
.scaledToFit()
.frame(width: 140.0, height: 70)
.foregroundColor(.white)
Text(car.model ?? "lol")
.font(.system(size: 15, weight: .bold, design: .default))
.foregroundColor(colorScheme == .dark ? Color.white : Color.black)
.frame(maxWidth: .infinity, alignment: .center)
Text(String(car.year))
.font(.system(size: 16, weight: .regular, design: .default))
.foregroundColor(.orange)
.frame(maxWidth: .infinity, alignment: .center)
Text(car.make)
.font(.system(size: 16, weight: .bold, design: .default))
.foregroundColor(colorScheme == .dark ? Color.white : Color.gray)
.frame(maxWidth: .infinity, alignment: .center)
}
.frame(height: 250)
.background(colorScheme == .dark ? Color.black.opacity(0.2) : Color.white)
.cornerRadius(20)
.padding()
.clipped()
.shadow(color: Color.black.opacity(0.24), radius: 10, x: 0, y: 0)
}
}
}
}
}
.background(colorScheme == .dark ? Color.black.opacity(0.1) : Color.white)
.onAppear {
users.getCars()
self.shouldAnimate = true
self.show = true
}
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
.environmentObject(Network())
}
}
Data:
[
{
"id": 1119,
"make": "Audi",
"model": "100",
"generation": "100 Avant (4A,C4)",
"engine_modification": "2.8 V6 E (174 Hp) quattro Automatic",
"year": 1991,
"powertrain_architecture": "Internal Combustion engine",
"body_type": "Station wagon (estate)",
"number_of_seats": 5,
"number_of_doors": 5,
"urban_fuel_consumption": 13.5,
"extra_urban_fuel_consumption": 8,
"combined_fuel_consumption": 10,
"fuel_type": "Petrol (Gasoline)",
"acceleration": 9.5,
"top_speed": 207,
"power": 174,
"torque": 250,
"engine_location": "Front, Longitudinal",
"engine_displacement": 2771,
"number_of_cylinders": 6,
"position_of_cylinders": "V-engine",
"number_of_valves_per_cylinder": 2,
"fuel_system": "Multi-point indirect injection",
"engine_aspiration": "Naturally aspirated engine",
"kerb_weight": 1550,
"fuel_tank_capacity": 80,
"drive_wheel": "All wheel drive (4x4)",
"number_of_gears": 4,
"front_brakes": "Ventilated discs",
"rear_brakes": "Disc"
},
{
"id": 1120,
"make": "Audi",
"model": "100",
"generation": "100 Avant (4A,C4)",
"engine_modification": "2.8 V6 E (174 Hp) quattro",
"year": 1991,
"powertrain_architecture": "Internal Combustion engine",
"body_type": "Station wagon (estate)",
"number_of_seats": 5,
"number_of_doors": 5,
"urban_fuel_consumption": 13.5,
"extra_urban_fuel_consumption": 8,
"combined_fuel_consumption": 10,
"fuel_type": "Petrol (Gasoline)",
"acceleration": null,
"top_speed": null,
"power": 174,
"torque": 250,
"engine_location": "Front, Longitudinal",
"engine_displacement": 2771,
"number_of_cylinders": 6,
"position_of_cylinders": "V-engine",
"number_of_valves_per_cylinder": 2,
"fuel_system": "Multi-point indirect injection",
"engine_aspiration": "Naturally aspirated engine",
"kerb_weight": 1550,
"fuel_tank_capacity": 80,
"drive_wheel": "All wheel drive (4x4)",
"number_of_gears": 5,
"front_brakes": "Ventilated discs",
"rear_brakes": "Disc"
},
users.users
import Foundation
struct Car: Hashable,Codable, Identifiable {
let id : Int?
var make: String
var model: String?
var generation: String?
var engine_modification: String?
var year: Int
var powertrain_architecture: String?
var body_type: String?
var number_of_seats: Int?
var number_of_doors: Int?
var urban_fuel_consumption: Double?
var extra_urban_fuel_consumption: Double?
var combined_fuel_consumption: Double?
var fuel_type: String?
var acceleration: Double? // was Int
var top_speed: Int? // was Int
var power: Int?
var torque: Int?
var engine_location: String?
var engine_displacement: Int?
var number_of_cylinders: Int?
var position_of_cylinders: String?
var number_of_valves_per_cylinder: Int?
var fuel_system: String?
var engine_aspiration: String?
var kerb_weight: Int?
var fuel_tank_capacity: Double?
var drive_wheel: String?
var number_of_gears: Int?
var front_brakes: String?
var rear_brakes: String?
}
CodePudding user response:
try something like this example code, assuming you want to search by year:
@State var searchText = ""
var searchResults: [Car] {
let searchYear = Int(searchText)
searchYear == nil ? users.users : users.users.filter{$0.year == searchYear!}
}
var body: some View {
// ...
SearchBar(text: $searchText)
// ...
LazyVGrid(columns: columns, spacing: 10) {
ForEach(searchResults) { car in
HStack(alignment: .top) {
VStack {
// ...
}
}
}
}
}
EDIT-1: to search for car model, try this:
var searchResults: [Car] {
searchText.isEmpty ? users.users : users.users.filter{
$0.model == nil ? false : $0.model!.contains(searchText)
}
}
EDIT-2: here is the code I used in my tests, to show that the approach works:
struct Car: Identifiable {
let id = UUID()
var year: Int
var make: String
var model: String?
}
struct ContentView: View {
@State var cars = [Car(year: 123, make: "aaa", model: "bbb"),
Car(year: 456, make: "cc", model: "dd"),
Car(year: 789, make: "eee", model: "dd")]
@State private var searchText = ""
var searchResults: [Car] {
searchText.isEmpty ? cars : cars.filter{
$0.model == nil ? false : $0.model!.contains(searchText)
}
}
var body: some View {
NavigationView {
List (searchResults) { car in
Text(car.model ?? "no data")
}
}
.searchable(text: $searchText)
}
}