Home > database >  Dart How to combine the values of a Map<dynamic, int> with Iterable<dynamic> and parse a
Dart How to combine the values of a Map<dynamic, int> with Iterable<dynamic> and parse a

Time:08-19

I am trying to merge the key of type Map<dynamic, int> with the value of type Iterable<dynamic> where the result will be a list in the end and be passed as a json to the api. Below is the json i want to achieve in the end:

{
    "productQuantity": [
    {
      "product_id": 10,
      "quantity": 1
    },
    {
      "product_id": 11,
      "quantity": 1
    }
  ]
}

Using https://app.quicktype.io/ i generated the model class checkout:

// To parse this JSON data, do
//
//     final checkout = checkoutFromMap(jsonString);

import 'dart:convert';

class Checkout {
    Checkout({
        this.productQuantity,
    });

    List<ProductQuantity> productQuantity;

    factory Checkout.fromJson(String str) => Checkout.fromMap(json.decode(str));

    String toJson() => json.encode(toMap());

    factory Checkout.fromMap(Map<String, dynamic> json) => Checkout(
        productQuantity: json["productQuantity"] == null ? null : List<ProductQuantity>.from(json["productQuantity"].map((x) => ProductQuantity.fromMap(x))),
    );

    Map<String, dynamic> toMap() => {
        "productQuantity": productQuantity == null ? null : List<dynamic>.from(productQuantity.map((x) => x.toMap())),
    };
}

class ProductQuantity {
    ProductQuantity({
        this.productId,
        this.quantity,
    });

    int productId;
    int quantity;

    factory ProductQuantity.fromJson(String str) => ProductQuantity.fromMap(json.decode(str));

    String toJson() => json.encode(toMap());

    factory ProductQuantity.fromMap(Map<String, dynamic> json) => ProductQuantity(
        productId: json["product_id"] == null ? null : json["product_id"],
        quantity: json["quantity"] == null ? null : json["quantity"],
    );

    Map<String, dynamic> toMap() => {
        "product_id": productId == null ? null : productId,
        "quantity": quantity == null ? null : quantity,
    };
}

I do not know the correct way to merge the productID(Map<dynamic, int>) and the quantity(Iterable<dynamic>) and then pass it to the api. I am using the BLOC pattern for getting the required data from the cart. Below is the checkout screen.

class CheckoutScreen extends StatelessWidget {
  const CheckoutScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final List<ProductQuantity>? _OrderProductQuantity = [];

    return Scaffold(
        appBar: AppBar(
          backgroundColor: buttonBG,
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const ShippingAddress(),
            const SizedBox(height: 20),
            Container(
              height: 60,
              alignment: Alignment.bottomCenter,
              decoration: const BoxDecoration(color: buttonBG),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  Center(
                    child: BlocBuilder<CartBloc, CartState>(
                      builder: (context, state) {
                        if (state is CartLoaded) {
                          return TextButton(
                            onPressed: () {
                              var alc = state.cart
                                  .productQuantity(state.cart.products);
                              var pio = alc.keys.toList();
                              var group = pio
                                  .groupListsBy((element) => element.id)
                                  .map((key, value) =>
                                      MapEntry(key, value.length));
                              var pid = group.keys.toString();
                              var qt = alc.values;
                              debugPrint(
                                  'productID = $pid'); // productID = (11, 10)
                              debugPrint(
                                  'productQuantity = $qt'); // productQuantity = (1, 1)
                              BlocProvider.of<CartBloc>(context)
                                  .add(PlaceOrderButtonPressed(
                                productQuantity: productQuantity,
                              ));
                            },
                            child: Text(
                              'Place Order',
                              style: Theme.of(context)
                                  .textTheme
                                  .button!
                                  .copyWith(color: Colors.white),
                            ),
                          );
                        }
                        return const Text('There was an error');
                      },
                    ),
                  ),
                  IconButton(
                    onPressed: () {},
                    icon: const Icon(
                      Icons.arrow_forward,
                      color: Colors.white,
                    ),
                  )
                ],
              ),
            ),
          ],
        ));
  }
}

Below is the CartBloc where i get the value of the productID and quantity:

  FutureOr<void> _placeOrder(
      PlaceOrderButtonPressed event, Emitter<CartState> emit) async {
    emit(PlacingOrderState());
    try {
      await checkoutRepo.placeOrder(event.productQuantity);

      emit(OrderSuccessState());
    } catch (error) {
      emit(OrderPlacingFailureState(error: error.toString()));
    }
  }

For the cartEvent:

class PlaceOrderButtonPressed extends CartEvent {
  final List<ProductQuantity>? productQuantity;

  const PlaceOrderButtonPressed({
    required this.productQuantity,
  });

  @override
  List<Object> get props => [];
}

The CheckoutRepository is as follows:

  Future<void> placeOrder(
    List<ProductQuantity>? productQuantity,
  ) async {
    await SecureStorage.readSecureData("token")
        .then((value) => finalToken = value);
    debugPrint('Place Order With Token: $finalToken');

    try {
      Map<String, dynamic> cartData = {
        "productQuantity": productQuantity,
      };

      Response response = await _dio.post(
        placeOrderUrl,
        options: Options(
          headers: {
            'Content-Type':
                'application/x-www-form-urlencoded;charset=UTF-8;application/json;multipart/form-data',
            'Accept': 'application/json',
            "Authorization": "Bearer $finalToken",
          },
        ),
        data: jsonEncode(cartData),
      );
    } on DioError catch (e) {
      debugPrint("Status code: ${e.response?.statusCode.toString()}");
      throw Exception('Failed to place order');
    }
  }

Please how do i achieve this?

CodePudding user response:

as per my understanding you are trying to implement cart functionality , I hace explaind cart functionality here , you can check this , you may have to change model as per your requirement.

CodePudding user response:

I was able to achieve this partially by using the dart extension on funtion which allowed me to iterate and merge the two lists. Now i get the instance of the list.

extension on List<ProductQuantity> {
  void addProductQuantity({required int productID, required int quantity}) {
    if (isNotEmpty) {
      try {
        var productWid = firstWhere((p) => p.productId == productID);
        productWid.quantity == quantity;
      } catch (e) {
        add(ProductQuantity(productId: productID, quantity: quantity));
      }
    } else {
      add(ProductQuantity(productId: productID, quantity: quantity));
    }
  }
}

Then i used a for loop to get the individual productID and quantity of each cart item.

                              setState(() {
                                for (var i = 0; i < plist.length; i  ) {
                                  idInOrder = plist[i];

                                  // debugPrint(plist[i].toString());
                                }
                                for (var i = 0; i < qt.length; i  ) {
                                  quantityInOrder = qt[i];
                                  // debugPrint(qt[i].toString());
                                }
                              });

Then finally added the empty list _orderProductQuantity to the extension on function.

                              _orderProductQuantity.addProductQuantity(
                                  productID: idInOrder,
                                  quantity: quantityInOrder);

So the result becomes a combined list of: [Instance of ProductQuantity] which is where i am running into a problem because i only get one instance when i should have multiple instances. If you run jsonEncode(_orderProductQuantity) the result will be ["{\"product_id\":11,\"quantity\":5}"]} which is my end target. I will create another question to try and find a way to get multiple instances instead of just 1 instance. Will update after that.

  • Related