Home > Net >  TextField value is not set to empty string despite setting empty state value
TextField value is not set to empty string despite setting empty state value

Time:01-13

My shopping list item Quantity TextField allows a decimal point, and if the user types a decimal as the first character like ".42", it throws an NumberFormatException when I cast the TextField string to a Double in the code below. To prevent the exception, I simply check to see if the TextField value is ".". If so, I set the Quantity to an empty string and display a Toast message telling the user to enter a valid quantity, but it is not setting the Quantity state to "", and pressing the decimal key at this point does not show the Toast message. I have to press the backspace key and press the decimal key again to display the message. How can I fix this?

ShoppingListItem Model

@Parcelize
data class ShoppingListItem(
    val id: Long = 0L,
    val shoppingListId: Long = 0L,
    ...
    val quantity: String = "",
): Parcelable

ViewModel

private val _shoppingListItemState = MutableLiveData(
    savedStateHandle.get<ShoppingListItem>("shoppinglistitem")
        ?: ShoppingListItem()
)

override val shoppingListItemState: LiveData<ShoppingListItem>
    get() = _shoppingListItemState

...

override fun setStateValue(stateToEdit: String, stateValue: Any?) {
 when (stateToEdit) {
      ITEM_QUANTITY_STR -> {
          _shoppingListItemState.value =
          _shoppingListItemState.value!!.copy(quantity = stateValue.toString())
        } 
    }
}

Composable

CustomOutlinedTextField(
    fieldModifier = Modifier
        .width(150.dp)
        .padding(end = 8.dp)
        .onPreviewKeyEvent {
            if (it.key == Key.Tab && it.nativeKeyEvent.action == ACTION_DOWN) {
                focusManager.moveFocus(FocusDirection.Right)
                true
            } else {
                false
            }
        },
    label = ITEM_QUANTITY_STR,
    inputVal = shoppingListItemState.value!!.quantity,
    isSingleLine = true,
    keyboardOptions = KeyboardOptions.Default.copy(
        capitalization = KeyboardCapitalization.None,
        autoCorrect = false,
        keyboardType = KeyboardType.Decimal,
        imeAction = ImeAction.Next
    ),
    keyboardActions = KeyboardActions(
        onNext = { focusManager.moveFocus(FocusDirection.Right) }
    )
) { value ->
    if(value == ".") {
        Toast.makeText(context, "Please enter a valid quantity", Toast.LENGTH_LONG)
            .show()
        mainViewModel.setStateValue(
            ITEM_QUANTITY_STR,
            ""
        )
    } else {
        if (value.isEmpty()) {
        mainViewModel.setStateValue(
            ITEM_QUANTITY_STR,
            ""
        )
    } else {
            val counter = value.count { it == decimalSeparator }
            if (counter <= 1) {
                if (value.toDouble() <= 999_999.999) {
                    mainViewModel.setStateValue(
                        ITEM_QUANTITY_STR,
                        value
                    )
                }
            }
        }
    }
}

CodePudding user response:

You can prevent the exception using in your validation something like:

value.toDoubleOrNull()

You can also use a regex to restrict the allowed character to a decimal number:

val pattern = remember { Regex("^\\d*\\.?\\d*\$") }

TextField(
    value = text,
    onValueChange = {
        if (it.isEmpty() || it.matches(pattern)) {
            text = it
            validate(it.toDoubleOrNull())
        }
    },
    keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal)
)
  • Related