Search code examples
android-jetpack-composeandroid-jetpack-navigationandroid-jetpack-datastore

How to add a value coming from inside a compose function into a dataStore


I am building an Android app that uses Compose and Navigation. On one screen I have several form fields each in its own composable function, of which I want to store the values. I have managed to do so for a single form field that is in the main screen function as in this example like this:

@Composable
fun Screen1(navController: NavController) {
    val context = LocalContext.current 
    val scope = rememberCoroutineScope()
    val dataStoreName = StoreName(context)
    val savedName = dataStoreName.getValue.collectAsState(initial = "")
    Column( ) { 
        val patientName = remember { mutableStateOf("") }
        Button(onClick = {scope.launch {dataStoreName.saveValue(patientName.value)}
            navController.navigate(Screen.Screen2.route) })  {
                Text(text = "Save & Next")}
        OutlinedTextField( value = patientName.value,
            label = { Text(text = "Name") },
            onValueChange = {  patientName.value = it  }) 
        Text(text = "Current information stored: " + savedName.value)  }  }

However, it is not clear to me how to adapt it when I have several fields each in it's own composable function. When I place the mutableState variable inside the textfield function it is not recognized by the code in the save button, and when I place it outside, the variable is not recognized by the textfield function... This is one of the textfield function as I have them now, which I would call inside the column in the Screen1 function:

@Composable
fun PatientNameField() {
    val patientName by remember { mutableStateOf(TextFieldValue("")) }
    OutlinedTextField(
        value = patientName.value,
        label = { Text(text = "Name") },
        onValueChange = { patientName.value = it   }    )
}

Solution

  • For your current problem you can pass the patientName as a parameter to your PatientNameField composable as shown below. This will help to maintain the state of patientName across your Screen1 and PatientNameField composables.

    @Composable
    fun Screen1(navController: NavController) {
        val context = LocalContext.current
        val scope = rememberCoroutineScope()
        val dataStoreName = StoreName(context)
        val savedName = dataStoreName.getValue.collectAsState(initial = "")
        Column {
            val patientName = remember { mutableStateOf("") }
            Button(onClick = {
                scope.launch { dataStoreName.saveValue(patientName.value) }
                navController.navigate(Screen.Screen2.route)
            }) {
                Text(text = "Save & Next")
            }
    
            //pass the patientName as a parameter to your Composable
            PatientNameField(patientName)
    
            Text(text = "Current information stored: " + savedName.value)
        }
    }
    
    @Composable
    fun PatientNameField(patientName: MutableState<String>) {
        OutlinedTextField(
            value = patientName.value,
            label = { Text(text = "Name") },
            onValueChange = { patientName.value = it   }    )
    }