Reputation: 2836
How to access values from particular item on the list made with ForEach? As you can see I was trying something like this (and many other options):
Text(item[2].onOff ? "On" : "Off")
I wanted to check the value of toggle of 2nd list item (for example) and update text on the screen saying if it's on or off.
And I know that it's something to do with @Binding and I was searching examples of this and trying few things, but I cannot make it to work. Maybe it is a beginner question. I would appreciate if someone could help me.
My ContentView:
struct ContentView: View {
// @Binding var onOff : Bool
@State private var onOff = false
@State private var test = false
var body: some View {
NavigationView {
List {
HStack {
Text("Is 2nd item on or off? ")
Text(onOff ? "On" : "Off")
// Text(item[2].onOff ? "On" : "Off")
}
ForEach((1...15), id: \.self) {item in
ListItemView()
}
}
.navigationBarTitle(Text("List"))
}
}
}
And ListItemView:
import SwiftUI
struct ListItemView: View {
@State private var onOff : Bool = false
// @Binding var onOff : Bool
var body: some View {
HStack {
Text("99")
.font(.title)
Text("List item")
Spacer()
Toggle(isOn: self.$onOff) {
Text("Label")
}
.labelsHidden()
}
}
}
Upvotes: 0
Views: 538
Reputation: 5117
import SwiftUI
struct ContentView: View {
@State private var onOffList = Array(repeating: true, count: 15)
var body: some View {
NavigationView {
List {
HStack {
Text("Is 2nd item on or off? ")
Text(onOffList[1] ? "On" : "Off")
}
ForEach((onOffList.indices), id: \.self) {idx in
ListItemView(onOff: self.$onOffList[idx])
}
}
.navigationBarTitle(Text("List"))
}
}
}
struct ListItemView: View {
@Binding var onOff : Bool
var body: some View {
HStack {
Text("99")
.font(.title)
Text("List item")
Spacer()
Toggle(isOn: $onOff) {
Text("Label")
}
.labelsHidden()
}
}
}
Upvotes: 1
Reputation: 2836
I understand that you are directing me to use ObservableObject. And probably it's the best way to go with final product. But I am still thinking about @Binding as I just need to pass values better between 2 views only. Maybe I still don't understand binding, but I came to this solution.
struct ContentView: View {
// @Binding var onOff : Bool
@State private var onOff = false
// @State private var test = false
var body: some View {
NavigationView {
List {
HStack {
Text("Is 2nd item on or off? ")
Text(onOff ? "On" : "Off")
// Text(self.item[2].$onOff ? "On" : "Off")
// Text(item[2].onOff ? "On" : "Off")
}
ForEach((1...15), id: \.self) {item in
ListItemView(onOff: self.$onOff)
}
}
.navigationBarTitle(Text("List"))
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
and ListItemView:
import SwiftUI
struct ListItemView: View {
// @State private var onOff : Bool = false
@Binding var onOff : Bool
var body: some View {
HStack {
Text("99")
.font(.title)
Text("List item")
Spacer()
Toggle(isOn: self.$onOff) {
Text("Label")
}
.labelsHidden()
}
}
}
What is happening now is text is being updated after I tap toggle. But I have 2 problems:
tapping 1 toggle changes all of them. I think it's because of this line:
ListItemView(onOff: self.$onOff)
I still cannot access value of just one row. In my understanding ForEach((1...15), id: .self) make each row have their own id, but I don't know how to access it later on.
Upvotes: 0
Reputation: 4450
I don't know what exactly you would like to achieve, but I made you a working example:
struct ListItemView: View {
@ObservedObject var model: ListItemModel
var body: some View {
HStack {
Text("99")
.font(.title)
Text("List item")
Spacer()
Toggle(isOn: self.$model.switchedOnOff) {
Text("Label")
}
.labelsHidden()
}
}
}
class ListItemModel: ObservableObject {
@Published var switchedOnOff: Bool = false
}
struct ContentView: View {
@State private var onOff = false
@State private var test = false
@State private var list = [
(id: 0, model: ListItemModel()),
(id: 1, model: ListItemModel()),
(id: 2, model: ListItemModel()),
(id: 3, model: ListItemModel()),
(id: 4, model: ListItemModel())
]
var body: some View {
NavigationView {
List {
HStack {
Text("Is 2nd item on or off? ")
Text(onOff ? "On" : "Off")
// Text(item[2].onOff ? "On" : "Off")
}
ForEach(self.list, id: \.id) {item in
ListItemView(model: item.model)
}
}
.navigationBarTitle(Text("List"))
}.onReceive(self.list[1].model.$switchedOnOff, perform: { switchedOnOff_second_item in
self.onOff = switchedOnOff_second_item
})
}
}
The @Published
basically creates a Publisher
, which the UI can listen to per onReceive()
.
Play around with this and you will figure out what these things do!
Good luck :)
Upvotes: 1