I am having some issues in my code.
So I am trying to create a product cart where a user clicks on the + button to increase the quantity of products and clicks on – button to decrease the quantity of products. Also these products are recommended products so they should have a default quantity of 1 product. But when I set the initial quantity to be 1, it does not behave well. When I click on the product once, it does not update but when when I click the second time, it updates it to 2. I tried doing some print statement, and I noticed that the default is still 0 and when it is clicked once, it just update to 1 and the second time is now 2 which now changed on the UI. How do I make it know there is an existing item of 1 quantity so when I increase it, it changes to 2 immediately. Also when I decrease it, it changes to 0 since it is 1 by default.
These are my code
I am using provider for state management
//cart_provider.dart
import 'package:flutter/material.dart';
import '../models/product_model.dart';
class CartProvider with ChangeNotifier {
List<Product> cartItems = [];
void addProduct(Product product) {
final existingProductIndex =
cartItems.indexWhere((p) => p.productName == product.productName);
if (existingProductIndex != -1) {
cartItems[existingProductIndex].quantity++;
} else {
product.quantity = 0;
cartItems.add(product);
}
notifyListeners();
}
void updateQuantity(Product product, bool isIncrement) {
final existingProductIndex =
cartItems.indexWhere((p) => p.productId == product.productId);
if (existingProductIndex != -1) {
if (isIncrement && product.quantity < 99) {
cartItems[existingProductIndex].quantity++;
product.isDecrementButtonDisabled = false;
} else if (!isIncrement) {
cartItems[existingProductIndex].quantity--;
if (cartItems[existingProductIndex].quantity == 0) {
product.isDecrementButtonDisabled = true;
}
}
} else {
addProduct(product);
}
notifyListeners();
}
}
//product_card.dart (this is where I am displaying the data"
import 'package:flutter/material.dart';
import 'package:greenbii_app/providers/cart_provider.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import '../constants/constants.dart';
import '../models/product_model.dart';
class ProductCard extends StatelessWidget {
final Product product;
const ProductCard({
Key? key,
required this.product,
}) : super(key: key);
@override
Widget build(BuildContext context) {
NumberFormat currencyFormat = NumberFormat.currency(
locale: 'en_NG',
name: 'naira',
symbol: '₦',
);
return Consumer<CartProvider>(
builder: (context, cartProvider, child) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
product.productName,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.textColor,
fontSize: 16.0,
fontWeight: FontWeight.w700,
),
),
Text(
product.descriptions,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.disabledColor,
fontSize: 12.0,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 10.0),
Text(
currencyFormat.format(double.parse(product.amount)),
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.primaryColor,
fontSize: 18.0,
fontWeight: FontWeight.w600,
),
),
],
),
),
Row(
children: [
IconButton(
onPressed: product.isDecrementButtonDisabled
? null
: () => context
.read<CartProvider>()
.updateQuantity(product, false),
icon: const Icon(Icons.remove),
),
const SizedBox(width: 10.0),
Text(product.quantity.toString()),
const SizedBox(width: 10.0),
IconButton(
onPressed: () => context
.read<CartProvider>()
.updateQuantity(product, true),
icon: const Icon(Icons.add),
),
],
)
],
);
},
);
}
}
//product_model.dart
class Product {
final int productId;
final String productName;
final String descriptions;
final String amount;
bool isDecrementButtonDisabled = false;
int quantity = 1;
Product({
required this.productId,
required this.productName,
required this.descriptions,
required this.amount,
});
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is Product &&
runtimeType == other.runtimeType &&
productId == other.productId;
@override
int get hashCode => productId.hashCode;
}
//loan_application.dart
import 'package:flutter/material.dart';
import 'package:greenbii_app/constants/constants.dart';
import 'package:greenbii_app/providers/cart_provider.dart';
import 'package:greenbii_app/widgets/menu_app_bar.dart';
import 'package:provider/provider.dart';
import '../models/product_model.dart';
import '../navigations/navigate.dart';
import '../widgets/data/product_data.dart';
import '../widgets/product_card.dart';
class LoanApplication extends StatefulWidget {
const LoanApplication({super.key});
@override
State<LoanApplication> createState() => _LoanApplicationState();
}
class _LoanApplicationState extends State<LoanApplication> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const MenuAppBar(
menuName: 'Loan Application',
isBack: true,
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: double.infinity,
decoration: BoxDecoration(
color: AppColors.successColor,
borderRadius: BorderRadius.circular(10),
),
child: const Padding(
padding: EdgeInsets.all(16.0),
child: Text(
'Best rate! The Purchasing Power Index of your business has been applied to your interest rate.',
style: TextStyle(
color: AppColors.primaryColor,
),
),
),
),
const SizedBox(height: 50),
const Text(
'Recommended Devices',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 10),
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(
vertical: 31.0, horizontal: 21.0),
decoration: BoxDecoration(
color: AppColors.whiteColor,
borderRadius: BorderRadius.circular(20.0),
boxShadow: const [
BoxShadow(
color: AppColors.shadowColor,
spreadRadius: 0.0,
blurRadius: 20.0,
),
],
),
child: ListView.separated(
itemCount: products.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
final product = products[index];
// final cart = Provider.of<CartProvider>(context);
return Consumer<CartProvider>(
builder: (context, cartProvider, child) {
return ProductCard(
key: ValueKey(product.productId),
product: product,
);
});
},
separatorBuilder: (context, index) => const Divider(
height: 30.0,
),
),
),
const SizedBox(height: 20),
const Text(
'More Devices',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 10),
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(
vertical: 31.0, horizontal: 21.0),
decoration: BoxDecoration(
color: AppColors.whiteColor,
borderRadius: BorderRadius.circular(20.0),
boxShadow: const [
BoxShadow(
color: AppColors.shadowColor,
spreadRadius: 0.0,
blurRadius: 20.0,
),
],
),
child: ListView.separated(
itemCount: products.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
final product = products[index];
final cart = Provider.of<CartProvider>(context);
return ProductCard(
key: ValueKey(product.productId),
product: product,
);
},
separatorBuilder: (context, index) => const Divider(
height: 30.0,
),
),
),
],
),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: GestureDetector(
onTap: () {
// navigate(context, const LoanApplication());
},
child: Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: AppColors.primaryColor,
),
child: const Text(
textAlign: TextAlign.center,
'Apply for Funding',
style: TextStyle(
color: Colors.white,
fontSize: 16,
),
),
),
),
),
);
}
}
//product_data.dart
import 'package:greenbii_app/models/product_model.dart';
final List<Product> products = [
Product(
productId: 1,
productName: 'Mobile Tablet',
descriptions: '10 inches screen, 4g ram, table or wall fitted.',
amount: '100000.00',
),
Product(
productId: 2,
productName: 'Laptop',
descriptions: '(500GB HDD, 8GB RAM, Core i5).',
amount: '250000.00',
),
Product(
productId: 3,
productName: '2.5Kva Backup Solar',
descriptions: '24v hybrid inverter, 2 batteries, 4 380W panels.',
amount: '300000.00',
),
];
Please I will be glad if I get a quick response and detailed explanation as I am just a beginner flutter developer.
Thank you guys. I will really appreciate this.
2
Answers
So I have been able o sort this. I realised that I am not fetching the products into the cart and also not allowing the state management to handle the state.
The problem is that at the very first increment to any product, you’re not actually having that product yet in
cartItems
. The product is being read directly from theproducts
list, so the first increment only add the product to thecartItems
, without incrementing it. Since you said that these products should have the initial quantity to 1, it means that you should populatecartItems
with products from theproducts
list at the very beginning. You can solve it by changing the initialization ofcartItems
like this: