Danh mụcThẻBài viết

admin

I'm a Full-stack developer

Thẻ

Linked List
Data Structure
Chat GPT
Design Pattern
Microservices
API
AWS CDK
ReactJS
AWS Lightsail
Flutter Mobile
Form validator in Flutter with EzValidator
Ngày đăng: 04/01/2024

When I am working on Flutter with form. For ensuring data integrity, and handling user input errors. I want to show an error message below each TextField, Dropdown, Switch, ... if the user does not input or wrong input. The EzValidator help me to resolve this issue.


In this article, we will explore how to validate user inputs in Flutter with the EzValidator package.


Contents

  1. Prerequisites
  2. Implementation
  3. Demo


Prerequisites

Ensure the VSCode and Flutter are installed on your local. If not installed yet, you should follow up below steps:


  • Download and install VSCode here
  • Download and install Flutter here
  • Set up the VSCode editor to complete, deploy, and debug the app here


Implementation

Create a new application
$ flutter create ez_validator_example


Navigate to the new project

main.dart
import 'package:EzValidatorExample/app.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(App());
}


app.dart
import 'package:EzValidatorExample/my_address.dart';
import 'package:flutter/material.dart';

class App extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'EzValidator Example',
      theme: ThemeData(),
      home: const MyAddressScreen(title: 'EzValidator Example'),
    );
  }
}


Install EzValidator package
$ flutter pub add ez_validator


pubspec.yaml
dependencies:
  ez_validator: ^0.3.1


Define a new schema object with name is address_schema.dart
import 'package:ez_validator/ez_validator.dart';

class AddressSchema {
  static EzSchema upsertSchema = EzSchema.shape(
    {
      'email': EzValidator<String>(optional: true)
          .email("Email không đúng định dạng"),
      'fullName': EzValidator<String>().required(
        "Trường này không được bỏ trống",
      ),
      'province': EzValidator<String>().number().required(
            "Trường này không được bỏ trống",
          ),
      'district': EzValidator<String>().number().required(
            "Trường này không được bỏ trống",
          ),
      'ward': EzValidator<String>().number().required(
            "Trường này không được bỏ trống",
          ),
      'streetAddress': EzValidator<String>().required(
        "Trường này không được bỏ trống",
      ),
      'phoneNumber': EzValidator<String>().phone(),
      'note': EzValidator<String>(),
      'isDefault': EzValidator<bool>(defaultValue: false).boolean(),
    },
  );
}


Create my address screen with file name is my_address.dart
import 'package:EzValidatorExample/my_address_state.dart';
import 'package:flutter/material.dart';

class MyAddressScreen extends StatefulWidget {
  const MyAddressScreen({super.key});

  @override
  State<MyAddressScreen> createState() => MyAddressScreenState();
}


Create screen state my_address_state.dart
import 'package:EzValidatorExample/my_address.dart';
import 'package:EzValidatorExample/address_schema.dart';
import 'package:flutter/material.dart';

class MyAddressScreenState extends State<MyAddressScreen> {
  bool isButtonDisabled = true;
  Map<String, dynamic>? errors = {};
  List<LocationModel> provinces = [];
  List<LocationModel> districts = [];
  List<LocationModel> wards = [];


  TextEditingController fullNameController = TextEditingController();
  TextEditingController phoneNumberController = TextEditingController();
  TextEditingController streetAddressController = TextEditingController();
  TextEditingController isDefaultController = TextEditingController();
  TextEditingController noteController = TextEditingController();
  TextEditingController emailController = TextEditingController();


  LocationModel province = const LocationModel();
  LocationModel district = const LocationModel();
  LocationModel ward = const LocationModel();

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

  Map<String, Object?> _getFormValues() {
    return {
      'fullName': fullNameController.text,
      'province': province,
      'district': district,
      'ward': ward,
      'streetAddress': streetAddressController.text,
      'phoneNumber': phoneNumberController.text,
      'email': emailController.text,
      'note': noteController.text,
      'isDefault': isDefault,
    };
  }

  void _textFieldsListener() {
    emailController.addListener(_validate);
    fullNameController.addListener(_validate);
    streetAddressController.addListener(_validate);
    phoneNumberController.addListener(_validate);
    noteController.addListener(_validate);
  }

  void _validate() {
    final validateRes = AddressSchema.upsertSchema.validateSync(_getFormValues()).$2 as Map<String, dynamic>;

    setState(() {
      errors = validateRes;
      isButtonDisabled = validateRes!.isEmpty == false;
    });
  }

  Future<void> _saveAddress() async {}

  Widget item(
    String lbText,
    TextEditingController controller,
    dynamic errorText,
  ) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 16),
      child: TextField(
        controller: widget.controller,
        onTapOutside: (event) {
          FocusManager.instance.primaryFocus?.unfocus();
        },
        decoration: InputDecoration(
          border: const OutlineInputBorder(),
          alignLabelWithHint: true,
          labelStyle: const TextStyle(color: Palette.secondary);,
          labelText: widget.label,
          errorText: widget.errorText,
          isDense: true,
          contentPadding: const EdgeInsets.all(8),
          focusedBorder: const OutlineInputBorder(
            borderSide: BorderSide(color: Palette.primary),
          ),
        ),
      );
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: const AppBar(
        title: 'My Address',
      ),
      body: SingleChildScrollView(
              child: Column(
                children: [
                  Container(
                    margin: const EdgeInsets.all(5),
                    padding: const EdgeInsets.all(25),
                    decoration: BoxDecoration(
                      color: Palette.white,
                      borderRadius: BorderRadius.circular(10),
                      boxShadow: [
                        BoxShadow(
                          color: Palette.secondary.withOpacity(0.2),
                          spreadRadius: 0.1,
                          blurRadius: 0.1,
                          offset: const Offset(0, 0.5),
                        ),
                      ],
                    ),
                    child: Column(
                      children: [
                        Padding(
                          padding: const EdgeInsets.only(
                            bottom: 16,
                          ),
                          child: PhoneNumberInputComp(
                            controller: phoneNumberController,
                            errorMessage: errors!['phoneNumber'] as String?,
                          ),
                        ),
                        item('Tên người nhận', fullNameController,
                            errors!['fullName']),
                        item('Email', emailController, errors!['email']),
                        itemLocation(
                          0,
                          'Tỉnh / Thành phố',
                          provinces,
                          province,
                        ),
                        itemLocation(
                          1,
                          'Quận / Huyên',
                          districts,
                          district,
                        ),
                        itemLocation(
                          2,
                          'Xã / Phường',
                          wards,
                          ward,
                        ),
                        item('Đia chỉ', streetAddressController,
                            errors!['streetAddress']),
                        item('Ghi chú', noteController, errors!['note']),
                        Row(
                          children: [
                            const Text('Mặc định'),
                            SwitchComp(
                              value: isDefault,
                              onChanged: (checked) {
                                setState(() {
                                  isDefault = checked;
                                });
                              },
                            ),
                          ],
                        ),
                        Align(
                          child: ElevatedButton(
                            style: ElevatedButton.styleFrom(
                              backgroundColor: isButtonDisabled
                                  ? Palette.secondary
                                  : Palette.primary,
                            ),
                            onPressed: isButtonDisabled ? null : _saveAddress,
                            child: const Row(
                              mainAxisSize: MainAxisSize.min,
                              children: [
                                Text(
                                  'Lưu Thay Đổi',
                                  style: TextStyle(
                                    color: Palette.white,
                                  ),
                                ),
                                SizedBox(
                                  width: 5,
                                ),
                                Icon(
                                  Icons.save_outlined,
                                  size: 24,
                                  color: Palette.white,
                                ),
                              ],
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
  }
}


Demo


Wrapping Up

And that's it on building a form validation in Flutter. Congrats!


If you enjoyed this article, consider sharing it to help other developers. You can also visit my blog to read more articles from me.


Till next time guys, byeeeee!

Đề xuất

Data structure: Doubly Linked List
admin07/04/2024

Data structure: Doubly Linked List
In this article, I would like to show you about Data structure - Doubly Linked List
Extract data using web scraping with Python
admin14/03/2024

Extract data using web scraping with Python
A beginner’s guide to learn web scraping with Python!
Difference Between Stack and Queue
admin07/04/2024

Difference Between Stack and Queue
In the fundamental data structure, besides the linked list, the stack and queue are also used widely in computer science and programming.
Mới nhất

TypeScript Design Pattern - Singleton
admin07/08/2023

TypeScript Design Pattern - Singleton
The singleton ensures only a single install is created in a class and provides a method to access this instance everywhere in a codebase.
Part 2: Setup Custom Domain Zone + SSL for Ghost on AWS Lightsail
admin17/06/2023

Part 2: Setup Custom Domain Zone + SSL for Ghost on AWS Lightsail
In this section, I will continue to show you how to point Ghost Instance Static IP to your domain.
NodeJS Verify and Decode Cognito JWT Tokens
admin12/06/2023

NodeJS Verify and Decode Cognito JWT Tokens
In this article, I will show you how to verify and decode the Cognito JWT Tokens token.
Đinh Thành Công Blog

My website, where I write blogs on a variety of topics and where I have some experiments with new technologies.

hotlinelinkedinskypezalofacebook
DMCA.com Protection Status
Góp ý
Họ & Tên
Số điện thoại
Email
Nội dung
Tải ứng dụng
hotline

copyright © 2023 - AGAPIFA

Privacy
Term
About