【问题标题】:how to update firestore database value correctly如何正确更新firestore数据库值
【发布时间】:2022-01-25 17:04:38
【问题描述】:

我正在努力在我的 Flutter 应用中构建基本的购物功能。我是编码和 Flutter 的新手。当用户单击 PlaceOrderPageContainer(按钮)以确认签出时,会调用 addOrderDetails() 方法,然后更新 Firebase 数据库。 Firestore 数据库中的所有内容都在正确更新,除了总金额被添加为零,无论购物车中的总金额如何。我在控制台中没有收到任何错误,但很明显我的代码没有正确编写。任何帮助将不胜感激。如果有帮助,我可以添加任何其他代码。

    class ShoppingCartPage extends StatefulWidget {
  const ShoppingCartPage({Key? key}) : super(key: key);

  @override
  _ShoppingCartPageState createState() => _ShoppingCartPageState();
}

class _ShoppingCartPageState extends State<ShoppingCartPage> {
  late double totalAmount;

  @override
  void initState() {
    super.initState();
    totalAmount = 0;
    Provider.of<TotalAmountProvider>(
      context,
      listen: false,
    ).display(0);
  }

  @override
  Widget build(BuildContext context) {
    return Consumer2<TotalAmountProvider, CartItemCounterProvider>(
      builder: (context, amountProvider, cartProvider, c) {
        return SafeArea(
          child: Scaffold(
            appBar: const ShoppingCartAppBar(),
            floatingActionButton: FloatingActionButton.extended(
              onPressed: () {
                if (ShoppingApp.sharedPreferences
                        .getStringList(
                          ShoppingApp.userCartList,
                        )
                        ?.length ==
                    1) {
                  Fluttertoast.showToast(msg: ToastString.cartEmpty);
                } else {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => AddressPage(
                        totalAmount: totalAmount,
                      ),
                    ),
                  );
                }
              },
              icon: const Icon(
                Icons.navigate_next,
              ),
              label: Text(
                ButtonString.checkOut.toUpperCase(),
              ),
            ),
            body: CustomScrollView(
              slivers: [
                SliverToBoxAdapter(
                  child:
                      Consumer2<TotalAmountProvider, CartItemCounterProvider>(
                    builder: (context, amountProvider, cartProvider, c) {
                      return Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Center(
                          child: cartProvider.count == 0
                              ? Container()
                              : Text(
                                  'Total Price: \$${amountProvider.totalAmount.toString()}',
                                  style: Theme.of(context).textTheme.headline6,
                                ),
                        ),
                      );
                    },
                  ),
                ),
                StreamBuilder<QuerySnapshot>(
                    stream: ShoppingApp.firestore
                        .collection('items')
                        .where('shortInfo',
                            whereIn: ShoppingApp.sharedPreferences
                                .getStringList(ShoppingApp.userCartList))
                        .snapshots(),
                    builder: (context, AsyncSnapshot snapshot) {
                      return !snapshot.hasData
                          ? const AdaptiveCircularProgressSliver()
                          : snapshot.data.docs.isEmpty
                              ? const EmptyShoppingCartContainer()
                              : SliverList(
                                  delegate: SliverChildBuilderDelegate(
                                    (context, index) {
                                      ItemModel model = ItemModel.fromJson(
                                        snapshot.data.docs[index].data(),
                                      );
                                      if (index == 0) {
                                        totalAmount = 0;
                                        // totalAmount = model.price! + totalAmount;
                                      } else {
                                        totalAmount =
                                            model.price! + totalAmount;
                                      }
                                      if (snapshot.data?.docs.length - 1 ==
                                          index) {
                                        WidgetsBinding.instance!
                                            .addPostFrameCallback((timeStamp) {
                                          Provider.of<TotalAmountProvider>(
                                                  context,
                                                  listen: false)
                                              .display(totalAmount);
                                        });
                                      }
                                      return sourceInfo(
                                        model,
                                        context,
                                        removeCartFunction: () =>
                                            removeItemFromUserCart(
                                          model.shortInfo as String,
                                        ),
                                      );
                                    },
                                    childCount: snapshot.hasData
                                        ? snapshot.data?.docs.length
                                        : 0,
                                  ),
                                );
                    }),
              ],
            ),
          ),
        );
      },
    );
  }

  Future<void> removeItemFromUserCart(
    String shortInfoAsID,
  ) async {
    List<String>? tempCartList = ShoppingApp.sharedPreferences.getStringList(
      ShoppingApp.userCartList,
    );
    tempCartList?.remove(shortInfoAsID);

    await ShoppingApp.firestore
        .collection(ShoppingApp.collectionUser)
        .doc(ShoppingApp.sharedPreferences.getString(
          ShoppingApp.userUID,
        ))
        .update({
      ShoppingApp.userCartList: tempCartList,
    }).then((value) {
      Fluttertoast.showToast(
        msg: ToastString.removeFromCart,
      );
      ShoppingApp.sharedPreferences.setStringList(
        ShoppingApp.userCartList,
        tempCartList as List<String>,
      );

      Provider.of<CartItemCounterProvider>(
        context,
        listen: false,
      ).displayResult();

      totalAmount = 0;
    });
  }
}

class AddressPage extends StatefulWidget {
  const AddressPage({
    Key? key,
    required this.totalAmount,
  }) : super(key: key);

  final double totalAmount;

  @override
  _AddressPageState createState() => _AddressPageState();
}

class _AddressPageState extends State<AddressPage> {
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: AdaptiveLayoutScaffold(
        appBar: const AddressPageAppBar(),
        floatingActionButton: const AddNewAddressFAB(),
        landscapeBodyWidget: Container(),
        portraitBodyWidget: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisSize: MainAxisSize.min,
          children: [
            const AddressPageHeadline(
              headlineText: ShoppingPageString.selectAddress,
            ),
            Consumer<AddressChangerProvider>(builder: (
              context,
              address,
              c,
            ) {
              return Flexible(
                child: StreamBuilder<QuerySnapshot>(
                    stream: ShoppingApp.firestore
                        .collection(ShoppingApp.collectionUser)
                        .doc(ShoppingApp.sharedPreferences
                            .getString(ShoppingApp.userUID))
                        .collection(ShoppingApp.subCollectionAddress)
                        .snapshots(),
                    builder: (context, snapshot) {
                      return !snapshot.hasData
                          ? const AdaptiveCircularProgressCenter()
                          : snapshot.data!.docs.isEmpty
                              ? const EmptyShippingAddressContainer()
                              : ListView.builder(
                                  itemCount: snapshot.data?.docs.length,
                                  shrinkWrap: true,
                                  itemBuilder: (context, index) {
                                    return AddressCard(
                                      addressID: snapshot.data?.docs[index].id
                                          as String,
                                      currentIndex: address.count,
                                      model: AddressModel.fromJson(
                                        snapshot.data?.docs[index].data()
                                            as Map<String, dynamic>,
                                      ),
                                      totalAmount: widget.totalAmount,
                                      value: index,
                                    );
                                  },
                                );
                    }),
              );
            }),
          ],
        ),
      ),
    );
  }
}

class AddressCard extends StatefulWidget {

  const AddressCard({
    Key? key,
    required this.addressID,
    required this.currentIndex,
    required this.model,
    required this.totalAmount,
    required this.value,
  }) : super(key: key);

  final String addressID;
  final int currentIndex;
  final AddressModel model;
  final double totalAmount;
  final int value;

  @override
  _AddressCardState createState() => _AddressCardState();
}

class _AddressCardState extends State<AddressCard> {
  @override
  Widget build(BuildContext context) {
    return AddressCardContainer(
      onTap: () {
        Provider.of<AddressChangerProvider>(
          context,
          listen: false,
        ).displayResult(widget.value);
      },
      addressCardColumn: AddressCardColumn(
        children: [
          Row(
            children: [
              AddressCardRadioButton(
                groupValue: widget.currentIndex,
                onChanged: (value) {
                  Provider.of<AddressChangerProvider>(
                    context,
                    listen: false,
                  ).displayResult(
                    value as int,
                  );
                },
                value: widget.value,
              ),
              AddressCardContent(
                city: widget.model.city as String,
                fullName: widget.model.name as String,
                phoneNumber: widget.model.phoneNumber as String,
                postalCode: widget.model.postalCode as String,
                state: widget.model.state as String,
                streetAddress: widget.model.streetAddress as String,
              ),
            ],
          ),
          widget.value == Provider.of<AddressChangerProvider>(context).count
              ? ShippingAddressProceedButton(
                  onPressed: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (
                          context,
                        ) =>
                            PlaceOrderPaymentPage(
                          addressID: widget.addressID,
                          totalAmount: widget.totalAmount,
                        ),
                      ),
                    );
                  },
                )
              : Container(),
        ],
      ),
    );
  }
}

class PlaceOrderPaymentPage extends StatefulWidget {
  const PlaceOrderPaymentPage({
    Key? key,
    required this.addressID,
    required this.totalAmount,
  }) : super(key: key);

  final String addressID;
  final double totalAmount;

  @override
  _PlaceOrderPaymentPageState createState() => _PlaceOrderPaymentPageState();
}

class _PlaceOrderPaymentPageState extends State<PlaceOrderPaymentPage> {
  @override
  Widget build(BuildContext context) {
    return AdaptiveLayoutScaffold(
      appBar: const PlaceOrderPaymentPageAppBar(),
      landscapeBodyWidget: Container(),
      portraitBodyWidget: PlaceOrderPageContainer(
        orderOnPressed: () => addOrderDetails(),
      ),
    );
  }

  void addOrderDetails() {
    final time = DateTime.now().millisecondsSinceEpoch;

    writeOrderDetailsForUser({
      ShoppingApp.addressID: widget.addressID,
      ShoppingApp.totalAmount: widget.totalAmount,
      'orderBy': ShoppingApp.sharedPreferences.getString(
        ShoppingApp.userUID,
      ),
      ShoppingApp.productID: ShoppingApp.sharedPreferences.getStringList(
        ShoppingApp.userCartList,
      ),
      ShoppingApp.paymentDetails: ShoppingPageString.cashOnDelivery,
      ShoppingApp.orderTime: time.toString(),
      ShoppingApp.isSuccess: true,
    });

    writeOrderDetailsForAdmin({
      ShoppingApp.addressID: widget.addressID,
      ShoppingApp.totalAmount: widget.totalAmount,
      'orderBy': ShoppingApp.sharedPreferences.getString(
        ShoppingApp.userUID,
      ),
      ShoppingApp.productID: ShoppingApp.sharedPreferences.getStringList(
        ShoppingApp.userCartList,
      ),
      ShoppingApp.paymentDetails: ShoppingPageString.cashOnDelivery,
      ShoppingApp.orderTime: time.toString(),
      ShoppingApp.isSuccess: true,
    }).whenComplete(() => {
          emptyCartNow(),
        });
  }

  void emptyCartNow() {
    ShoppingApp.sharedPreferences.setStringList(ShoppingApp.userCartList, [
      'garbageValue',
    ]);
    List<String>? tempList = ShoppingApp.sharedPreferences.getStringList(
      ShoppingApp.userCartList,
    );

    FirebaseFirestore.instance
        .collection('users')
        .doc(ShoppingApp.sharedPreferences.getString(
          ShoppingApp.userUID,
        ))
        .update({
      ShoppingApp.userCartList: tempList,
    }).then((value) {
      ShoppingApp.sharedPreferences.setStringList(
        ShoppingApp.userCartList,
        tempList as List<String>,
      );
      Provider.of<CartItemCounterProvider>(
        context,
        listen: false,
      ).displayResult();
    });
    Fluttertoast.showToast(
      msg: ToastString.orderPlacedSuccessfully,
    );
    Navigator.pushReplacement(
      context,
      MaterialPageRoute(
        builder: (context) => const ShoppingPage(),
      ),
    );
  }

  Future<void> writeOrderDetailsForUser(
    Map<String, dynamic> data,
  ) async {
    await ShoppingApp.firestore
        .collection(ShoppingApp.collectionUser)
        .doc(ShoppingApp.sharedPreferences.getString(ShoppingApp.userUID))
        .collection(ShoppingApp.collectionOrders)
        .doc(
          ShoppingApp.sharedPreferences.getString(ShoppingApp.userUID)! +
              data['orderTime'],
        )
        .set(data);
  }

  Future<void> writeOrderDetailsForAdmin(Map<String, dynamic> data) async {
    await ShoppingApp.firestore
        .collection(ShoppingApp.collectionOrders)
        .doc(
          ShoppingApp.sharedPreferences.getString(ShoppingApp.userUID)! +
              data['orderTime'],
        )
        .set(data);
  }
}


class CartItemCounterProvider extends ChangeNotifier {
  final int _counter = (ShoppingApp.sharedPreferences
              .getStringList(
                ShoppingApp.userCartList,
              )
              ?.length ??
          0) -
      1;
  int get count => _counter;

  Future<void> displayResult() async {
    
    int _counter = (ShoppingApp.sharedPreferences
                .getStringList(
                  ShoppingApp.userCartList,
                )
                ?.length ??
            0) -
        1;

    await Future.delayed(
        const Duration(
          milliseconds: 100,
        ), () {
      notifyListeners();
    });
  }
}

【问题讨论】:

  • 您能否添加代码 sn-p 来说明您如何调用此 PaymentPage 小部件
  • @YanniTheDeveloper。我在上面添加了更多代码,希望包括您正在寻找的内容。谢谢。
  • 我很清楚你有一个状态管理问题,我不能只通过代码调试它。如果你想让我帮你放大,你可以在这里留下你的电子邮件。例如,在设置 => totalAmount = 0; 之后,我有一个 Q;你为什么用model.price添加它? => 总金额 = 型号.价格! + 总金额;
  • @YanniTheDeveloper。感谢您花时间查看代码和评论。关于将 totalAmount 设置为 0 并添加价格的问题的答案是购物车默认具有“垃圾值”。因此,在代码中,目标是为 0 索引分配总量 0。然后我尝试在指数为 1 或更大时将价格添加到总金额。如果您要问的话,在“if”中设置 totalAmount = model.price +totalAmount 可能没有意义。

标签: firebase flutter dart google-cloud-firestore sharedpreferences


【解决方案1】:

CartCheckOutFAB 首先总是用值 0 实例化,因为 ShoppingCartPage 状态没有改变。 您可以尝试移动 Consumer2 作为 AdaptiveLayoutScaffold 的父级,并使用 amountProvider.totalAmount 实例化 CartCheckOutFAB >

  • 如果它不起作用,您能否提供 CartCheckOutFAB 小部件类。

【讨论】:

  • 我更新了上面的代码以包含 CartCheckOutFAB 类。今天下午我将测试您的更改。我非常感谢您的所有帮助。
  • 我用更新版本的 ShoppingCart 替换了原始代码,其中包含您关于移动消费者的建议。同时,我将 CartCheckOutFAB 作为自定义小部件移除,并将其移动到购物车中,以便您可以看到代码。我还添加了 TotalAmount 和 CartItemCounter 提供程序以及地址卡,因此您不必猜测代码的不同部分。我很困惑为什么你建议的改变没有改变行为。我一定是从您之前看到的代码中出错了。再次感谢您的帮助。
  • 第一次删除 SliverToBoxAdapter 中的 Consumer,作为它的副本,第二次在 MaterialPageRoute 中使用 AddressPage(totalAmount: amountProvider.totalAmount,)。 3rd尝试在断点的帮助下检查所有类中totalAmount的值或打印到控制台。或使用 Provider.of( context).totalAmount 同时将 totalAmount 传递给 AddressCardState 中的 PlaceOrderPaymentPage()
  • 感谢您的大力帮助。我会一步一步地按照你的建议,让你知道它是怎么回事。我迅速打印到控制台,并立即看到当 FAB 在购物车中按下时,总金额值为 0,因此您的想法将使我能够指出哪里出了问题。这很棒!在你建议之前,我显然没想过这样做。
  • 好的,我很高兴它给了你一个线索!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-14
  • 1970-01-01
  • 2021-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多