skip to Main Content

I get this error when build the page:

E/flutter ( 6971): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: setState() or markNeedsBuild() called during build.
E/flutter ( 6971): This Obx widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
E/flutter ( 6971): The widget on which setState() or markNeedsBuild() was called was:
E/flutter ( 6971): Obx
E/flutter ( 6971): The widget which was currently being built when the offending call was made was:
E/flutter ( 6971): RawGestureDetector-[LabeledGlobalKey#42d00]

the page is:

import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:get/get.dart';

import '../controllers/checkout_controller.dart';

class CheckoutView extends GetView<CheckoutController> {
  @override
  const CheckoutView({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Finalizar Pedido'),
          centerTitle: true,
        ),
        body: SingleChildScrollView(
          child: GetBuilder<CheckoutController>(builder: (controller) {
            if (controller.isLoading) {
              // Show loading indicator or placeholder while data is being fetched
              return const Center(child: CircularProgressIndicator());
            } else {
              // Build the checkout UI using the fetched data
              final billingAddress = controller.addressesController.billing;
              final shippingAddress = controller.addressesController.shipping;

              return Column(
                children: [
                  const ListTile(
                    title: Text(
                      'Endereço de Cobrança:',
                      style: TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                  ListTile(
                    title: Text(
                      '${billingAddress['address_1']}, ${billingAddress['address_2']}n'
                      '${billingAddress['city']}, ${billingAddress['state']}n'
                      '${billingAddress['postcode']}',
                    ),
                  ),
                  const SizedBox(height: 16),
                  const ListTile(
                    title: Text(
                      'Endereço de entrega:',
                      style: TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                  ListTile(
                    title: Text(
                      '${shippingAddress['address_1']}, ${shippingAddress['address_2']}n'
                      '${shippingAddress['city']}, ${shippingAddress['state']}n'
                      '${shippingAddress['postcode']}',
                    ),
                  ),
                  const ListTile(
                    title: Text(
                      'Pagamento',
                      style: TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                  ListView.builder(
                    shrinkWrap: true,
                    physics: const BouncingScrollPhysics(),
                    itemCount: controller.paymentMethods.length,
                    itemBuilder: (context, index) {
                      final paymentMethod = controller.paymentMethods[index];
                      return RadioListTile(
                        title: Text(paymentMethod.title),
                        subtitle: Html(data: paymentMethod.description),
                        value: paymentMethod.id,
                        groupValue: controller.selectedPaymentMethod,
                        onChanged: (value) =>
                            controller.setSelectedPaymentMethod(value),
                      );
                    },
                  ),
                  const ListTile(
                    title: Text(
                      'Frete',
                      style: TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                  const ListTile(
                    title: Text('Frete grátis.'),
                  ),
                  const ListTile(
                    title: Text(
                      'Observações',
                      style: TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Container(
                      decoration: BoxDecoration(
                        border: Border.all(
                          color: Colors.grey,
                          width: 1.0,
                        ),
                        borderRadius: BorderRadius.circular(4.0),
                      ),
                      child: TextFormField(
                        decoration: const InputDecoration(
                          labelText: 'Suas observações sobre o pedido',
                          border: InputBorder
                              .none, // Remove the default border from the input field
                          contentPadding: EdgeInsets.symmetric(
                              horizontal: 10.0, vertical: 8.0),
                        ),
                        onChanged: (value) => controller.setCustomerNote(value),
                      ),
                    ),
                  ),
                  ElevatedButton(
                    onPressed: () => controller.doCheckout(),
                    child: const Text('Finalizar pedido'),
                  )
                ],
              );
            }
          }),
        ));
  }
}

Already tried to comment parts of code;

Already used Obx instead GetBuilder;

I’m not using any Obs vars;

I don’t understand why it gets error!!

2

Answers


  1. Chosen as BEST ANSWER
        import 'package:flutter/material.dart';
    import 'package:flutter_html/flutter_html.dart';
    import 'package:get/get.dart';
    import 'package:logger/logger.dart';
    
    import '../controllers/checkout_controller.dart';
    
    class CheckoutView extends StatelessWidget {
      @override
      CheckoutView({super.key});
      CheckoutController controller = Get.put(CheckoutController());
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Finalizar Pedido'),
            centerTitle: true,
          ),
          body: SingleChildScrollView(
            child: GetBuilder<CheckoutController>(builder: (_) {
              Logger().d(controller.isLoading);
              if (controller.isLoading) {
                // Show loading indicator or placeholder while data is being fetched
                return const Center(child: CircularProgressIndicator());
              } else {
                // Build the checkout UI using the fetched data
                final billingAddress = controller.billing;
                final shippingAddress = controller.shipping;
    
                return Column(
                  children: [
                    const ListTile(
                      title: Text(
                        'Endereço de Cobrança:',
                        style: TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                    ListTile(
                      title: Text(
                        '${billingAddress['address_1']}, ${billingAddress['address_2']}n'
                        '${billingAddress['city']}, ${billingAddress['state']}n'
                        '${billingAddress['postcode']}',
                      ),
                    ),
                    const SizedBox(height: 16),
                    const ListTile(
                      title: Text(
                        'Endereço de entrega:',
                        style: TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                    ListTile(
                      title: Text(
                        '${shippingAddress['address_1']}, ${shippingAddress['address_2']}n'
                        '${shippingAddress['city']}, ${shippingAddress['state']}n'
                        '${shippingAddress['postcode']}',
                      ),
                    ),
                    const ListTile(
                      title: Text(
                        'Pagamento',
                        style: TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                    ListView.builder(
                      shrinkWrap: true,
                      physics: const BouncingScrollPhysics(),
                      itemCount: controller.paymentMethods.length,
                      itemBuilder: (context, index) {
                        final paymentMethod = controller.paymentMethods[index];
                        return RadioListTile(
                          title: Text(paymentMethod.title),
                          subtitle: Html(data: paymentMethod.description),
                          value: paymentMethod.id,
                          groupValue: controller.selectedPaymentMethod,
                          onChanged: (value) =>
                              controller.setSelectedPaymentMethod(value),
                        );
                      },
                    ),
                    const ListTile(
                      title: Text(
                        'Frete',
                        style: TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                    const ListTile(
                      title: Text('Frete grátis.'),
                    ),
                    const ListTile(
                      title: Text(
                        'Observações',
                        style: TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Container(
                        decoration: BoxDecoration(
                          border: Border.all(
                            color: Colors.grey,
                            width: 1.0,
                          ),
                          borderRadius: BorderRadius.circular(4.0),
                        ),
                        child: TextFormField(
                          decoration: const InputDecoration(
                            labelText: 'Suas observações sobre o pedido',
                            border: InputBorder
                                .none, // Remove the default border from the input field
                            contentPadding: EdgeInsets.symmetric(
                                horizontal: 10.0, vertical: 8.0),
                          ),
                          // onChanged: (value) => controller.setCustomerNote(value),
                        ),
                      ),
                    ),
                    ElevatedButton(
                      onPressed: () => controller.doCheckout(),
                      child: const Text('Finalizar pedido'),
                    )
                  ],
                );
              }
            }),
          ),
        );
      }
    }
    

    and in checkout_controller.dart:

    import 'package:flutter/material.dart';
    import 'package:get/get.dart';
    import 'package:logger/logger.dart';
    import 'package:polina/services/api_service.dart';
    import 'package:wp_json_api/models/responses/wp_user_info_response.dart' as md;
    
    class CheckoutController extends GetxController {
      final ApiService apiService = Get.find();
      late Map<String, dynamic> checkoutData;
      late List<dynamic> paymentMethods;
      String selectedPaymentMethod = 'cod';
      String customerNote = '';
      bool isLoading = true;
      var billing = {};
      var shipping = {};
    
      @override
      void onInit() {
        fetchCheckoutData();
        super.onInit();
      }
    
      @override
      void onReady() {
        super.onReady();
      }
    
      @override
      void onClose() {
        super.onClose();
      }
    
      fetchCheckoutData() async {
        isLoading = true;
        update();
        paymentMethods = await apiService.getPaymentMethod();
        checkoutData = await apiService.getCheckout();
        await loadAddresses();
        isLoading = false;
        update();
      }
    
      Future<void> loadAddresses() async {
        var u = await apiService.getUserInfo();
        List<md.MetaData>? m = u.data?.metaData;
        billing['first_name'] = m
            ?.firstWhere((element) => element.key == 'billing_first_name')
            .value![0];
        billing['last_name'] = m
            ?.firstWhere((element) => element.key == 'billing_last_name')
            .value![0];
        billing['company'] =
            m?.firstWhere((element) => element.key == 'billing_company').value![0];
        billing['address_1'] = m
            ?.firstWhere((element) => element.key == 'billing_address_1')
            .value![0];
        billing['address_2'] = m
            ?.firstWhere((element) => element.key == 'billing_address_2')
            .value![0];
        billing['city'] =
            m?.firstWhere((element) => element.key == 'billing_city').value![0];
        billing['postcode'] =
            m?.firstWhere((element) => element.key == 'billing_postcode').value![0];
        billing['country'] =
            m?.firstWhere((element) => element.key == 'billing_country').value![0];
        billing['state'] =
            m?.firstWhere((element) => element.key == 'billing_state').value![0];
        //shipping
        shipping['first_name'] = m
            ?.firstWhere((element) => element.key == 'shipping_first_name')
            .value![0];
        shipping['last_name'] = m
            ?.firstWhere((element) => element.key == 'shipping_last_name')
            .value![0];
        shipping['company'] =
            m?.firstWhere((element) => element.key == 'shipping_company').value![0];
        shipping['address_1'] = m
            ?.firstWhere((element) => element.key == 'shipping_address_1')
            .value![0];
        shipping['address_2'] = m
            ?.firstWhere((element) => element.key == 'shipping_address_2')
            .value![0];
        shipping['city'] =
            m?.firstWhere((element) => element.key == 'shipping_city').value![0];
        shipping['postcode'] = m
            ?.firstWhere((element) => element.key == 'shipping_postcode')
            .value![0];
        shipping['country'] =
            m?.firstWhere((element) => element.key == 'shipping_country').value![0];
        shipping['state'] =
            m?.firstWhere((element) => element.key == 'shipping_state').value![0];
        Logger().d(billing.toString());
        Logger().d(shipping.toString());
      }
    
      void setSelectedPaymentMethod(String value) {
        selectedPaymentMethod = value;
        update();
      }
    
      void setCustomerNote(String value) {
        customerNote = value;
      }
    
      doCheckout() async {
        isLoading = true;
        var checkout2 = {
          "billing_address": billing,
          "shipping_address": shipping,
          "customer_note": customerNote,
          "create_account": false,
          "payment_method": selectedPaymentMethod,
          "payment_data": [],
          "shipping_lines": [
            {
              "method_id": "free_shipping",
              "method_title": "Frete grátis",
              "total": 0
            }
          ]
        };
        apiService.doCheckout(checkout2).then((order) {
          isLoading = false;
          Get.snackbar(
            'Sucesso',
            'Pedido realizado.',
            snackPosition: SnackPosition.BOTTOM,
            backgroundColor: Colors.green,
            colorText: Colors.white,
          );
          //go to order details passing order id
          Get.offNamedUntil(
            '/order',
            ModalRoute.withName('/'),
            arguments: {'id': order['order_id']},
          );
        });
      }
    }
    

  2. Try this ->

    class CheckoutView extends GetView<CheckoutController> {
      @override
      const CheckoutView({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Finalizar Pedido'),
            centerTitle: true,
          ),
          body: SingleChildScrollView(
            child: Builder(
              builder: (context) {
                if (controller.isLoading) {
                  // Show loading indicator or placeholder while data is being fetched
                  return const Center(child: CircularProgressIndicator());
                } else {
                  // Build the checkout UI using the fetched data
                  final billingAddress = controller.addressesController.billing;
                  final shippingAddress = controller.addressesController.shipping;
    
                  return Column(
                    children: [
                      const ListTile(
                        title: Text(
                          'Endereço de Cobrança:',
                          style: TextStyle(
                            fontSize: 18,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                      ),
                      ListTile(
                        title: Text(
                          '${billingAddress['address_1']}, ${billingAddress['address_2']}n'
                          '${billingAddress['city']}, ${billingAddress['state']}n'
                          '${billingAddress['postcode']}',
                        ),
                      ),
                      const SizedBox(height: 16),
                      const ListTile(
                        title: Text(
                          'Endereço de entrega:',
                          style: TextStyle(
                            fontSize: 18,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                      ),
                      ListTile(
                        title: Text(
                          '${shippingAddress['address_1']}, ${shippingAddress['address_2']}n'
                          '${shippingAddress['city']}, ${shippingAddress['state']}n'
                          '${shippingAddress['postcode']}',
                        ),
                      ),
                      const ListTile(
                        title: Text(
                          'Pagamento',
                          style: TextStyle(
                            fontSize: 18,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                      ),
                      ListView.builder(
                        shrinkWrap: true,
                        physics: const BouncingScrollPhysics(),
                        itemCount: controller.paymentMethods.length,
                        itemBuilder: (context, index) {
                          final paymentMethod = controller.paymentMethods[index];
                          return RadioListTile(
                            title: Text(paymentMethod.title),
                            subtitle: Html(data: paymentMethod.description),
                            value: paymentMethod.id,
                            groupValue: controller.selectedPaymentMethod,
                            onChanged: (value) =>
                                controller.setSelectedPaymentMethod(value),
                          );
                        },
                      ),
                      const ListTile(
                        title: Text(
                          'Frete',
                          style: TextStyle(
                            fontSize: 18,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                      ),
                      const ListTile(
                        title: Text('Frete grátis.'),
                      ),
                      const ListTile(
                        title: Text(
                          'Observações',
                          style: TextStyle(
                            fontSize: 18,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Container(
                          decoration: BoxDecoration(
                            border: Border.all(
                              color: Colors.grey,
                              width: 1.0,
                            ),
                            borderRadius: BorderRadius.circular(4.0),
                          ),
                          child: TextFormField(
                            decoration: const InputDecoration(
                              labelText: 'Suas observações sobre o pedido',
                              border: InputBorder
                                  .none, // Remove the default border from the input field
                              contentPadding: EdgeInsets.symmetric(
                                  horizontal: 10.0, vertical: 8.0),
                            ),
                            onChanged: (value) => controller.setCustomerNote(value),
                          ),
                        ),
                      ),
                      ElevatedButton(
                        onPressed: () => controller.doCheckout(),
                        child: const Text('Finalizar pedido'),
                      ),
                    ],
                  );
                }
              },
            ),
          ),
        );
      }
    }
    

    I don’t have all the context, but if it works(which I think it should), then the issue is GetView Updates itself automagically whenever your controller gets an update. But if you create another GetBuilder inside it, They both try to update the view at the same time. Then this issue occurs.

    Again, from what I am seeing this should be the issue. Unless there’s some top-level parent issue you’re facing.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search