1

Product Item Composable :

    @Composable
fun ProductItem(product: Product, index: Int) {

    val addProductViewModel = hiltViewModel<AddProductVM>()

    val productSelectedIndex = remember { mutableIntStateOf(0) }

    Card(
        modifier = Modifier
            .fillMaxWidth()
    ) {
        Row(modifier = Modifier
            .fillMaxHeight()) {

            Column() {

                Row{
                    Box(
                        modifier = Modifier
                            .weight(1f)
                        contentAlignment = Alignment.Center
                    ) {
                        if (product.variants[0].cart_count > 0) {
                            Row {
                                Text(text = product.variants[0].cart_count.toString())
                      }
                        } else {
                            Text(
                                text = "Add To Cart", // "Add To Cart" text
                                modifier = Modifier
                                    .clickable {
                                        productSelectedIndex.intValue = index
                                        val newCount = product.variants[0].cart_count + 1
                                        addProductViewModel.addProduct(product.variants[0].product_id.toString(),
                                            newCount.toString(),
                                            product.variants[0].id.toString())
                                    }
                            )
                        }
                    }
                }
            }
        }
    }
}

Here I want to update the text count value by clicking Add to Cart text

AddProductResult Composable :

    @Composable
fun AddProductResult(addProductResult: ApiResult<AddProduct>) {

    when (addProductResult) {
        is ApiResult.Loading -> {
            // Loading state code for products
        }

        is ApiResult.Error -> {
            Log.e("addproductapicall", "failure error: " + addProductResult.error.toString())
        }

        is ApiResult.Success -> {
            val Result = addProductResult.data?.error
            if(Result == true) {
                Log.e("addproductapicall", "success success: " + addProductResult.data.message.toString())
            } else {
                Log.e("addproductapicall", "failure success: " + addProductResult.data?.message.toString())
            }
        }
    }
}

I want to update the UI of clicked Product count text when I clicked on "Add To Cart" text only after getting response from AddProductResult when Result == false

now. its updating before api call result

This is my view model

AddProductVM :

    @HiltViewModel
class AddProductVM @Inject constructor(private val apiService: ApiService,
                                       private val defaultDispatcher: CoroutineDispatcher
): ViewModel() {

    private val _addProductList= MutableStateFlow<ApiResult<AddProduct>>(ApiResult.Empty())
    val addProductList= _addProductList.asStateFlow()

    fun addProduct(productId:String,qty:String,productVariantId:String){
        _addProductList.value = ApiResult.Loading()
        viewModelScope.launch {
            apiService.addProduct(productId,qty,productVariantId)
                .flowOn(defaultDispatcher)
                .catch {
                    _addProductList.value= ApiResult.Error(it.message ?: "Something went wrong")
                }
                .collect{
                    _addProductList.value=it
                }
        }
    }
}
2
  • Hello, why didn't you add the code of addProductViewModel.addProduct function? Commented Nov 11, 2023 at 18:17
  • yes , I have added now, please check @Faruk Karaca Commented Nov 12, 2023 at 1:24

1 Answer 1

1

First of all, your ApiResult class should look like this. You should check the Success and Error states separately. You don't' need to check errors again in ApiResult.Success.

sealed class ApiResult<out T> {
    object Loading: ApiResult<Nothing>()

    data class Success<out T>(
        val data: T
    ): ApiResult<T>()

    data class Error(
        val e: Exception
    ): ApiResult<Nothing>()
}

Collecting should look something like this

viewModelScope.launch {
    apiService.addProduct(productId,qty,productVariantId)
        .flowOn(defaultDispatcher)
        .catch {
            _addProductList.value= ApiResult.Error(e = it)
        }
        .collect{
            _addProductList.value= ApiResult.Success(data = it)
        }
}

and compose

when (addProductResult) {
    is ApiResult.Loading -> {
        // Loading state code for products
    }

    is ApiResult.Error -> {
        Log.e("addproductapicall", "failure error: " + addProductResult.e.message)
    }

    is ApiResult.Success -> {
        val Result = addProductResult.data
    }
}

If you go with this approach it should work fine. You will have to work a little, I can't see the entire code. This should be the correct approach.

Sign up to request clarification or add additional context in comments.

2 Comments

actually , i am getting the response from api successfully, my requirement is to update the text value of clicked item in ProductItem composable after getting api result which is another composable @Faruk Karaca
you need set collectAsStateWithLifecycle() for Product before passing ProductItem compose function. If Product does not behave like a state, the compose will not understand that it needs to be recompose when its value changes. You need to adapt the following statement into your code. var state = viewModel.state.collectAsStateWithLifecycle() @Composable fun MyCompose (state: String) { Text(state) } Whenever the state here changes, the text will also change.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.