I have list of items stored in a View Model
struct ItemType: Identifiable {
let id: String = UUID().uuidString
let name: String
let weight: Double
}
class ListViewModel: ObservableObject {
@Published var items: [ItemType] // ItemType is Identifiable
}
This View Model is being used in my main view and all the items are presented as the list items in NavigationView
@StateObject var vm: ListViewModel()
var body: some View {
List {
ForEach(vm.items) { item in
NavigationLink("Item title") {
ItemDetailView(item: item)
}
}
}
Clicking on list item takes user into Item Detail View which presents the details of the item.
struct ContentView: View {
let item: ItemType
var body: some View {
NavigationView {
VStack {
// View details
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
NavigationLink(destination: EditItemView())
}
}
}
}
}
I would like to give option to the user to edit any of the ItemType fields in EditItemView having state of each item up to date. How can I achieve it?
I will appreciate any help! Thanks in advance
CodePudding user response:
you could try this approach (in addition to the comments):
ForEach($vm.items) { $item in // <-- here $
NavigationLink("Item title") {
ItemDetailView(item: $item) // <-- here $
}
}
and declare a @Binding var item: ItemType
in you ItemDetailView
An alternative is this approach:
ForEach(vm.items.indices, id: \.self) { index in // <-- here
NavigationLink("Item title") {
ItemDetailView(item: $vm.items[index]) // <-- here
}
}
EDIT-1: here is a complete example code to edit your item in ItemDetailView
import Foundation
import SwiftUI
struct ContentView: View {
@StateObject var vm = ListViewModel() // <-- here
var body: some View {
NavigationView {
List {
ForEach($vm.items) { $item in // <-- here $
NavigationLink(item.name) { // <-- the change will be displayed here
ItemDetailView(item: $item) // <-- here $
}
}
}
}
}
}
struct ItemDetailView: View {
@Binding var item: ItemType // <-- here
var body: some View {
TextField("name", text: $item.name) // <-- here edit the item
.border(.red)
.padding(.bottom)
}
}
struct ItemType: Identifiable {
let id: String = UUID().uuidString
var name: String // <-- here
var weight: Double // <-- here
}
class ListViewModel: ObservableObject {
// -- here for testing
@Published var items: [ItemType] = [ItemType(name: "Mickey Mouse", weight: 12.3)]
}
Alternatively, you can also do this, to edit for example, the name
of the item:
struct ContentView: View {
@StateObject var vm = ListViewModel() // <-- here
var body: some View {
List {
ForEach($vm.items) { $item in
VStack {
Text(item.name) // <-- here display the name
TextField("name", text: $item.name) // <-- here edit the name
.textFieldStyle(.roundedBorder).border(.green)
}
}
}
}
}
CodePudding user response:
In SwiftUI we don't use view model objects you have to learn the View
data struct and State/Binding property wrappers that make it the same as a view model object. Eg
@State var items: [Item] = []
var body: some View {
List {
ForEach($items) { $item in
NavigationLink("Item title") {
ItemDetailView(item: $item)
}
}
}
In ItemDetailView
we can use let item
if we only need read access, body is still called when item changes. @Binding var
for write access.