I have some accounts that I want to get a user to input a number to provide an initial balance.
Not sure how to do the binding. Here's my model:
class DefaultBalancesViewModel: ObservableObject {
@Published var accountBalances: [Account: String] = [:]
@Published var accounts: [Account] = []
private let dbCore: DBCore
init(dbCore: DBCore = DBCore.shared) {
self.dbCore = dbCore
self.accounts = dbCore.accounts
self.accountBalances = dbCore.accounts.reduce(into: [Account: String]()) { $0[$1] = "" }
}
}
and my basic SwiftUI:
struct DefaultBalancesView: View {
@StateObject var viewModel = DefaultBalancesViewModel()
var body: some View {
ForEach(viewModel.accounts) { account in
HStack {
Text(account.name)
Spacer()
TextField("", text: $viewModel.accountBalances[account]) // <-- error here: Cannot convert value of type 'Binding<[Account : String]>.SubSequence' (aka 'Slice<Binding<Dictionary<Account, String>>>') to expected argument type 'Binding<String>' (and a couple of other errors)
}
}
Button("Save") {
//
}
}
}
How should I structure this so I can dynamically enter a number for each account?
CodePudding user response:
At the moment you have multiple copies of Account
arrays, and a dictionary with String! There should be only one source of truth, eg @Published var accounts: [Account]
, and the Account
should be able to hold (or calculate) its balance.
Try this approach (works well for me), where you have only one array of [Account]
(one source of truth), that you can edit
using a TextField
:
Customise the code to suit your needs, e.g the currency
,
or simply a "normal" decimal formatter.
class DefaultBalancesViewModel: ObservableObject {
// for testing
@Published var accounts: [Account] = [Account(name: "account-1", balance: 1.1),
Account(name: "account-2", balance: 2.2),
Account(name: "account-3", balance: 3.3)]
private let dbCore: DBCore
init(dbCore: DBCore = DBCore.shared) {
self.dbCore = dbCore
self.accounts = dbCore.accounts
}
}
struct DefaultBalancesView: View {
@StateObject var viewModel = DefaultBalancesViewModel()
var body: some View {
ForEach($viewModel.accounts) { $account in // <-- here
HStack {
Text(account.name).foregroundColor(.red)
Spacer()
TextField("", value: $account.balance, format: .currency(code: "USD")) // <-- here
.textFieldStyle(RoundedBorderTextFieldStyle())
}
}
Button("Save") {
// for testing
viewModel.accounts.forEach { print("--> name: \($0.name) balance: \($0.balance)")}
}
}
}
// for testing
struct Account: Identifiable {
let id = UUID()
var name: String
var balance: Double // <-- here
}