Kodokon kodokon.com

ฟอร์ม: TextField คอนโทรลเลอร์ และการตรวจสอบความถูกต้อง

ควบคุมช่องกรอกข้อมูลของคุณด้วย TextEditingController และตรวจสอบทุกช่องพร้อมกันในครั้งเดียว ด้วย Form และ TextFormField

9 นาที · 3 คำถาม

เปิดบทเรียนนี้ใน Kodokon

ช่องกรอกข้อมูลที่ไม่มีคอนโทรลเลอร์ก็เหมือนกล่องดำ TextEditingController ทำให้คุณเป็นผู้ควบคุม สามารถอ่าน controller.text ได้ทุกเมื่อ เติมค่าให้ช่องล่วงหน้า ล้างค่าหลังส่งข้อมูล หรือฟังทุกการกดแป้นด้วย addListener คอนโทรลเลอร์ถูกสร้างขึ้นใน State ไม่ใช่ใน build เด็ดขาด มิฉะนั้นมันจะถูกสร้างใหม่ทุกครั้งที่มีการรีบิลด์

DART
import 'package:flutter/material.dart';

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

  @override
  State<NicknameField> createState() =>
      _NicknameFieldState();
}

class _NicknameFieldState extends State<NicknameField> {
  final _controller = TextEditingController();

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: _controller,
      decoration: const InputDecoration(
        labelText: 'Nickname',
        border: OutlineInputBorder(),
      ),
      onSubmitted: (value) => debugPrint(value),
    );
  }
}
คอนโทรลเลอร์มีชีวิตอยู่ใน State และตายลงใน dispose()

ทันทีที่หน้าจอมีหลายฟิลด์ที่ต้องตรวจสอบ ให้ใช้สามสหาย Form, GlobalKey<FormState> และ TextFormField แต่ละฟิลด์จะอธิบายกฎของตัวเองใน validator ฟังก์ชันนี้จะคืนข้อความแสดงข้อผิดพลาด หรือคืน null หากทุกอย่างเรียบร้อยดี การเรียก validate() บนคีย์จะกระตุ้นตัว validator ทั้งหมด พร้อมกันในครั้งเดียว

DART
import 'package:flutter/material.dart';

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

  @override
  State<SignUpForm> createState() => _SignUpFormState();
}

class _SignUpFormState extends State<SignUpForm> {
  final _formKey = GlobalKey<FormState>();
  final _emailController = TextEditingController();

  @override
  void dispose() {
    _emailController.dispose();
    super.dispose();
  }

  void _submit() {
    if (_formKey.currentState!.validate()) {
      debugPrint('Email: ${_emailController.text}');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          TextFormField(
            controller: _emailController,
            keyboardType: TextInputType.emailAddress,
            decoration: const InputDecoration(
              labelText: 'Email',
            ),
            validator: (value) {
              if (value == null || value.isEmpty) {
                return 'Required field';
              }
              if (!value.contains('@')) {
                return 'Invalid address';
              }
              return null;
            },
          ),
          const SizedBox(height: 16),
          FilledButton(
            onPressed: _submit,
            child: const Text('Create account'),
          ),
        ],
      ),
    );
  }
}
validate() กระตุ้นตัว validator ทุกตัวในฟอร์ม

เมื่อคลิกปุ่ม validate() จะรัน validator แต่ละตัว ข้อความที่คืนกลับมาจะปรากฏเป็นสีแดงใต้ฟิลด์ที่เกี่ยวข้อง และเมท็อดจะคืนค่า false หากมีอย่างน้อยหนึ่งฟิลด์ที่ไม่ถูกต้อง ดังนั้นตรรกะการส่งข้อมูลของคุณจึงอยู่หลัง if เพียงตัวเดียว ทำให้เป็นไปไม่ได้เลยที่จะส่งข้อมูลที่ไม่ถูกต้อง

ทดสอบความรู้

ตรวจสอบว่าคุณจำประเด็นสำคัญของบทเรียนนี้ได้ครบถ้วน

  1. TextEditingController มีไว้เพื่ออะไร?
    • เพื่อวาดเส้นขอบของฟิลด์
    • เพื่ออ่านและแก้ไขข้อความของฟิลด์ และฟังการเปลี่ยนแปลงของมัน
    • เพื่อตรวจสอบที่อยู่อีเมลโดยอัตโนมัติ
    • เพื่อปิดแป้นพิมพ์
  2. validator ควรคืนค่าอะไรเมื่อค่านั้นถูกต้อง?
    • true
    • สายอักขระว่าง
    • null
    • ตัวค่าเอง
  3. ทำไมจึงต้องเรียก _controller.dispose() ในเมท็อด dispose() ของ State?
    • เพื่อล้างฟิลด์บนหน้าจอ
    • เพื่อปล่อยคืนทรัพยากรและหลีกเลี่ยงการรั่วไหลของหน่วยความจำ
    • เพื่อส่งฟอร์ม