UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Change in View does not update object/model

Forums > SwiftUI

Hi,

I have a problem where a change in the View is not updating the underlying object in the model. Idea here is to generate a dynamic list of attributes of all different types (string, date, bool) and in the GUI all looks fine but when hitting the Save button, I can see that the data is not updated. What am I missing here?

Full working demo project below:

//
//  ContentView.swift
//  AttributeDemo
//
//  Created by Max on 28.05.22.
//

import SwiftUI

public enum AttributeType: Codable, CaseIterable{
    case int
    case string
    case datetime
    case decimal
    case double
    case boolean

    var stringValue: String {
        switch self {
            case .int: return "Full numbers"
            case .string: return "Text"
        case .datetime: return "Date"
        case .decimal: return "Decimal"
        case .double: return "Double"
        case .boolean: return "Yes/No"
        }
    }
}

public class Attribute: Identifiable, Codable, ObservableObject {
    public var id: UUID = UUID()
    public var bkey: String = ""
    public var tmp_create: Date = Date()
    public var itemBkey: String = ""
    public var attrType: AttributeType = .string
    public var name: String = ""
    public var description: String = ""
    public var value_int: Int = 0
    public var value_string: String = ""
    public var value_datetime: Date = Date()
    public var value_decimal: Decimal = 0.0
    public var value_double: Double = 0.0
    public var value_boolean: Bool = false
    var userBkey: String = ""
    var userToken: String = ""
}

struct ContentView: View {
    @State private var attributes: [Attribute] = []
    @State private var showingAttributeTypes = false

    var body: some View {
        VStack{
            Button("Add attribute"){
                self.showingAttributeTypes.toggle()
            }
            .confirmationDialog("Select a color", isPresented: $showingAttributeTypes, titleVisibility: .visible) {
                            Button("Text") {
                                addAttribute(attributeType: .string)
                            }
                Button("Number") {
                    addAttribute(attributeType: .decimal)
                }
                Button("Date") {
                    addAttribute(attributeType: .datetime)
                }
                Button("Yes/No") {
                    addAttribute(attributeType: .boolean)
                }
                        }

            ForEach(self.attributes){value in
                AttributeView(attribute: value)
            }

            Button("Save"){
                self.attributes.forEach{value in
                    print(value.attrType.stringValue)
                    print(value.value_string)
                    print(value.value_datetime)
                    print(value.value_boolean)
                    print("--------------------------------")
                }
            }
        }
    }

    func addAttribute(attributeType: AttributeType){
        var attribute = Attribute()
        attribute.attrType = attributeType
        self.attributes.append(attribute)
    }
}

struct AttributeView: View {
    @ObservedObject var attribute: Attribute = Attribute()
    @State private var description: String = ""
    @State private var value_boolean: Bool = false
    @State private var value_string: String = ""
    @State private var value_decimal: Decimal = 0.0
    @State private var value_double: Double = 0.0
    @State private var value_datetime: Date = Date()

    var body: some View {
        HStack{
            FormField(fieldName: "Description", fieldValue: $description)
                .keyboardType(.default)
            Spacer()
            switch(attribute.attrType){
            case .boolean:
                Toggle(isOn: $value_boolean) {
                    Label("", image: "")
                }
            case .string:
                TextField("", text: $value_string)
                    .keyboardType(.default)
            case .datetime:
                DatePicker(selection: $value_datetime, displayedComponents: .date, label: { Text("") })
            case .decimal:
                TextField("", value: $value_decimal, format: .number)
                    .keyboardType(.decimalPad)
            case .double:
                TextField("", value: $value_double, format: .number)
                    .keyboardType(.decimalPad)
            default:
                EmptyView()
            }
        }
    }
}

struct FormField: View {
    var fieldName = ""
    @Binding var fieldValue: String

    var body: some View{
        TextField(fieldName, text: $fieldValue)

    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Max

2      

What are you expecting to see and what are you actually seeing? From what I can tell, your code is functioning as intended.

2      

Let's say I just add a single boolean attribute and set the toggle to On and hit Save, I get

Yes/No

2022-05-28 08:17:13 +0000
false
--------------------------------

in the console output. I would have expected to see

Yes/No

2022-05-28 08:17:13 +0000
true
--------------------------------

2      

I am an idiot ... in my AttributeView I am actually not updating the item ...

struct AttributeView: View {
    @ObservedObject var attribute: Attribute = Attribute()
    @State private var description: String = ""
    @State private var value_boolean: Bool = false
    @State private var value_string: String = ""
    @State private var value_decimal: Decimal = 0.0
    @State private var value_double: Double = 0.0
    @State private var value_datetime: Date = Date()

    var body: some View {
        HStack{
            FormField(fieldName: "Description", fieldValue: $description)
                .keyboardType(.default)
            Spacer()
            switch(attribute.attrType){
            case .boolean:
                Toggle(isOn: $value_boolean) {
                    Label("", image: "")
                }
            case .string:
                TextField("", text: $value_string)
                    .keyboardType(.default)
            case .datetime:
                DatePicker(selection: $value_datetime, displayedComponents: .date, label: { Text("") })
            case .decimal:
                TextField("", value: $value_decimal, format: .number)
                    .keyboardType(.decimalPad)
            case .double:
                TextField("", value: $value_double, format: .number)
                    .keyboardType(.decimalPad)
            default:
                EmptyView()
            }
        }
    }
}

needs to change to

struct AttributeView: View {
    @ObservedObject var attribute: Attribute = Attribute()

    var body: some View {
        HStack{
            FormField(fieldName: "Description", fieldValue: $description)
                .keyboardType(.default)
            Spacer()
            switch(attribute.attrType){
            case .boolean:
                Toggle(isOn: $attribute.value_boolean) {
                    Label("", image: "")
                }
            case .string:
                TextField("", text: $attribute.value_string)
                    .keyboardType(.default)
            case .datetime:
                DatePicker(selection: $attribute.value_datetime, displayedComponents: .date, label: { Text("") })
            case .decimal:
                TextField("", value: $attribute.value_decimal, format: .number)
                    .keyboardType(.decimalPad)
            case .double:
                TextField("", value: $attribute.value_double, format: .number)
                    .keyboardType(.decimalPad)
            default:
                EmptyView()
            }
        }
    }
}

and then it works of course ...

2      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.