0

I am doing my first Swift UI project. I am having a form backed by a view-model (vm: SectionFormViewModel). I found a neat solution to limit inputs to numbers in this SO answer.

struct SectionForm: View {

    // @ObservedObject var homeVM: HomeViewModel

    @StateObject var vm = SectionFormViewModel()

    var body: some View {
        // ....
    }

    var roomVolume: some View {
        Section(header: Text("Room Dimensions")) {
            if vm.manualArea {
                HStack {

                    // Required to extract to component
                    // --------------------------------

                    TextField("Length (feet)", text: $vm.length)
                        //.keyboardType(.numberPad)
                        .onReceive(Just(vm.length)) { newValue in
                            let filtered = newValue.filter { "0123456789".contains($0) }
                            if filtered != newValue {
                                vm.length = filtered
                            }
                        }

My idea was to create my own NumberField. It would be called like this:

NumberField(label: "Length (feet)", binding: $vm.length)

But I can't figure out exactly how.

struct NumberField: View {
    @Binding var binding: Binding<String>
    
    var body: some View {
        TextField("Length (feet)", text: binding)
            //.keyboardType(.numberPad)
            .onReceive(Just($binding.wrappedValue)) { newValue in
                let filtered = newValue.filter { "0123456789".contains($0) }
                if filtered != newValue {
                    $binding.length = filtered
                }
            }
    }
}

First of all, is it possible to do something like that?

I don't think it can be @State because it is defined elsewhere. I think it should be a @Binding. It might be an obvious thing, but after many searches, hours of teeth grinding, nail biting and hairline receding, I am confident I need some help.

Sorry about the title, I am not even sure how to word it. I am that new to Swift!

Ziyan Junaideen
  • 3,270
  • 7
  • 46
  • 71

1 Answers1

1

The problem is, you have created binding of binding. which is wrong. see your code. Two bindings are there.

 @Binding var binding: Binding<String>

Your building should be like this.

struct NumberField: View {
    var label: String
    @Binding var binding: String
    
    var body: some View {
        TextField("Length (feet)", text: $binding)
            //.keyboardType(.numberPad)
            .onReceive(Just(binding)) { newValue in
                let filtered = newValue.filter { "0123456789".contains($0) }
                if filtered != newValue {
                    binding = filtered
                }
            }
    }
}

Now you can use it like this

NumberField(label: "Length (feet)", binding: $vm.length)
Raja Kishan
  • 16,767
  • 2
  • 26
  • 52