5

I would like to enable a AppCompatButton when all fields in a form are complete.

I am using a ViewModel and would like to use Databinding to enable this.

I have 2 methods that fire when text is changed on the views to update an objects data in the viewmodel.

The issue I am running into is when both fields are complete, I need to enable a button on the layout allowing them to proceed.

An example would be log in, when the username and password fields are fulled in, the log in button becomes enabled.

Stillie
  • 2,647
  • 6
  • 28
  • 50
  • check this answer https://stackoverflow.com/a/54361844/7666442 you will get hint how to `Enable a button when all EditText complete` – AskNilesh Jan 30 '19 at 09:40
  • As i said i wanted to use databinding, i know you can do this through the Fragment/Activity but i want to do this using Databinding – Stillie Jan 30 '19 at 09:42
  • you can also use`onTextChanged` in databinding check here https://stackoverflow.com/a/33841796/7666442 – AskNilesh Jan 30 '19 at 09:44
  • i've seen that one, but how am i going to have access to the button, when the onTextChanged is on the username field? – Stillie Jan 30 '19 at 09:45

2 Answers2

9

You can use the same solution like here

But if you want use only AndroidArch and DataBinding you can create your own approach like below:

class MyVM : ViewModel() {
    ...
    val mLoginLiveData = MutableLiveData<String>()
    val mPasswordLiveData = MutableLiveData<String>()
    val mLoginPasswordMediator = MediatorLiveData<Boolean>()
    ...
    init {
      mLoginPasswordMediator.addSource(mLoginLiveData) { validateForm() }
      mLoginPasswordMediator.addSource(mPasswordLiveData) { validateForm() }
      ...
    }

    private fun validateForm() {
        // put your validation logic here, and update the following value
        // as `true` or `false` based on validation result
        // mLoginPasswordMediator.value = ...
    }

    override fun onCleared() {
        // DO NOT forget to remove sources from mediator
        mLoginPasswordMediator.removeSource(mLoginLiveData)
        mLoginPasswordMediator.removeSource(mPasswordLiveData)
    }
}

and in your activity class listen your MediatorLiveData:

class MyActivity : AppCompatActivity() {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
      //Obtain your ViewModel class here
      //Initialize binding here
      ...
      mBinding.lifecycleOwner = this
      mVM.mLoginPasswordMediator.observe(this, Observer { validationResult ->
          mBinding.yourButton.isEnabled = validationResult
      })
    }
}

And didn't forget to use your LiveDatas' in 'your_activity_layout'.xml:

...
//Add your ViewModel class to layout here
<EditText
  ...
  android:text="@={vm.mLoginLiveData}"
  ... />
...
<EditText
  ...
  android:text="@={vm.mPasswordLiveData}"
  ... />
...
Mirjalal
  • 1,292
  • 1
  • 17
  • 40
aLT
  • 326
  • 3
  • 9
  • This is the type of reply i wanted. Please see https://pastebin.com/Q6y7p1ZL Where i am observing the data, it doesnt seem to be hitting that break point and i cant figure out why. I have added android:text="@{viewModel.passwordMutableLiveData}" to each of the views and its still not working :( – Stillie Jan 30 '19 at 11:08
  • @x10sion make sure that you've added in your UI-layer (activity or fragment...) the line mViewModel.setLifecycleOwner(this). Cause it seems that you have forgotten to add it (if nothing happened else of course). Check it out, please. – aLT Jan 30 '19 at 12:35
  • I have added that, but still no change, i dont understand why the observer is not being fired when i make text changes in the TextInputEditText's (I have also tried just EditText's) – Stillie Jan 30 '19 at 13:01
  • @x10sion did you add mBinding.setVariable(mVM)? Also check out your Android Studio version cause LiveData databinding is available since 3.2 Canary 9 – aLT Jan 31 '19 at 01:58
  • thank you, this was the best solution and the exact answer i was looking for – Stillie Feb 05 '19 at 11:19
  • observer not being fired here – LMaker May 24 '19 at 14:54
  • @LMaker, oh, should add mLoginPasswordMediator.value = mLoginLiveData.value I guess – aLT May 25 '19 at 16:06
  • I dont get it. Because `mLoginPasswordMediator` is expecting a `Boolean` and `mLoginLiveData` has a `String` on it – LMaker May 25 '19 at 16:12
  • @LMaker, okay, yep, there are few additional statements need to be added for checking values in both LiveData and push the result to Mediator. But the main logic here is right – aLT May 25 '19 at 17:34
  • 1
    A day lost trying to figure out what wrong with my code and my problem was only the "=" after "@". That was the reason I didn't get any updates in the mediator observer. – Jorge Casariego Apr 25 '20 at 13:35
0

To do this you would have to add onEditorActionListener to your editText which you would enable the button lets say for example i have an edit text named password which i want to enable a login button when it is not empty and when the text entered i it is not less than 8 i would validate and enable the button like this:

password.setOnEditorActionListener(new TextView.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
        if (password.getText().length() > 0  && password.getText.lenght !< 8) {
            //Automatically click button to login
            loginBtn.setEnabled(true);
            return true;
        }
        return false;
    }
});

You can also use a TextWatcher or an addTextChangedListener on the EditText see here for fore details: https://freakycoder.com/android-notes-66-how-to-use-textwatcher-for-more-than-one-edittext-e190b7ae1070

https://www.dev2qa.com/android-enable-disable-button-by-edittext-text-length/

Asendo
  • 158
  • 1
  • 10