yambo
yambo

Reputation: 1817

Combine multiple LiveData values into one using MediatorLiveData

I have an email, password, and phone number, that are all live data values updated in real time by a fragment as the user types.

How can I have a live data variable that observes all three of those variables, and returns something based on all of their combined results?

ViewModel

class AuthenticationViewModel: ViewModel() {
    var email: MutableLiveData<String> = MutableLiveData("")
    var password: MutableLiveData<String> = MutableLiveData("")
    var phoneNumber: MutableLiveData<Int> = MutableLiveData(0)

    val isFormValid: MediatorLiveData<Boolean> = {
        // if email is valid
        // and if password is valid
        // and if phoneNumber is valid
        // return true
        // How do I do this?
    }
}

Fragment

binding.emailInput.addTextChangedListener { email ->
    viewModel.email.value = email.toString()
}

viewModel.isFormValid.observe(this, {
    // do what I want in real time
})

Upvotes: 2

Views: 3936

Answers (1)

Luciano Ferruzzi
Luciano Ferruzzi

Reputation: 1102

Try adding each liveData as a source like this and check the other liveData's value when one of them trigger a change: ViewModel

class AuthenticationViewModel: ViewModel() {
    val email: MutableLiveData<String> = MutableLiveData("")
    val password: MutableLiveData<String> = MutableLiveData("")
    val phoneNumber: MutableLiveData<Int> = MutableLiveData(0)

    val isFormValid: MediatorLiveData<Boolean> = MediatorLiveData().apply {
        addSource(email) { emailValue -> isValidEmail(emailValue) && isValidPassword(password.value) && isValidPhoneNumber(phoneNumber.value) }
        addSource(password) { passwordValue -> isValidEmail(email.value) && isValidPassword(passwordValue) && isValidPhoneNumber(phoneNumber.value) }
        addSource(phoneNumber) { phoneNumberValue -> isValidEmail(email.value) && isValidPassword(password.value) && isValidPhoneNumber(phoneNumberValue) }
    
    }
}

And then just observe the livedata as usual:

Fragment

binding.emailInput.addTextChangedListener { email ->
    viewModel.email.value = email.toString()
}

viewModel.isFormValid.observe(this, {
    // do what I want in real time
})

solution inspired by https://medium.com/codex/how-to-use-mediatorlivedata-with-multiple-livedata-types-a40e1a59e8cf , kinda the same but not using Triple and a new class for it, also you can add as many as you want.

Upvotes: 3

Related Questions