I'm a beginner with SwiftUI and I wanted to create a dynamic list with the birthdays of people. I also wanted to integrate a filter that facilitates to find birthdays. But in the lines:
if enableFilter == true {
return json.filter {$0.BirthdayString.contains(filter(date: filterDate))}
} else {
return json
}
I always get these errors:
Instance member 'enableFilter' cannot be used on type 'ContentView'; did you mean to use a value of this type instead?
and
Instance member 'filterDate' cannot be used on type 'ContentView'; did you mean to use a value of this type instead?
I think I understand why the errors are present but I don't no how to fix it. I tried:
@State static var
but then I cannot change the values with my
filterView
Thank you for your help, here is the full source code:
import SwiftUI
struct person: Codable, Hashable, Identifiable {
var id: Int
var Birthday: Date
var BirthdayString: String
}
func filter(date: Date) -> String {
let DateComponents = Calendar.current.dateComponents([.year, .month, .day], from: date)
let DateComponentsString: String = "\(DateComponents.day)/\(DateComponents.month)/\(DateComponents.year)"
return DateComponentsString
}
struct ContentView: View {
@State var people: [person] = {
guard let data = UserDefaults.standard.data(forKey: "people") else { return [] }
if let json = try? JSONDecoder().decode([person].self, from: data) {
if enableFilter == true {
return json.filter {$0.BirthdayString.contains(filter(date: filterDate))}
} else {
return json
}
}
return []
}()
@State var filterDate: Date = Date()
@State var enableFilter: Bool = false
@State var showFilter: Bool = false
@State var newPersonDate: Date = Date()
var body: some View {
NavigationView {
VStack {
HStack {
DatePicker(selection: $newPersonDate, label: {Text("Birthday")}).padding()
Button(action: {didTapAddTask()}, label: {Text("Add")}).padding()
}
List {
ForEach($people) { $person in
Text("\(person.Birthday)")
}
}
}
.navigationTitle(Text("People's birthday"))
}
}
var filterView: some View {
VStack {
DatePicker(selection: $filterDate, label: {Text("Date")}).padding()
Toggle(isOn: $enableFilter, label: {Text("enable filter")}).padding()
}
}
func didTapAddTask() {
let id = people.reduce(0) { max($0, $1.id) } + 1
people.insert(person(id: id, Birthday: newPersonDate, BirthdayString: filter(date: newPersonDate)), at: 0)
newPersonDate = Date()
save()
}
func save() {
guard let data = try? JSONEncoder().encode(people) else { return }
UserDefaults.standard.set(data, forKey: "people")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
You can use another Computed property which will get the data based on some another property's value. i.e enableFilter
.
@State var people: [person] = {
guard let data = UserDefaults.standard.data(forKey: "people") else { return [] }
if let json = try? JSONDecoder().decode([person].self, from: data) {
return json
}
return []
}()
var data : [person] {
if enableFilter {
return people.filter {$0.BirthdayString.contains(filter(date: filterDate))}
} else {
return people
}
}
And use this property to get the relevant data:
var body: some View {
NavigationView {
VStack {
HStack {
DatePicker(selection: $newPersonDate, label: {Text("Birthday")}).padding()
Button(action: {didTapAddTask()}, label: {Text("Add")}).padding()
}
List {
ForEach(data) { person in // <<--- Here `data`
Text("\(person.Birthday)")
}
}
}
.navigationTitle(Text("People's birthday"))
}
}