Skip to Content
Validation

Validation

Client-side validation in your mobile app helps catch errors early on, right on the user’s device. This gives them immediate feedback and lets them fix mistakes without waiting for the app to communicate with a server. This improves the user experience by making it faster and smoother, and it also helps your app run more efficiently by reducing unnecessary communication with the server. However, don’t forget to also implement server-side validation for extra security!

Usage

Dependencies

Within your app module’s build.gradle.kts file, incorporate the following dependencies:

implementation(project(":core:validation"))

Example

Define your validation rules

Create a class that extends TextValidationRule and implements its methods to define your validation rules:

class MyCustomRule( override val errorMessage: (context: Context) -> String = { context -> // Default error message context.getString(R.string.error_message) } ): TextValidationRule { override val validationRule: (String) -> Boolean = { // Your validation logic // e.g.: input.length > 5 // Return true if the input is valid } }

There are also some predefined rules you can use:

  • RequiredRule: Checks if the input is not null or empty
  • EmailRule: Checks if the input is a valid email address
  • PasswordRule: Checks if the input is a valid password (at least 6 characters, 1 uppercase, 1 lowercase, 1 digit)

Create a validator

Create a TextValidator in your UIState class to validate your input:

data class MyUIState( // The input you want to validate (value is updated by UI events) val requiredInput: String? = null, // Option 1: Store validation Result as variable var requiredInputValidationResult: ValidationResult: ValidationResult? = null // Option 2: Store validation Result as State var requiredInputValidationResultAsState: MutableState<ValidationResult?> = mutableStateOf(null) ) { // This is a validator with the rules on which you want to validate val validator = TextValidator.withRules(MyCustomRule()) // Takes a vararg of rules so you can add as many as you want // This method will only work if you use the ValidationResult as State // For the other option you have to call the validate method on the validator and manually update the state fun validateRequiredInput(context: Context) { if(requiredInput == null) return // If the input is null, we don't want to validate it // Perform the validation and update the result // .value is used to update the MutableState requiredInputValidationResult.value = validator.validate(context, requiredInput) } }

Validating the input

You can now call the validateRequiredInput method in your composable to validate the input. This will update requiredInputValidationResultAsState with the validation result:

@Composable fun MyComposable(uiState: MyUIState) { val context = LocalContext.current LaunchedEffect(uiState.requiredInput) { uiState.validateRequiredInput(context) } }

Alternatively you can also validate the input in your ViewModel:

class MyViewModel { val _uiState = MutableStateFlow(MyUIState()) val uiState = _uiState.asStateFlow() fun onAction(action: MyAction) { when(action) { is MyAction.ValidateRequiredInput -> { _uiState.update { it.copy( requiredInputValidationResult = it.validator.validate(context, it.requiredInput) ) } } } } }

Display error messages

You can now display error messages based on the validation result:

MyTextField( error = uiState.requiredInputValidationResult.errorMessage() // Will be your error message if the validation fails )

Checking if inputs are valid

You can check if all inputs are valid by calling the isValid method on the TextValidator:

val areInputsValid by remember { derivedStateOf { uiState.requiredInputValidationResult.isValid() == true // More validation checks can be added // e.g.: && uiState.otherInputValidationResult?.isValid() == true && ... } } Button( enabled = areInputsValid )