0

I have one fragment where I update a total integer in my sharedViewModel, this is the shopsFragment

class ShopFragment : Fragment(), AppBarLayout.OnOffsetChangedListener {

    private val model: SharedViewModel by viewModels()

  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        model.updateTotal(200)
    }
}

Now, my other fragment that I need this data to be shared between, is a BottomSheetDialogFragment , in this Fragment I get an instance of the sharedViewModel by doing this

class CartBottomSheet: BottomSheetDialogFragment() {

    private val model: SharedViewModel by viewModels ({requireParentFragment()})

 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
          model.getTotal().observe(viewLifecycleOwner, Observer { total ->
            sheet_total_price.text = "$$total.00"
        })
    }

Now, when I try to get the 200 that I posted in the other Fragment, it shows 0, and that means that the instance of that sharedViewModel is a new instance because it returns 0 because my viewmodel instance initializes a common shared total with 0

class SharedViewModel: ViewModel() {
    private val totalData = MutableLiveData<Int>()
    private var sharedTotal = 0

 fun updateTotal(total:Int){
        sharedTotal = total
        totalData.value = sharedTotal
    }

    fun getTotal():LiveData<Int>{
        return totalData
    }

Now, my question is, do I need to pass as a bundle to the BottomDialogFragment this instance of the sharedViewmodel to work with, or is there any way to get the same instance to get the value of total

Thanks

SNM
  • 5,625
  • 9
  • 28
  • 77
  • Since Shops is not a parent of Cart fragment, I think that requireParent is the problem, I dont know if there is a cleaner way to get the viewmodel than passing it as a bundle to this dialogfragment – SNM Mar 21 '20 at 17:17

1 Answers1

1

You can set ShopFragment as targetFragment for the CartBottomSheet fragment. In this way when you create the Shared VM you will get the same instance. Basically if you put this together you can achieve it by the code below :-

class CartBottomSheet: BottomSheetDialogFragment() {
    private val model: SharedViewModel?=null

    companion object {
        fun show(fragmentManager: FragmentManager, parentFragment: Fragment) {
            val sheet = CartBottomSheet()
            sheet.setTargetFragment(parentFragment, 13)
            sheet.show(fragmentManager, sheet.tag)
        }
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        targetFragment?.let {
            // Create model here with it 
        }
    }

}

So now for opening sheet you should call

CartBottomSheet.show(fragmentManager!!, this)
ADM
  • 20,406
  • 11
  • 52
  • 83
  • I'm usign navigation components to open the fragment with val bundle = Bundle() bundle.putSerializable("cart",ArrayList(cartItemList)) findNavController().navigate(R.id.bottomSheet,bundle) – SNM Mar 21 '20 at 17:57
  • what is SelectBranchBottomSheet – SNM Mar 21 '20 at 18:00
  • I think is CartBottomSheet.show(fragmentManager!!,this) – SNM Mar 21 '20 at 18:01
  • the model should be created as I'm creating it right now ? so now, cartbottomSheet is a child of ShopFragment with this approach ? – SNM Mar 21 '20 at 18:02
  • Have a look a [This thread](https://stackoverflow.com/questions/50752026/how-to-set-target-fragment-of-a-dialog-when-using-navigation-components) since you are using nav-controller .. – ADM Mar 21 '20 at 18:02
  • The problem with that implementation is the getActivity() , I need the sharedviewmodel to live inside shopFragment and not in the container activity – SNM Mar 21 '20 at 18:04
  • What I'm thinking @ADM is to send the data to CartFragment and then when closing it returning this data to the ShopFragment and update the viewmodel from there, what do you think about that ? – SNM Mar 21 '20 at 18:06
  • Well in nav-controller pattern you can also pass arguments. So if you want to keep it that way then you can try passing targetFragment instance( not the recommended way though ) .. See [This](https://developer.android.com/guide/navigation/navigation-pass-data).. Also If you ask me i like to use callback interface in this particular case instead of `LiveData`.. – ADM Mar 21 '20 at 18:06
  • Thanks !! I think that sending all the information to CartFragment as a bundle is better, since when I pop this framgnet, or return to the previos one, I can deliver the updated data this way https://developer.android.com/guide/navigation/navigation-programmatic#returning_a_result doing this prevents me to have an instance of the viewmodel at the CartFragment – SNM Mar 21 '20 at 18:08