skip to Main Content

I am trying to create a form page and it contains multiple widgets like FreeTextForm and DropdownButtonFormField. Data for drop down is fetched from sqlite using sqflite.
The issue happen if I interact with the drop down after I interact with text form, but if I interact with drop down first then go to text form the issue will not appear (it will appear if after interact with text form I interact back with drop down).

Here is the code for the form page

class ActivityFormPage extends StatelessWidget {
  const ActivityFormPage({super.key});

  @override
  Widget build(BuildContext context) {
    final ActivityController c = Get.put(
      ActivityController(
        id: Get.arguments["id"],
        db: Get.find<DBInstance>().database,
      ),
    );

    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          onPressed: () => Get.back(),
          icon: const Icon(
            Icons.arrow_back,
          ),
        ),
        title: Text(
          "New Activity",
          textAlign: TextAlign.left,
          style: context.textTheme.titleLarge,
        ),
      ),
      body: SafeArea(
        child: SingleChildScrollView(
          child: Padding(
            padding: EdgeInsets.all(UIConst.standardPadding * 2),
            child: Column(
              children: [
                Form(
                  key: c.newActivityKey,
                  child: Column(
                    children: [
                      CustomFreeTextForm(
                        label: "Title",
                        hint: "Write activity title",
                        state: c.state.title,
                        maxLines: 1,
                      ),
                      SizedBox(
                        height: UIConst.standardGapHeight * 2,
                      ),
                      CustomDropDownForm<CategoryModel>(
                        label: "Category",
                        hint: "Select category",
                        noDataHint: "No category available",
                        itemArray: c.getAllCategories(),
                        state: c.state.categoryId,
                        isDisabled: false,
                      ),
                      SizedBox(
                        height: UIConst.standardGapHeight * 2,
                      ),
                      Obx(() {
                        return CustomDropDownForm<SubCategoryModel>(
                          label: "Sub Category",
                          hint: "Select sub category",
                          noDataHint: "No sub category available",
                          itemArray: c.getAllSubCategories(
                            c.state.categoryId.toInt(),
                          ),
                          state: c.state.subCategoryId,
                          isDisabled: c.state.categoryId.toInt() == 0,
                        );
                      }),
                      SizedBox(
                        height: UIConst.standardGapHeight * 2,
                      ),
                      Row(
                        children: [
                          CustomTimePicker(
                            width: MediaQuery.of(context).size.width * 0.4,
                            label: "Start time",
                            hint: "Select start time",
                            state: c.state.startTime,
                            onChange: c.formatDisplayTime,
                          ),
                          const Expanded(
                            flex: 1,
                            child: SizedBox(),
                          ),
                          CustomTimePicker(
                            width: MediaQuery.of(context).size.width * 0.4,
                            label: "End time",
                            hint: "Select end time",
                            state: c.state.endTime,
                            onChange: c.formatDisplayTime,
                          ),
                        ],
                      ),
                      SizedBox(
                        height: UIConst.standardGapHeight * 2,
                      ),
                      CustomFreeTextForm(
                        label: "Description",
                        hint: "Write description",
                        state: c.state.description,
                        maxLines: 5,
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

and here is the code of the CustomDropDownForm

class CustomDropDownForm<T extends BaseModel> extends StatelessWidget {
  final String label;
  final String hint;
  final String noDataHint;
  final Future<List<T>> itemArray;
  final RxInt state;
  final bool isDisabled;

  const CustomDropDownForm({
    super.key,
    required this.label,
    required this.hint,
    required this.noDataHint,
    required this.itemArray,
    required this.state,
    required this.isDisabled,
  });

  @override
  Widget build(BuildContext context) {
    return AbsorbPointer(
      absorbing: isDisabled,
      child: Opacity(
        opacity: isDisabled ? 0.5 : 1.0,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              label,
              style: context.textTheme.bodySmall,
            ),
            SizedBox(
              height: UIConst.standardGapHeight,
            ),
            FutureBuilder<List<T>>(
              future: itemArray,
              builder: (context, snapshot) {
                if (snapshot.hasData && snapshot.data!.isNotEmpty) {
                  return DropdownButtonFormField<int>(
                    value: null,
                    items: snapshot.data!.map((e) {
                      return DropdownMenuItem(
                        value: e.id,
                        child: Text(
                          e.name,
                          style: context.textTheme.bodyMedium,
                        ),
                      );
                    }).toList(),
                    onChanged: isDisabled
                        ? null
                        : (value) {
                            state.value = value!;
                          },
                    hint: Text(
                      hint,
                      style: context.textTheme.bodyMedium!.copyWith(
                        color: state.value == 0 ? Colors.black : Colors.grey,
                      ),
                    ),
                    decoration: dropDownButtonDecoration,
                    elevation: 0,
                  );
                } else {
                  return DropdownButtonFormField(
                    value: null,
                    items: const [],
                    onChanged: null,
                    hint: Text(noDataHint),
                    decoration: dropDownButtonDecoration,
                  );
                }
              },
            ),
          ],
        ),
      ),
    );
  }
}

This is the error looks like

enter image description here

The expectation is that when I interact with the CustomDropDownForm after interact with other widgets, no issue arises and the drop down items are shown

2

Answers


  1. Get.arguments is not null and that it contains the key you’re trying to access. You can do this by performing a null check before accessing the value.

    final id = Get.arguments?["id"];
    final ActivityController c = Get.put(
      ActivityController(
        id: id,
        db: Get.find<DBInstance>().database,
      ),
    );
    
    Login or Signup to reply.
  2. The error message indicates that you’re trying to access the "id" key
    on a null object. This typically happens when you’re trying to access
    a value from a Map that doesn’t exist. To fix this, you need to ensure
    that you’re accessing the Map correctly and that it’s not null.

    In your code, it seems that you’re accessing the "id" key from the
    Get.arguments Map. However, you haven’t provided a default value or
    handled the case where Get.arguments is null. Let’s fix this by
    providing a default value for the "id" key or handling the null case.

    Try below code, it will not crash if the argument is null

        class ActivityFormPage extends StatelessWidget {
      const ActivityFormPage({Key? key});
    
      @override
      Widget build(BuildContext context) {
        final Map<String, dynamic>? arguments = Get.arguments;
        final int? id = arguments?["id"] as int?;
    
        final ActivityController c = Get.put(
          ActivityController(
            id: id,
            db: Get.find<DBInstance>().database,
          ),
        );
    
        return Scaffold(
          appBar: AppBar(
            leading: IconButton(
              onPressed: () => Get.back(),
              icon: const Icon(
                Icons.arrow_back,
              ),
            ),
            title: Text(
              "New Activity",
              textAlign: TextAlign.left,
              style: context.textTheme.titleLarge,
            ),
          ),
          body: SafeArea(
            child: SingleChildScrollView(
              child: Padding(
                padding: EdgeInsets.all(UIConst.standardPadding * 2),
                child: Column(
                  children: [
                    Form(
                      key: c.newActivityKey,
                      child: Column(
                        children: [
                          // Your form fields...
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        );
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search