OutlinedTextField in AlertDialog is not editable - Android Compose

47 views Asked by At

I'm trying to create a simple AlertDialog with a single OutlinedTextField which takes some value and performs an action when confirm button is clicked. No matter what I try, it seems the text field is not editable and I can't figure out why.

@Composable
fun InputDialog(
    dialogTitle: String,
    description: String,
    value: MutableState<String>,
    show: MutableState<Boolean>,
    onConfirm: (String) -> Unit) {
    val textFieldValue = TextFieldValue(value.value)
    AlertDialog(
        //modifier = Modifier.background(Color.Yellow),
        onDismissRequest = {
            show.value = false
        },
        confirmButton = {
            TextButton(
                onClick = {
                    onConfirm(textFieldValue.text)
                }
            ) {
                Text("Save")
            }
        },
        dismissButton = {
            TextButton(
                onClick = {
                    show.value = false
                }
            ) {
                Text("Cancel")
            }
        },
        text = {
            Column {
                Text(description)
                OutlinedTextField(
                    enabled = true,
                    readOnly = false,
                    value = textFieldValue,
                    onValueChange = {
                        value.value = it.text
                    },
                    label = {
                        Text(dialogTitle.toUpperCase(Locale.current))
                    },
                    placeholder = {
                        Text(dialogTitle)
                    })
            }
        })
}
2

There are 2 answers

4
tomerpacific On

The issue is that the value for your textfield is not defined as state.

You have this:

@Composable
fun InputDialog(
    dialogTitle: String,
    description: String,
    value: String,
    show: MutableState<Boolean>,
    onConfirm: (String) -> Unit) {
    var textFieldValue = TextFieldValue(value) /// <------ HERE

and you should convert it to this:

val textFieldValue = remember { mutableStateOf("")}

For more about state in Jetpack Compose, you can read here.

0
BenjyTec On

I think you are trying to pass in the text from a parent Composable and also update the value there in case the user edits the text. In that case, you should not create a second state variable in the InputDialog.

In Jetpack Compose, we use the unidirectional data flow pattern. That means that values/state flows down the Composable hierarchy, and changes/events flow upwards by using callback functions. So you should pass down the text that should be displayed, and once the text changes, notify the parent about that change. The parent updates the state variable, this update will cause a recomposition, and the text in the InputDialog will be updated accordingly.

Please try to update your code as follows:

@Composable
fun ParentComposable() {

    var inputText by remember { mutableStateOf("Hello") }

    //...
    InputDialog(
        dialogTitle = "My Title",
        dialogDescription = "My Description",
        text = inputText,
        onTextChange = { newValue ->
            inputText = newValue  // update text with new value
        },
        show = true,
        onConfirm = { /** ... **/ }
    )
}

Then update your InputDialog Composable as follows:

@Composable
fun InputDialog(
    dialogTitle: String,
    description: String,
    text: String,
    onTextChange: (String) -> Unit,  // introduce callback parameter
    show: MutableState<Boolean>,
    onConfirm: (String) -> Unit) {

    AlertDialog(
        // ...
        text = {
            Column {
                Text(description)
                OutlinedTextField(
                    enabled = true,
                    readOnly = false,
                    value = text,
                    onValueChange = { newText ->
                        onTextChange(newText)  // callback to parent
                    },
                    // ...
                )
            }
        }
    )
}

I renamed some parameters to avoid confusion.
Note that there are two different overloads of OutlinedTextField available:

This overload provides access to the input text, cursor position and selection range and IME composition. If you only want to observe an input text change, use the OutlinedTextField overload with the String parameter instead.

In your case, the first overload is probably enough. Then you also don't need to take care of managing the cursor and selection yourself.