I'm trying to make an e-commerce app using Flutter, I have implemented add to cart with the help of chatGPT since I'm new to it. Everything works okay, the only problem is that the counter on quantity isn't working, so if I press + to add, it won't add and same goes for -. Here's the code for the Cart Model, Cart Screen, and Cart Controller. I'm also using GetX for state management.
Cart Screen:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:exclusive_details_and_restorations/const/cart_controller.dart';
import 'package:exclusive_details_and_restorations/const/text.dart';
class CartScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CartController cartController = Get.find<CartController>();
print('CartScreen rebuilt');
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
const Color.fromRGBO(0, 40, 70, 100),
Colors.red.shade900,
],
),
),
child: Scaffold(
backgroundColor: const Color.fromRGBO(0, 40, 70, 100),
appBar: AppBar(
iconTheme: const IconThemeData(color: Colors.white),
backgroundColor: const Color.fromRGBO(0, 40, 70, 100),
title: const CustomText(
text: "Cart",
color: Colors.white,
),
actions: [
SizedBox(
width: 100,
child: Image.asset("assets/images/exclusive-details-rename.png"),
),
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Obx(
() => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: ListView.builder(
itemCount: cartController.cartItems.length,
itemBuilder: (context, index) {
var item = cartController.cartItems[index];
return ListTile(
title: CustomText(text: item.productName),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomText(text: "\$${item.price}"),
Row(
children: [
ElevatedButton(
onPressed: () {
// Decrease quantity
cartController.decreaseQuantity(item);
cartController.update();
},
child: const Icon(Icons.remove),
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0),
child: CustomText(
text: item.quantity.toString()),
),
ElevatedButton(
onPressed: () {
// Increase quantity
item.increaseQuantity();
cartController.update();
},
child: const Icon(Icons.add),
),
],
),
],
),
);
},
),
),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CustomText(
text: "Total: ",
size: 18,
fontWeight: FontWeight.bold,
),
CustomText(
text:
"\$${cartController.totalAmount.toStringAsFixed(2)}",
size: 18,
fontWeight: FontWeight.bold,
),
],
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// Implement the checkout logic here
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: CustomText(
text: "Proceed to Checkout",
size: 16,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
),
),
);
}
}
Cart Controller Code:
// controllers/cart_controller.dart
import 'package:exclusive_details_and_restorations/models/cart_model.dart';
import 'package:get/get.dart';
class CartController extends GetxController {
RxList<CartItem> cartItems = <CartItem>[].obs;
void addItem(CartItem newItem) {
int existingIndex = cartItems.indexWhere(
(item) => item.productName == newItem.productName,
);
if (existingIndex != -1) {
cartItems[existingIndex].quantity += 1;
} else {
cartItems.add(newItem);
}
}
void decreaseQuantity(CartItem item) {
if (item.quantity > 1) {
item.quantity -= 1;
} else {
cartItems.remove(item);
}
}
void clearCart() {
cartItems.clear();
}
double get totalAmount {
return cartItems.fold(0, (sum, item) => sum + item.totalPrice);
}
}
Cart Model Code:
// models/cart_model.dart
class CartItem {
final String productId;
final String productName;
final double price;
int quantity;
CartItem({
required this.productId,
required this.productName,
required this.price,
required this.quantity,
});
double get totalPrice => price * quantity;
void increaseQuantity() {
quantity += 1;
}
void decreaseQuantity() {
if (quantity > 1) {
quantity--;
}
}
}
Main File Code:
// main.dart
import 'package:exclusive_details_and_restorations/const/cart_controller.dart';
import 'package:exclusive_details_and_restorations/views/about_view.dart';
import 'package:exclusive_details_and_restorations/views/cart_view.dart';
import 'package:exclusive_details_and_restorations/views/gallery_view.dart';
import 'package:exclusive_details_and_restorations/views/home_view.dart';
import 'package:exclusive_details_and_restorations/views/service_areas.dart';
import 'package:exclusive_details_and_restorations/views/services.dart';
import 'package:exclusive_details_and_restorations/views/shop.dart';
import 'package:exclusive_details_and_restorations/views/splash.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
initialBinding: BindingsBuilder(() {
Get.put(CartController());
}),
routes: {
'/': (context) => const SplashScreen(),
'home': (context) => const HomeScreen(),
'about': (context) => const AboutView(),
'serviceAreas': (context) => const ServiceAreasView(),
'gallery': (context) => const GalleryView(),
'services': (context) => const ServicesView(),
'shop': (context) => EcommerceTest(),
'cart': (context) => CartScreen(),
},
);
}
}
An RxList
only notifies an Obx
to rebuild when items are added or removed, not when they are modified. You will need to call refresh()
on it to do it manually, like this:
void addItem(CartItem newItem) {
int existingIndex = cartItems.indexWhere(
(item) => item.productName == newItem.productName,
);
if (existingIndex != -1) {
cartItems[existingIndex].quantity += 1;
cartItems.refresh();
} else {
cartItems.add(newItem);
}
}
void decreaseQuantity(CartItem item) {
if (item.quantity > 1) {
item.quantity -= 1;
cartItems.refresh();
} else {
cartItems.remove(item);
}
}
Another option is to use a GetBuilder
instead of an Obx
. The call to cartController.update();
makes that one refresh. Right now your cartController.update();
doesn't have any effect since you don't use any GetBuilder
;