12

I have been trying to show AlertDialog from onClick of Card in dynamic list in Android Jetpack Compose.

I am getting compile time error @Composable invocations can only happen from the context of a @Composable function when doing it.

Below is my code snippet :

@Preview(showBackground = true)
@Composable
fun prepareCard(card: Card) {
    MyApplicationTheme() {
        androidx.compose.material.Card() {
            Column(Modifier.clickable {
                Log.d("TAG", "clicked : " + card.name)
                val showDialog = mutableStateOf(true)

                if (showDialog.value) {
                    alert(card)
                }
                 ...
            }
        }
     }

I have made alert() composable function which gets called from above code

@Composable
fun alert(card : Card) {
    AlertDialog(
        title = {
            Text("")
        },
        text = {
            Text(text = card.name)
        }, onDismissRequest = {
        },
        confirmButton = {},
        dismissButton = {}
    )
}

As shown in image, I am getting compile time error

Please help to solve this issue

Note :

I have tried like below modifications, it solved compile time error but it is still not showing AlertDialog on click of Card

@Preview(showBackground = true)
@Composable
fun prepareCard(card: Card) {
    MyApplicationTheme() {
        val showDialog = mutableStateOf(false)


        if (showDialog.value) {
            alert(card)
        }

        androidx.compose.material.Card() {
            Column(Modifier.clickable {
                Log.d("kushal", "clicked : " + card.name)
                showDialog.value = true
            }) {
            ...
           }
         }

enter image description here

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
Kushal
  • 8,100
  • 9
  • 63
  • 82

3 Answers3

18

Use the remember in your showDialog to resolve the issue of not showing the AlertDialog.

val showDialog = remember { mutableStateOf(false) }
if (showDialog.value) {
     // alert...
}
Card() {
   Column(Modifier.clickable(
     onClick = {showDialog.value = true})
   ) {}
}

Also in your Alert() function you should handle the state.

@Composable
fun Alert(name: String,
          showDialog: Boolean,
          onDismiss: () -> Unit) {
    if (showDialog) {
        AlertDialog(
            title = {
                Text("Title")
            },
            text = {
                Text(text = name)
            }, 
            onDismissRequest = onDismiss,
            confirmButton = {
                TextButton(onClick = onDismiss ) {
                    Text("OK")
                }
            },
            dismissButton = {}
        )
    }
}

and call it with:

val showDialog = remember { mutableStateOf(false) }

Card() {
    if (showDialog.value) {
        Alert(name = "Name",
            showDialog = showDialog.value,
            onDismiss = {showDialog.value = false})
    }
    Column(Modifier.clickable(
        onClick = {showDialog.value = true})
    ) {}
}
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
  • I implemented like you suggested and it is working. If I click outside of `AlertDialog` it is closing alert which is expected behavior, but I am not able to understand how Jetpack Compose is handling this. If I do not pass `onDismiss` in `alert()` call, then `AlertDialog` is not closing on outside click. Can you explain this? – Kushal Apr 06 '21 at 07:01
  • 1
    It is handled by the `onDismissRequest` : Executes when the user tries to dismiss the `Dialog` by clicking outside or pressing the back button – Gabriele Mariotti Apr 06 '21 at 07:35
4

You can update your code like the code below ->

@Composable
fun alert() {
MaterialTheme {
    Column {
    val openDialog = remember { mutableStateOf(false)  }

        Button(onClick = {
            openDialog.value = true
        }) {
            Text("Click me")
        }

        if (openDialog.value) {

            AlertDialog(
                onDismissRequest = {
                    // Dismiss the dialog when the user clicks outside the dialog or on the back
                    // button. If you want to disable that functionality, simply use an empty
                    // onCloseRequest.
                    openDialog.value = false
                },
                title = {
                    Text(text = "Dialog Title")
                },
                text = {
                    Text("Here is a text ")
                },
                confirmButton = {
                    Button(

                        onClick = {
                            openDialog.value = false
                        }) {
                        Text("This is the Confirm Button")
                    }
                },
                dismissButton = {
                    Button(

                        onClick = {
                            openDialog.value = false
                        }) {
                        Text("This is the dismiss Button")
                    }
                }
            )
        }
    }

}
}
Anwar Elsayed
  • 493
  • 3
  • 11
  • But it does not solve `compile-time` error – Kushal Apr 05 '21 at 11:43
  • this a full example with a button when you click on the button it will show the AlertDialog – Anwar Elsayed Apr 05 '21 at 11:44
  • you can find it also on jetpack play ground from here https://foso.github.io/Jetpack-Compose-Playground/material/alertdialog/ – Anwar Elsayed Apr 05 '21 at 11:45
  • I have checked it. I have tried to update my code and added updated code in question. Can you once check it? With updated code, compile-time error is not coming but `AlertDialog` is not showing `onClick` – Kushal Apr 05 '21 at 12:08
  • 1
    Add `val showDialog = remember { mutableStateOf(false) }` insted of `val showDialog = mutableStateOf(false)` this will help the issue of not showing the dialog onClick – Anwar Elsayed Apr 05 '21 at 12:17
0

That's the recommended way to show the dialog by using states.

val openDialog = remember { mutableStateOf(true) }
val dialogWidth = 200.dp
val dialogHeight = 50.dp

if (openDialog.value) {
    Dialog(onDismissRequest = { openDialog.value = false }) {
        // Draw a rectangle shape with rounded corners inside the dialog
        Box(Modifier.size(dialogWidth, dialogHeight).background(Color.White))
    }
}
abhi
  • 961
  • 9
  • 13