Search code examples
kotlinandroid-fragmentsviewmodelandroid-viewmodelandroid-ktx

Share ViewModel used by calling Fragment to DialogFragment using by viewModels


I have a SearchFragment with the following code.

@AndroidEntryPoint
class SearchFragment :
    Fragment(),
    View.OnClickListener {
    ...
    private var _binding: FragSearchBinding? = null
    private val binding get() = _binding as FragSearchBinding
    private val viewmodel by viewModels<SearchViewModel>()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    )
        : View {
        _binding = FragSearchBinding.inflate(inflater, container, false)
        binding.fragSearchSearchResultFilter.setOnClickListener(this)
        return binding.root
    }

    ...

    private fun showFilterDialog() {
        val dialog = FilterBottomSheetDialogFragment.newInstance()
        dialog.show(parentFragmentManager, "filter_bsd_tag")
    }
    ...
}

I am showing a FilterBottomSheetDialogFragment using that SearchFragment. I want to pass the ViewModel of SearchFragment to the DialogFragment. I have this code for my FilterBottomSheetDialogFragment.

@AndroidEntryPoint
class FilterBottomSheetDialogFragment :
    BottomSheetDialogFragment(),
    View.OnClickListener {
    companion object {
        fun newInstance() = FilterBottomSheetDialogFragment()
        private const val TAG_SELECTION_DIALOG = "tag_selection_dialog"
    }

    private var _binding: BsdFilterBinding? = null
    private val binding get() = _binding as BsdFilterBinding
    private val viewmodel: SearchViewModel = ???
}

I have tried

private val viewmodel by viewModels<SearchViewModel>(ownerProducer = { this.requireParentFragment() })

The above doesn't work as it just creates a new instance of ViewModel.

I also tried

private val viewmodel: SearchViewModel by lazy {
    ViewModelProvider(requireParentFragment()).get(SearchViewModel::class.java)
}

The above doesn't work with the error saying that the SearchViewModel instance cannot be created. My SearchViewModel has this constructor.

@HiltViewModel
class SearchViewModel @Inject constructor(
    private val courseRepository: CourseRepository
) : ViewModel()

How can I pass the SearchViewModel to the DialogFragment without using the constructor parameter?


Solution

  • You're mistake here is actually the fragment manager you're using when showing your dialog. Currently you're using the parent fragment manager, whereas your dialog should exist as a child fragment of the fragment it is being shown from.

    So you should be using:

    dialog.show(childFragmentManager, "filter_bsd_tag")
    

    which will then ensure that

    viewModels<SearchViewModel>(ownerProducer = { requireParentFragment() })
    

    refers to the SearchFragment.