'@Composable funck. into onClick event - Jetpack Compose

I try show AlertDialog when press a button. For AlertDialog i have a composable function - showDialog. It is clear that this function calls a dialog. I have another composable function which displays some window with text and buttons. When the button is clicked, I want to call a function that stores the AlertDialog.

AlertDialog body:

fun monthDialog() {

val openDialog = remember { mutableStateOf(true) }

if (openDialog.value) {
    AlertDialog(
        onDismissRequest = {
            openDialog.value = false
        },
        title = {
            Text(text = "Title")
        },
        text = {
            Text(
                "This area typically contains the supportive text " +
                        "which presents the details regarding the Dialog's purpose."
            )
        },
        buttons = {
            Row(
                modifier = Modifier.padding(all = 8.dp),
                horizontalArrangement = Arrangement.Center
            ) {
                Button(
                    modifier = Modifier.fillMaxWidth(),
                    onClick = { openDialog.value = false }
                ) {
                    Text("Dismiss")
                }
            }
        }
    )
}

first I tried the simplest solution that came to my mind:

IconButton(onClick = monthDialog())

and got error (@Composable invocations can only happen from the context of a @Composable function)

after i tried a normal trigger using mutablestateof and following condition:

val showDialog = remember { mutableStateOf(false)}
if(showDialog.value == true) monthDialog()

and put some like this into onClick event:

monthHeader(onClick = {showDialog.value = !showDialog.value})

and this is work....but ugly and badly. for a first time this is worf fine. but after the first click, I need to click two more times to trigger that event again.

button code snippet:

fun Calendar (){
//...

val showDialog = remember { mutableStateOf(false)}
if(showDialog.value == true) monthDialog()

Card(
){
    Column(){
            IconButton(onClick ={
                monthDialog() // error here
                //showDialog.value = !showDialog.value
            }
    }
}

after few hours for searching in google i try my own solution

val clicked = remember { mutableStateOf(false)}
val showDialog = remember { mutableStateOf(false)}

if(showDialog.value) monthDialog()
else if(clicked.value) monthDialog()

Card(){
    Column(){
        monthHeader(onClick = {
            clicked.value = showDialog.value
            showDialog.value = !clicked.value
        })
    }
}

but in my opinion this is crutch/kludge



Solution 1:[1]

Leaving a better solution here (imho):

Hoist the state of your dialog.

@Composable
fun MonthDialog(onClose: () -> Unit) {
    AlertDialog(
        onDismissRequest = onClose,
        title = {
            Text(text = "Title")
        },
        text = {
            Text(
                "This area typically contains the supportive text " +
                        "which presents the details regarding the Dialog's purpose."
            )
        },
        buttons = {
            Row(
                modifier = Modifier.padding(all = 8.dp),
                horizontalArrangement = Arrangement.Center
            ) {
                Button(
                    modifier = Modifier.fillMaxWidth(),
                    onClick = onClose
                ) {
                    Text("Dismiss")
                }
            }
        }
    )

Noticed that I removed the state from this component and make it stateless. This component will just notify when the dialog is closed.

Now you can call the dialog like this:

var showDialog by remember { mutableStateOf(false) }
if (showDialog) {
    MonthDialog(onClose = { showDialog = false })
}
Card {
    MonthHeader( // use upper case for naming your composables
        onClick = {
            showDialog = true
        }
    )
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 nglauber