manishkkatoch / SimpleTwoWayBindingIOS

An ultra light, ultra simple two way binding library for IOS and Swift.
MIT License
165 stars 48 forks source link

Initial Model value not shown on UIControls #1

Closed AnnieNinaJoyceV closed 6 years ago

AnnieNinaJoyceV commented 6 years ago

Hello! Thank you for creating this library and explaining TwoWayBinding. I found something is missing, or I must be doing something wrong. What I am expecting it to do? When a model's parameter and a UIControl is bound, I expect the UIControl to display the initial value of the bound parameter when the control is loaded. Later, when the control updates its text, the changes should be reflected in the bound model's parameter. What is missing? The second part, model's parameter is being updated based on control's input is working effortlessly. But, the first part is not working or I must be missing something. What I tried? In the example code, when I update FormViewModel to modify the name parameter to hold the value 'John Doe', let name: Observable<String> = Observable("John Doe") I expect the nameField of ViewController to load with text 'John Doe'. This update doesn't happen unless I update to function bind in Observable to this,

public func bind(observer: @escaping Observer) { self.observers.append(observer) if let value = value { notifyObservers(value) } }

That is when the binding is happening let the observer take the current value if it has any.

I would like to know what I am missing here. Thanks in advance 👍

manishkkatoch commented 6 years ago

@AnnieNinaJoyceV sorry for a super delayed response. I was away on a vacation. In my opinion, I would set up my data, separate from my setup of bindings. The ViewModel, in this case, is not a traditional view model. Its primary focus is to provide bindings and observables which can change at later stages. Hence in the example, I was visualizing it as:

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.navigationItem.title = "Survey Form"
        setupBindings()
        viewModel.companyName.value = "Something"
    }

However, I do see reason in your requirement. If you have an implementation please raise a pull request, else I will have this implemented in a day's time.

AnnieNinaJoyceV commented 6 years ago

Uhm no! As said in my first post, tweaking the bind function has it fixed. I will wait for your implementation. Since, I am not very sure whether the tweaking is proper. Hope you had a nice vacation!! 👍

manishkkatoch commented 6 years ago

I can see one caveat in your solution: whenever a control binds to an observable, it will notify all observers it's value even though it is not changed. These are unnecessary invocations which we can avoid if we modify Bindable as:

public func bind(with observable: Observable<BindingType>) {
        if let _self = self as? UIControl {
            _self.addTarget(Selector, action: Selector{ self.valueChanged() }, for: [.editingChanged, .valueChanged])
        }
        self.binder = observable
        //addition here.
        if let val = observable.value {
            self.updateValue(with: val)
        }
        //addition end.
        self.observe(for: observable) { (value) in
            self.updateValue(with: value)
        }
    }

this will ensure that the Bindable control which is asking to bind with Observable updates if the observable already had a set value.

AnnieNinaJoyceV commented 6 years ago

Great!! 👍

manishkkatoch commented 6 years ago

Implemented in dd32e58 This is now available as release version 0.0.2.