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

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.
How to secure your API gateway
admin17/04/2024

How to secure your API gateway
In this blog, I will cover the 6 methods that technology leaders need to incorporate to secure and protect APIs.
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
Mới nhất

Design Patterns
admin07/08/2023

Design Patterns
The design pattern does not be a specific programming language. Almost programming languages might apply design patterns that to resolve a problem repeat.
Create S3 Bucket with AWS CDK
admin09/06/2023

Create S3 Bucket with AWS CDK
In this article, I introduce Amazon CDK and how to write AWS infrastructure-as-code using TypeScript. We will do it step by step.
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