Flutter: keep the form view separate and simple with inherited widget

Veli Bacık
4 min readMar 20, 2023

Hello everyone! After many projects developed, I noticed sometimes business layer and view were confused due to some instance. Therefore, I am trying to change my mind and think of ways to code more efficiently. Let’s look at how we can do this.

Photo by Edward Howell on Unsplash

Before starting:

Maybe you can use many packages at this time or you saw that. If you put your UI instance in the business layer, it might appear okay but it is going to cause so many problems.

  • It is possible for any teammate to access this controller and do whatever they wish with it.
  • Your instance is mixed with your business and getting problems especially you just need to maybe value but you use a controller class It becomes more complex if you do something like testable.

We should decide: the UI layer should be separated and self-contained.

I focused on forms of business so we have many text editting controller, combo box etc but actually your business layer just need to data when every validation has done.

UI Side:

There is a name, surname, phone number, plate number, as well as the address text field with an action button for sending the service. So it means that I have to use at least six controllers, both to use and manage. When everything is okay, we need to make model.

SingleChildScrollView(
physics: const ClampingScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const _Header(),
const _CustomDivider(),
const VerticalSpace.standard(),
const _NameTextField(),
const VerticalSpace.standard(),
const _NameArrivedUserTextField(),
const VerticalSpace.standard(),
const _PhoneField(),
const VerticalSpace.standard(),
const _PlateTextField(),
const VerticalSpace.standard(),
const _AddressField(),
_ActionButton(
formKey: _formKey,
activeButtonValue: _activeButtonValue,
),
const VerticalSpace.small(),
],
),
),
...

At this time, I’m going to create own custom inherited widget. It is a useful and primary solution for like this page.

class CompleteDialogInherited extends InheritedWidget {
CompleteDialogInherited({
required super.child,
super.key,
});

static CompleteDialogInherited of(BuildContext context) {
final result =
context.dependOnInheritedWidgetOfExactType<CompleteDialogInherited>();
assert(result != null, 'No CompleteDialogInherited found in context');
return result!;
}

@override
bool updateShouldNotify(CompleteDialogInherited oldWidget) => true;

}

Many times we forget how to use primitive capabilities. Third-party packages, etc., are being implemented. If you have a change of primitive solution, I can always prefer this way.

After creating your own inherit component, you can accesses the every logic in the sub widget. So you do not need to send data across the page. There are many benefits to using it, especially if you have a complex page.

class _NameArrivedUserTextField extends StatelessWidget {
const _NameArrivedUserTextField();

@override
Widget build(BuildContext context) {
return Padding(
padding: const PagePadding.horizontalSymmetric(),
child: LabeledProductTextField(
controller: CompleteDialogInherited.of(context).nameArrivedController,
keyboardType: TextInputType.name,
formatters: [
FilteringTextInputFormatter.deny(RegExp('[0-9]')),
],
hintText: LocaleKeys.completeDialog_nameDelivered.tr(),
labelText: LocaleKeys.completeDialog_nameDelivered.tr(),
validator: (value) => ValidatorItems(value).validateFullName,
),
);
}
}

Business layer:

I’ve added dispose, and model logic in inherid widget class so i just call these logic when i need.

  • All bindings need to be discarded when the user closes the dialog.
  • When the user sends all content to the service, we will use the model creation method. So this sample is pretty basic, but you can implement your own business using this layer. It will provide better code separation and better usage.

After reviewing the requirements, our internal component should look like this.

Let’s take a look at the logic behind sending data. (And this case needs to be updated with form key usage, I missed this)

As you can see, we don’t need to call any 3.party methods or code. It will call CompleteDialogInherited. So it can be used easily in this view. By using this component, you can add new UI logic directly to your page without using any packages.

In other usage for dispose, we just calling directly this instance by using context.

 CompleteDialogInherited? _inherited;
// First need to add builder
Builder(
builder: (context) {
_inherited ??= CompleteDialogInherited.of(context);
...
}

@override
void dispose() {
super.dispose();
_inherited?.dispose();
}

That’s all. Especially after this time, we don’t put it in our logic anywhere and if we want anything, just add this class and provide

!!TURKEY EARTHQUAKE 7.8 AND 7.6

Turkey has recently been struck by a devastating earthquake with a magnitude of 7.8. The impact has been widespread and many communities have been severely affected. In this difficult time, we are reaching out to ask for your support. Any donation, no matter how small, will help us provide much-needed aid to those affected by the earthquake. Your generosity will help provide shelter, food, and medical supplies to those in need. Your contribution will make a real difference in the lives of those affected by this disaster. Thank you for your kindness and support.

You can donate for AHBAP with this site AHBAP_DONATE

--

--

Veli Bacık

We always change the world, so just want it. [OLD]Google Developer Expert Flutter & Dart, Gamer, Work More!