---
title: "Modern Android Form Validations With Data Binding"
description: "How to validate form fields without if or when expressions"
canonical: https://oozou.com/blog/modern-android-form-validations-with-data-binding-147
locale: en
date: 2020-12-21
author: "OOZOU Team"
---

# Modern Android Form Validations With Data Binding

> How to validate form fields without if or when expressions

Published: 2020-12-21 · Author: OOZOU Team (Engineering) · 3 min read

# 
Introduction

One of the many things you need to know how to do as an android developer is creating forms. With that comes the responsibility of client side validation. There are various approaches used to do this but I'd like to share my personal favourite with you all.

# Let's Get Into It

First we will be creating a validator class that will handle validation of liveData

```kotlin
//A predicate is a function that evaluates to true when its param matches the condition of the predicate
typealias Predicate = (value: String?) -> Boolean

class LiveDataValidator(private val liveData: LiveData<String>) {
    private val validationRules = <em>mutableListOf</em><Predicate>()
    private val errorMessages = <em>mutableListOf</em><String>()

     var error = MutableLiveData<String?>()

    <strong>//For checking if the liveData value matches the error condition set in the validation rule predicate
    //The livedata value is said to be valid when its value doesn't match an error condition set in the predicate</strong>
    fun isValid(): Boolean {
        for (i in 0 <em>until </em>validationRules.size) {
            if (validationRules[i](liveData.<em>value</em>)) {
                emitErrorMessage(errorMessages[i])
                return false
            }
        }

        emitErrorMessage(null)
        return true
    }

    <strong>//For emitting error messages</strong>
    private fun emitErrorMessage(messageRes: String?) {
        error.<em>value </em>= messageRes
    }

    <strong>//For adding validation rules</strong>
    fun addRule(errorMsg: String, predicate: Predicate) {
        validationRules.add(predicate)
        errorMessages.add(errorMsg)
    }
}
```

Then, we will create a ValidatorResolver which will help us aggregate multiple liveData validators. This will be useful when we want to check if all liveData attached to our form are in a valid state.

```kotlin
class LiveDataValidatorResolver(private val validators: List<LiveDataValidator>) {
    fun isValid(): Boolean {
        for (validator in validators) {
            if (!validator.isValid()) return false
        }
        return true
    }
}
```

Next, we will create the validation rules in our viewModel

```kotlin
class ExampleViewModel : ViewModel() {
   val usernameLiveData = MutableLiveData<String>()
   val usernameValidator = LiveDataValidator(usernameLiveData).<em>apply </em><strong>{
      //Whenever the condition of the predicate is true, the error message should be emitted
      </strong>addRule("username is required") <strong>{ it</strong>.<em>isNullOrBlank</em>() <strong>}
   }
   </strong>val passwordLiveData = MutableLiveData<String>()
   val passwordValidator = LiveDataValidator(passwordLiveData).<em>apply </em><strong>{
      //We can add multiple rules. 
      //However the order in which they are added matters because the rules are checked one after the other
      </strong>addRule("password is required") <strong>{ it</strong>.<em>isNullOrBlank</em>() <strong>}
      </strong>addRule("password length must be 10") <strong>{ it?.length != 10</strong> <strong>}
   }

   //We will use a mediator so we can update the error state of our form fields
   //and the enabled state of our login button as the form data changes
   </strong>val isLoginFormValidMediator = MediatorLiveData<Boolean>()

   init {
       isLoginFormValidMediator.<em>value </em>= false
       isLoginFormValidMediator.addSource(usernameLiveData) <strong>{ </strong>validateForm() <strong>}
       </strong>isLoginFormValidMediator.addSource(passwordLiveData) <strong>{ </strong>validateForm() <strong>}</strong>
   }

   //This is called whenever the usernameLiveData and passwordLiveData changes
   fun validateForm() {
       val validators = <em>listOf</em>(usernameValidator, passwordValidator)
       val validatorResolver = LiveDataValidatorResolver(validators)
       isLoginFormValidMediator.<em>value </em>= validatorResolver.isValid()
   }
}
```

Finally, we will be creating a simple login form containing two fields - username, password - and a button to complete the login process. The XML below assumes you're familiar with data binding.

```
<androidx.constraintlayout.widget.ConstraintLayout
<com.google.android.material.textfield.TextInputLayout
    android:id="@+id/field_username"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:errorEnabled="true"
    <strong>app:error="@{viewModel.usernameValidator.error}"</strong>
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <com.google.android.material.textfield.TextInputEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        <strong>android:text="@={viewModel.usernameLiveData}"</strong> />

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

<com.google.android.material.textfield.TextInputLayout
    android:id="@+id/field_password"
    style="@style/TextInputLayoutTheme"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:errorEnabled="true"
    <strong>app:error="@{viewModel.passwordValidator.error}"</strong>
    app:layout_constraintEnd_toEndOf="parent"
   app:layout_constraintStart_toStartOf="parent"
   app:layout_constraintTop_toBottomOf="@+id/field_username">

    <com.google.android.material.textfield.TextInputEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        <strong>android:text="@={viewModel.passwordLiveData}"</strong> />

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

<com.google.android.material.button.MaterialButton
    android:id="@+id/button_log_in"
    android:layout_width="match_parent"
    android:layout_height="60dp"
     android:layout_marginTop="100dp"
    <strong>android:enabled="@{viewModel.isLoginFormValidMediator}"</strong>
    android:text="Log in"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/field_password"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<br>
```

# Conclusion

I prefer this method because it helps me avoid writing long if or when expressions whenever I have a huge form with plenty of validation rules. If you like flexing your creative muscles, you can give it a try in your next project and consider joining our team at Oozou.

---

Contact OOZOU: hello@oozou.com · +66 2544 0000 · https://oozou.com/contact

More for AI agents: https://oozou.com/llms.txt · every page has a markdown twin at its URL plus ".md"
