DEV Community

Curtly Critchlow
Curtly Critchlow

Posted on

How to reuse form field widget to add and update cloud firestore documents - #100DaysOfCode - Day 17

Introduction

This post is part of my 100DaysOfCode series. In this series, I write about what I am learning on this challenge. For this challenge, I will be learning flutter and firebase by building an Agriculture Management Information System.

Recap

On Day 16 we discussed how to reuse a screen widget to personalize our app for the currently signed-in user.

Overview

In this post, we'll discuss how to use our farmer form screen to add and update cloud firestore documents. We have already implemented the Add functionality so we will focus on the update functionality.

Location Filter Enum

The first step is to create a Farm Type enum. enum FarmType { add, update }. This enum value will be passed to the FarmerFormScreen() widget to modify the screen into an add farmer form and an update farmer form.

class FarmerFormScreen extends StatefulWidget {
  static String routeName = 'AddFarmerScreen';
  final FarmerServiceModel? farmerModel;
  final FormType formType;
  FarmerFormScreen({
    this.farmerModel,
    required this.formType,
    Key? key,
  }) : super(key: key);

  @override
  _FarmerFormScreenController createState() => _FarmerFormScreenController();
}
Enter fullscreen mode Exit fullscreen mode

This widget accepts an optional final FarmerServiceModel? farmerModel; that will be used to update the farmer document.

Text Form Field widget with Controller

class _FarmerFormScreenController extends State<FarmerFormScreen> {
  @override
  Widget build(BuildContext context) => _FarmerFormScreenView(this);
  late TextEditingController dateOfBirthController;

  @override
  void initState() {
    super.initState();

    dateOfBirthController = TextEditingController();
    if (widget.formType == FormType.update) {
      dateOfBirthController = TextEditingController(
          text: DateFormat.yMMMd().format(widget.farmerModel!.dateOfBirth!));
    } else {
      dateOfBirthController = TextEditingController();
    }
  }
Enter fullscreen mode Exit fullscreen mode

The date of birth text form field initial value will be null when adding a farmer and the farmer date of birth when updating a farmer document.

Text Form Field widget without controller

 class LastNameTextFormField extends StatelessWidget {
  const LastNameTextFormField({
    Key? key,
    required this.state,
  }) : super(key: key);

  final _FarmerFormScreenController state;

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      decoration: FormStyles.textFieldDecoration(labelText: 'Last Name'),
      focusNode: state.lastNameFocusNode,
      textInputAction: TextInputAction.next,
      autovalidateMode: AutovalidateMode.onUserInteraction,
      validator: state.farmer.validateRequiredField,
      onSaved: state.farmer.saveLastName,
      initialValue: state.widget.formType == FormType.update
          ? state.widget.farmerModel!.lastName
          : null,
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

The initialValue is assigned the farmer document lastname value if state.widget.formType == FormType.update and null otherwise. This same methodology was repeated for all other form field widgets.

Wrap Up

In this post, we discussed how to reuse our farmer form screen widget to add and update a farmer document.

Connect with me

Thank you for reading my post. Feel free to subscribe below to join me on the #100DaysOfCodeChallenge or connect with me on LinkedIn and Twitter. You can also buy me a book to show your support.

Oldest comments (2)

Collapse
 
rlizano19 profile image
rlizanog
class _FarmerFormScreenController extends State<FarmerFormScreen> {
  @override
  Widget build(BuildContext context) => _FarmerFormScreenView(this);
  late TextEditingController dateOfBirthController;
Enter fullscreen mode Exit fullscreen mode

Can you elaborate on _FarmerFormScreenView? Not sure what to add in my case.

Collapse
 
curtlycritchlow profile image
Curtly Critchlow

Sure, Instead of returning a scaffold and the other widget that will make up the FarmFormScreen I returned a _FarmerFormScreenView. This class is passed the entire State object. This is done to create an extra layer of separation between my code logic and my UI. I am now free to swap out the _FarmerFormScreenView for a _FarmerFormScreenMobileView etc and all my different views (UI) will have access to my code logic.