Binding in a Foreach in Swiftui

@Binding and ForEach in SwiftUI

You can use something like the code below. Note that you will get a deprecated warning, but to address that, check this other answer: https://stackoverflow.com/a/57333200/7786555

import SwiftUI

struct ContentView: View {
@State private var boolArr = [false, false, true, true, false]

var body: some View {
List {
ForEach(boolArr.indices) { idx in
Toggle(isOn: self.$boolArr[idx]) {
Text("boolVar = \(self.boolArr[idx] ? "ON":"OFF")")
}
}
}
}
}

Binding in a ForEach in SwiftUI

Assuming your elements is state of items array, it can be

List {
ForEach(elements.indices, id: \.self) { i in
CheckBoxView(checked: $elements[i].checked)
}
}

Binding in SwiftUI ForEach from Parent to Child

You missed the $ before subtask.

If you don't write $subtask, then subtask is now a Binding<Subtask>. This would mean you can still do subtask.wrappedValue to use subtask normally and subtask to use the binding, but that's not as neat. With the $, $subtask is a Binding<Subtask> and subtask is a Subtask.

Change:

ForEach($model.subtasks) { subtask in
ChildView(subtask: $subtask)
}

To:

ForEach($model.subtasks) { $subtask in
ChildView(subtask: $subtask)
}

Or alternatively (and more confusingly, I don't recommend):

ForEach($model.subtasks) { subtask in
ChildView(subtask: subtask)
}

Using ForEach with a an array of Bindings (SwiftUI)

Trying a different approach. The FormField maintains it's own internal state and publishes (via completion) when its text is committed:

struct FormField : View {
@State private var output: String = ""
let viewModel: FormFieldViewModel
var didUpdateText: (String) -> ()

var body: some View {
VStack {
TextField($output, placeholder: Text(viewModel.placeholder), onCommit: {
self.didUpdateText(self.output)
})

Line(color: Color.lightGray)
}.padding()
}
}
ForEach(viewModel.viewModels) { vm in
FormField(viewModel: vm) { (output) in
vm.output = output
}
}

SwiftUI: How to filter Binding value in ForEach?

I think the issue is not the filtering per se, but the .lowercased() that the ForEach is rejecting. Rather than try to force that, there is a simpler way. Use a computed variable that does the filtering, and then roll your own Binding to send to the view like this:

struct ContentView: View {
@State var testArray = [
Test(number: 1, text: "1"),
Test(number: 2, text: "2"),
Test(number: 3, text: "3"),
Test(number: 4, text: "4"),
Test(number: 5, text: "5"),
Test(number: 6, text: "6")
]

@State private var searchText = ""
@State private var placeholder = "Search..."

var filteredTest: [Test] {
// If you want to return no items when there is no matching filter use this:
testArray.filter { ($0.text.lowercased().contains(searchText.lowercased()))}

// If you want the whole array unless the filter matches use this:
let returnTestArray = testArray.filter { ($0.text.lowercased().contains(searchText.lowercased()))}
guard !returnTestArray.isEmpty else { return testArray }
return returnTestArray
}

var body: some View {
NavigationView{
VStack{
SearchBar(text: $searchText, placeholder: $placeholder)
List {
ForEach(filteredTest) { test in
TestView10(test: Binding<Test> (
get: { test },
set: { newValue in
if let index = testArray.firstIndex(where: { $0.id == newValue.id } ) {
testArray[index] = newValue
}
}
))
}
}
}
}
}
}

I also renamed your array of data testArray to better reflect what it was, and in the ForEach, data now becomes test.

SwiftUI Bind to core data object inside foreach

I love CoreData with SwiftUI. It works just so simple. Just create a new edit view with ObservedObject of Book.

struct EditView : View {
@ObservedObject var book: Book

init(book: Book) {
self.book = book
}

var body : some View {
TextField("Name", text: $book.bookName)
}
}

And that's it. Then you can send $book.bookName as Binding to the String.

However, make sure! you have declared bookName as non-optional value in CoreData. TextField requires a Binding<String>, NOT a Binding<String?>

Use that EditView inside your ForEach and you are ready to go:

ForEach(books) { book in
EditView(book: book)

SwiftUI - using ForEach with a Binding array that does not conform to identifiable / hashable


Option 1:

Give your IncidentResponse an ID and then tell it to not try to decode the value:

struct IncidentResponse: Codable, Identifiable {
var id = UUID()
let incident: IncidentDetails?

enum CodingKeys: String, CodingKey {
case incident
}
}

Option 2:

Make incident and id non-optional and then use this to get the id:

ForEach(existingIncidents, id: \.incident.id) { incident in

I'll also note that IncidentResponse seems to be a somewhat meaningless wrapper at this point. When you do your decoding and store the values to existingIncidents (which you haven't shown), you could probably store them just as [IncidentDetails] instead. In that case, you just have to make the id property non-optional on IncidentDetails and declare it as Identifiable. For example:

struct IncidentDetails: Codable, Identifiable {
let id: String
let reason: IncidentReasonResponse?
let message: String?
let startedAt: String?
let endedAt: String?
}

//....

let existingIncidentsWrappers : [IncidentResponse] = //...
let existingIncidents : [IncidentDetails] = existingIncidentsWrappers.compactMap { $0.incident }

SwiftUI ForEach with array or sub-array

You don’t have to use $ sign in front of your arrays.

ForEach(isExpanded ? items[..<items.count] : items[..<4], id: \.self) { sub in

}

dynamic binding in SwiftUI ForEach for a field

Here is possible variant

ForEach(Array(inputFields.enumerated()), id: \.1) { index, inputStruct in
TextField(inputStruct.placeholder, text: self.$inputFields[index].storage)
}


Related Topics



Leave a reply



Submit