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

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.
RESTful API - How to design?
admin09/06/2023

RESTful API - How to design?
In this article, I will describe the useful points of designing a good API.
🚀 Using Bitwise Oprators to build a RBAC in Node.js 🚀
admin13/04/2024

🚀 Using Bitwise Oprators to build a RBAC in Node.js 🚀
In this article, I will illustrate to you how to build an RBAC in Node.js using Bitwise Operators.
Mới nhất

Semantic Versioning NodeJS
admin07/07/2023

Semantic Versioning NodeJS
How to Use Semantic Versioning in NPM
JOI - API schema validation
admin12/06/2023

JOI - API schema validation
Data validation is one of topics that I am interesting. I always review my code after developed features or fixed bugs. There are many places where need to validate data, it is really terrible. Some cases, we need to validate data input because ensure the data into API, it will not make any problems to crash system.
Part 1: Build a Chat App with ReactJS + Material UI
admin13/09/2023

Part 1: Build a Chat App with ReactJS + Material UI
In this article, I would like to introduce using ReactJS and material UI to build a Chat App.
Đ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