creating a list from an array of structs

I'm trying to populate an array of structs from textfield entries but when i add an entry it replaces all other entries with the last one.

import SwiftUI

struct Drug: Hashable, Codable, Identifiable {
 var id = UUID()
 var name: String
 var amount: String
 var bag: String
  
 var isRead: Bool = false
}

extension Drug {
 static let samples = [
  Drug(name: "", amount: "", bag: ""),
]
}



 class BooksViewModel: ObservableObject {
 @Published var drugs: [Drug] = Drug.samples
 @Published var favs : [Drug] = []
   
}

struct BooksListView: View {
  @StateObject var viewModel = BooksViewModel()
  @State var newdrug : Drug = Drug(name: "", amount: "", bag: "")
   
  var body: some View {
    VStack{
      List {
        TextField ("Droga", text: $newdrug.name)
        TextField ("Cantidad", text: $newdrug.amount)
        TextField ("Volumen", text: $newdrug.bag)
      }
       
      List (viewModel.favs) { drug in
        Text ("\(drug.name) \(drug.amount) in \(drug.bag)")
      }
       
      Button ("Add") {
        viewModel.favs.insert(newdrug, at: 0)
        print(viewModel.favs)
      }

       
    }
  }
   
   
   
  struct BooksListView_Previews: PreviewProvider {
    static var previews: some View {
      BooksListView()
    }
  }
}

Accepted Reply

The problem is your view's newdrug value always has the same UUID. It gets allocated one time when the view is instantiated. You then add the item with that UUID to the list several times.

In your add button, replace this:

viewModel.favs.insert(newdrug, at: 0)

with this:

viewModel.favs.insert(Drug(name: newdrug.name, amount: newdrug.amount, bag: newdrug.bag), at: 0)

That will cause a whole new Drug object to be created and inserted. It gets a new UUID when it's created, so it won't match the ID of any of the other objects in the array. SwiftUI will then be able to recognize it's a different object.

Replies

The problem is your view's newdrug value always has the same UUID. It gets allocated one time when the view is instantiated. You then add the item with that UUID to the list several times.

In your add button, replace this:

viewModel.favs.insert(newdrug, at: 0)

with this:

viewModel.favs.insert(Drug(name: newdrug.name, amount: newdrug.amount, bag: newdrug.bag), at: 0)

That will cause a whole new Drug object to be created and inserted. It gets a new UUID when it's created, so it won't match the ID of any of the other objects in the array. SwiftUI will then be able to recognize it's a different object.

Thanks a lot Zimmie!!!!!

  • Absolutely! There are a lot of other ways to do this, too. You can store the name, amount, and bag values as separate state variables, then only instantiate a Drug object when you're ready to add it to the array. You could have a detail view to edit objects, and make the Add button add a new, blank Drug which you then edit to your desired values.

    All of these have tradeoffs. I recommend trying several styles to see which works best for you.

Add a Comment