# compose

Lukasz Kalnik

08/12/2022, 9:40 AM
Using Compose Destinations library, I pass a navigation argument and read it in ViewModel from
. Then I need to load data in the ViewModel based on the passed argument. Do I get some callback when the ViewModel has been navigated to? How do I perform the initial data loading based on the navigation argument?
When I do it in the ViewModel's
block, it crashes, because it tries to access the navigation argument when the ViewModel is created in containing Fragment to be passed to the composable in the initial navigation graph setup.
I suppose this is the cause of the problem, passing the ViewModel to composable for setup in the Fragment:
Copy code
class SystemFragment : Fragment() {
    private val sensorSettingsViewModel by viewModels<SensorSettingsViewModel>(
        factoryProducer = { SensorSettingsViewModelFactory(this) }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        return ComposeView(requireContext()).apply {
            setContent {
                            navGraph = NavGraphs.root
                        ) {
                            composable(SensorSettingsSheetDestination) {
                                    viewModel = sensorSettingsViewModel
This is what I have in my ViewModel (and it crashes when entering the
, even without any actual navigation to the
Copy code
class SensorSettingsViewModel(
    savedStateHandle: SavedStateHandle,
) : ViewModel() {

    private val navArgs: SensorSettingsSheetNavArgs = savedStateHandle.navArgs()
    private val currentId: String = navArgs.sensorId

It crashes with
RuntimeException: 'sensorId' argument is mandatory but was not present
Copy code
at myapp.systemoverview.presentation.destinations.SensorSettingsSheetDestination.argsFrom (SensorSettingsSheetDestination.kt:77)

Colton Idle

08/12/2022, 10:26 AM
Hm. Typically in this case I will just grab the arg from sSH in init like you mentioned and I've never had any issues. I wonder if it has something to do with the fact that you're using fragments? im not being too helpful except with basically saying that, what you did _should work (at least in my exp)

Lukasz Kalnik

08/12/2022, 11:05 AM
No problem, thanks for chiming in anyway. Every feedback is helpful.
However in my code it's clear that the
gets constructed in
even though there was no navigation to it (because I pass it to the composable). I will test a delayed passing of viewmodels (as composable default argument), maybe it fixes the issue.
Yes, I can confirm - not creating the ViewModel in Fragment fixed the crash.
In the end I generated the viewmodels with
and passed them as default parameters to the composables:
Copy code
val systemOverviewModule = module {
     viewModel { SensorSettingsViewModel(savedStateHandle = get()) }
Copy code
fun SystemScreen(
    viewModel: SystemViewModel = getViewModel(),
) {}
(I just noticed that there are different screens/viewmodels in both snippets, but you get the idea.)