Home > Net >  How to prevent duplicate card widget on same product if i click more than one time in Flutter
How to prevent duplicate card widget on same product if i click more than one time in Flutter

Time:12-15

I use provider library state management for doing add to cart and basically i am a bit beginner in provider. So the issue i am facing is for example there are three products laptop , iphone x & keyboard. Now if i put laptop two times in the cart then in cart page it displays two laptop card widgets, instead i want to display only one card widget in that laptop qty: 2. And second issue is that i have implemented and - button in each card widget in cart page and if i click on or - button then it should reflect on qty and also on total price. Really appreciate if you help me in this problem.

main.dart

void main() {
  runApp(ChangeNotifierProvider(
    create: (context) => Cart(),
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final List<Item> items = [
    Item(title: 'laptop ', price: 500.0),
    Item(title: 'iphone x ', price: 400.0),
    Item(title: 'keyboard ', price: 40.0),
  ];
  @override
  Widget build(BuildContext context) {
    return Consumer<Cart>(builder: (context, cart, child) {
      return Scaffold(
        appBar: AppBar(
          title: Text('Shopping cart'),
          actions: <Widget>[
            Padding(
              padding: EdgeInsets.all(8.0),
              child: Row(
                children: <Widget>[
                  IconButton(
                    icon: Icon(
                      Icons.shopping_cart,
                      color: Colors.white,
                    ),
                    onPressed: () {
                      Navigator.of(context).push(MaterialPageRoute(
                          builder: (context) => CheckoutPage()));
                    },
                  ),
                  Text(cart.count.toString())
                ],
              ),
            )
          ],
          centerTitle: true,
        ),
        body: ListView.builder(
          itemCount: items.length,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text(items[index].title),
              subtitle: Text(items[index].price.toString()),
              trailing: Icon(Icons.add),
              onTap: () {
                cart.add(items[index]);
              },
            );
          },
        ),
      );
    });
  }
}

CheckoutPage.dart

class CheckoutPage extends StatefulWidget {
  @override
  _CheckoutPageState createState() => _CheckoutPageState();
}

class _CheckoutPageState extends State<CheckoutPage> {
  @override
  Widget build(BuildContext context) {
    return Consumer<Cart>(
      builder: (context, cart, child) {
        return Scaffold(
            appBar: AppBar(
              title: Text('Checkout Page [\$ ${cart.totalPrice}]'),
              actions: [
                TextButton(
                    onPressed: () {
                      print(cart.totalPrice);
                    },
                    child: Text('Check'))
              ],
            ),
            body: cart.basketItems.length == 0
                ? Text('no items in your cart')
                : ListView.builder(
                    itemCount: cart.basketItems.length,
                    itemBuilder: (context, index) {
                      return Card(
                        child: ListTile(
                          title: Text(cart.basketItems[index].title),
                          subtitle: Row(
                            children: [
                              TextButton(onPressed: () {}, child: Text(' ')),
                              Text(cart.basketItems[index].qty.toString()),
                              TextButton(onPressed: () {}, child: Text('-')),
                            ],
                          ),
                          trailing: IconButton(
                            icon: Icon(Icons.delete),
                            onPressed: () {
                              cart.remove(cart.basketItems[index]);
                            },
                          ),
                        ),
                      );
                    },
                  ));
      },
    );
  }
}

Item.dart

class Item {
  String title;
  double price;
  Item({this.title, this.price});
}

Cart.dart

class Cart extends ChangeNotifier {
  List<Item> _items = [];
  double _totalPrice = 0.0;

  void add(Item item) {
    _items.add(item);
    _totalPrice  = item.price;
    notifyListeners();
  }

  void remove(Item item) {
    _totalPrice -= item.price;
    _items.remove(item);
    notifyListeners();
  }

  int get count {
    return _items.length;
  }

  double get totalPrice {
    return _totalPrice;
  }

  List<Item> get basketItems {
    return _items;
  }
}

CodePudding user response:

Hmm try before adding item add a certain function that will look up for the duplicate item like this

e.g. inside on add

Add qty on you class on item.dart so that in every add item you should have default qty to one then goes this below.

class Item {
  String title;
  double price;
  int qty;
  Item({this.title, this.price,this.qty});
}

void add(Item item) {
  final itemIsExist  = _items.where((e)=> e.title == item.title);
    if(itemIsExist.isNotEmpty){
   // if item exist and you want to add  1 on qty
   final addQty = _items.firstWhere((e)=> e.title == item.title);
   addQty.qty= addQty.qty 1;
   // do your thing here to calculate again the total
}else{
 _items.add(item);
    _totalPrice  = item.price;
    notifyListeners();
}
  }

CodePudding user response:

I suggest creating another variable on base class and extend it for model, But now let's follow your way.

We can create a map to iterate items on _CheckoutPageState and create a Set, but we need to count the item quantity,

We can take the help of map in this case and place it just under Consumer builder before returning Scaffold

Map<String, int> itemsMap = {};

for (final item in cart._items) {
  if (!itemsMap.containsKey(item.title)) {
    itemsMap.putIfAbsent(item.title, () => 1);
  } else {
    itemsMap.update(item.title, (value) => itemsMap[item.title]!   1);
  }
}

And uses will be like

itemBuilder: (context, index) {
  final keys = itemsMap.keys.toList();
  final count = itemsMap.values.toList();
  return Card(
    child: ListTile(
      title: Text(keys[index].toString()),
      subtitle: Row(
        children: [
          TextButton(onPressed: () {}, child: Text(' ')),
          Text(count[index].toString()),
          TextButton(onPressed: () {}, child: Text('-')),
        ],
      ),

State class



class _CheckoutPageState extends State<CheckoutPage> {
  @override
  Widget build(BuildContext context) {
    return Consumer<Cart>(
      builder: (context, cart, child) {
        Map<String, int> itemsMap = {};

        for (final item in cart.basketItems) {
          if (!itemsMap.containsKey(item.title)) {
            itemsMap.putIfAbsent(item.title, () => 1);
          } else {
            itemsMap.update(item.title, (value) => itemsMap[item.title]!   1);
          }
        }
        return Scaffold(
            appBar: AppBar(
              title: Text('Checkout Page [\$ ${cart.totalPrice}]'),
              actions: [
                TextButton(
                    onPressed: () {
                      print(cart.totalPrice);
                    },
                    child: Text('Check'))
              ],
            ),
            body: cart.basketItems.length == 0
                ? Text('no items in your cart')
                : ListView.builder(
                    itemCount: itemsMap.length,
                    itemBuilder: (context, index) {
                      final keys = itemsMap.keys.toList();
                      final count = itemsMap.values.toList();
                      return Card(
                        child: ListTile(
                          title: Text(keys[index].toString()),
                          subtitle: Row(
                            children: [
                              TextButton(
                                  onPressed: () {
                                    cart.add(
                                      Item(
                                        title: keys[index].toString(),
                                        price: keys[index].trim() == "laptop"
                                            ? 500
                                            : keys[index].trim() == "iphone x"
                                                ? 400
                                                : 40,
                                      ),
                                    );
                                  },
                                  child: Text(' ')),
                              Text(count[index].toString()),
                              TextButton(
                                  onPressed: () {
                                    cart.remove(Item(
                                      title: keys[index].toString(),
                                      price: keys[index].trim() == "laptop"
                                          ? 500
                                          : keys[index].trim() == "iphone x"
                                              ? 400
                                              : 40,
                                    ));
                                  },
                                  child: Text('-')),
                            ],
                          ),
                          trailing: IconButton(
                            icon: Icon(Icons.delete),
                            onPressed: () {
                              cart.remove(cart.basketItems[
                                  index]); // remove match all on remove method
                            },
                          ),
                        ),
                      );
                    },
                  ));
      },
    );
  }
}

  • Related