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 - Abstract Factory
admin07/08/2023

TypeScript Design Pattern - Abstract Factory
The abstract factory pattern is one of five design patterns in the Creational Design Pattern group. The abstract factory provides an interface for creating families of related or dependent objects without specifying their concrete classes.
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.
Part 1: React Props and State
admin18/06/2023

Part 1: React Props and State
Before learning React, we should understand Props and State. This is basic for a newbie.
Mới nhất

Data structure: Singly Linked List
admin07/04/2024

Data structure: Singly Linked List
In this article, I will show you how to set up a singly linked list algorithm in Python.
TypeScript Design Pattern - Proxy
admin11/08/2023

TypeScript Design Pattern - Proxy
Provide a surrogate or placeholder for another object to control access to it.
How to integrate ChatGPT-3.5 Turbo into Node.js
admin10/01/2024

How to integrate ChatGPT-3.5 Turbo into Node.js
Step-by-Step Guide to Incorporating ChatGPT-3.5 Turbo into Node.js for Basic ReactJS Applications
Đ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