Search code examples
androidandroid-edittextandroid-databindingandroid-livedata

How to databind edittext attribute android:enabled with viewmodel data?


Requirement:
I have a usename and a password edittexts. I want password edittext to be enabled only when a valid username is entered in username edittext.

Layout code:

<variable
    name="model"
    type="com.app.viewmodel.ViewModel" />

...

<com.google.android.material.textfield.TextInputLayout
    ...>

    <androidx.appcompat.widget.AppCompatEditText
        android:id="@+id/username_edit_text"
        android:inputType="text"
        android:onTextChanged="@{model::onUsernameTextChanged}"
        .../>

</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
    ...>

    <androidx.appcompat.widget.AppCompatEditText
        android:id="@+id/password_edit_text"
        android:enabled="@{safeUnbox(model.isUsernameValid)}"
        android:inputType="textPassword"
        android:onTextChanged="@{model::onPasswordTextChanged}"
        .../>

</com.google.android.material.textfield.TextInputLayout>

Viewmodel:

private val isUsernameValid: MutableLiveData<Boolean> = MutableLiveData()

init {
    isUsernameValid.value = false
}

fun getIsUsernameValid(): MutableLiveData<Boolean> {
    return isUsernameValid
}

fun onUsernameTextChanged(usernameString: CharSequence, start: Int, before: Int, count: Int) {
    isUsernameValid.value = (usernameString.length >= 8)

    Log.e(TAG, "${isUsernameValid.value}")
}    

In the log message, I could see that the isUsernameValid is changed to true after entering valid username, but the password edittext is not enabling after that.

Any possible way to solve this?

Edit 1: After reading @Birju Vachhani 's solution.

Fragment code:

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    if (activity != null) {
        signInViewModel = ViewModelProviders.of(this).get(SignInViewModel::class.java)
        signInFragmentBinding.sharedModel = mainActivityViewModel
        signInFragmentBinding.lifecycleOwner = this
        signInFragmentBinding.model = signInViewModel
    }
}

signInFragmentBinding.lifecycleOwner = this Adding this line solved it.


Solution

  • In your activity, do this and it will work:

    binding.lifecycleOwner = this
    

    In order to make binding act on LiveData changes, LifecyclerOwner needs to be provided.

    class MainActivity : AppCompatActivity() {
    
        ...
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
            binding.lifecycleOwner = this
            binding.viewModel = viewModel
        }
    }