Home > OS >  How to create editable details view in SwiftUI
How to create editable details view in SwiftUI

Time:08-03

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.

  • Related