ltvie
ltvie

Reputation: 973

How to call viewmodel dynamically with difference params with jetpack compose?

At the first time running, these code was working properly. Showing the data from the firestore with default parameter. But if I change parameter based on selectedDropdown no data is retrieved. I use modelFactory

Here my MainActivity class

Column() {
    Column {
        DropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false },
            modifier = Modifier
                .width(with(LocalDensity.current) { textfieldSize.toDp() })
        ) {
            suggestions.forEach { label ->
                DropdownMenuItem(onClick = {
                    selectedText = label
                    pompaId = label.replace(" ", "").lowercase() // 1. parameter value based on this
                    expanded = !expanded
                }) {
                    Text(text = label)
                }
            }
        }
    }
    KalibrasiList(pompaId) //2. this called everytime dropdown was changed
    
}

Composable Function

@Composable
fun KalibrasiList(
    pompaId: String,
    kalibrasiViewModel: KalibrasiViewModel = viewModel(
        factory = KalibrasiViewModelFactory(pompaId, KalibrasiRepository()) //3. this fired once even parameter was change. (I need this fired follow dropdown change, so firestore can fired to retrieve data)
    )
) {
    when (val kalibrasiList = kalibrasiViewModel
        .response
        .asStateFlow()
        .collectAsState()
        .value) {

        is OnSuccess -> {
           // my code here..
        }
}

ModelFactory

class KalibrasiViewModelFactory(
    private val pompaId: String,
    private val kalibrasiRepository: KalibrasiRepository
) : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(KalibrasiViewModel::class.java)) {
            return KalibrasiViewModel(pompaId, kalibrasiRepository) as T
        }
        throw IllegalStateException()
    }
}

viewmodel class

class KalibrasiViewModel(val pompaId: String,val kalibrasiRepository: KalibrasiRepository): ViewModel() {

    val response = MutableStateFlow<Response?>(null)

    init {
        viewModelScope.launch {
            kalibrasiRepository.getList(pompaId).collect {
                response.value = it
            }
        }
    }
}

repository class

class KalibrasiRepository {
    private val firestore = FirebaseFirestore.getInstance()
    @OptIn(ExperimentalCoroutinesApi::class)
    fun getList(pompaId: String) = callbackFlow {
        val collection = firestore.collection("colCalibrate")
            .whereEqualTo("pompaId", pompaId)
            .orderBy("createdAt", Query.Direction.DESCENDING)
        val snapshotListener = collection.addSnapshotListener { value, error ->
            val response = if (error == null) {
                OnSuccess(value)
            } else {
                OnError(error)
            }

            this.trySend(response).isSuccess
        }

        awaitClose {
            snapshotListener.remove()
        }
    }

}

I want to load data every time when the dropdown value was changed.

Upvotes: 1

Views: 1586

Answers (1)

Phil Dukhov
Phil Dukhov

Reputation: 87774

You can use key parameter of viewModel: it'll create a new view model for each unique key.

kalibrasiViewModel: KalibrasiViewModel = viewModel(
        key = pompaId,
        factory = KalibrasiViewModelFactory(pompaId, KalibrasiRepository(),
    )
)

Upvotes: 1

Related Questions