Skip to content

[FormBuilder]: AutovalidateMode Always and onUserInteraction break invalidate method #1484

Open
@GChanathip

Description

@GChanathip

Is there an existing issue for this?

  • I have searched the existing issues

Package/Plugin version

10.0.1

Platforms

  • Android
  • iOS
  • Linux
  • MacOS
  • Web
  • Windows

Flutter doctor

Flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.29.0, on macOS 15.4 24E248 darwin-arm64, locale en-TH)
[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0-rc2)
[!] Xcode - develop for iOS and macOS (Xcode 16.2)
    ! CocoaPods 1.15.2 out of date (1.16.2 is recommended).
        CocoaPods is a package manager for iOS or macOS platform code.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/to/platform-plugins
      To update CocoaPods, see https://guides.cocoapods.org/using/getting-started.html#updating-cocoapods
[✓] Chrome - develop for the web
[✓] Android Studio (version 2024.2)
[✓] VS Code (version 1.98.2)
[✓] Connected device (5 available)
    ! Error: Browsing on the local area network for Fw iPhone 15. Ensure the device is unlocked and attached with a
      cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
    ! Error: Browsing on the local area network for ChanathipiPad. Ensure the device is unlocked and attached with a
      cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
    ! Error: Browsing on the local area network for chanathip’s iPhone. Ensure the device is unlocked and attached
      with a cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
    ! Error: Browsing on the local area network for Jarawee’s iPhone. Ensure the device is unlocked and attached with
      a cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
    ! Error: Browsing on the local area network for PAK. Ensure the device is unlocked and attached with a cable or
      associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
    ! Error: Browsing on the local area network for Intre . Ensure the device is unlocked and attached with a cable
      or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
    ! Error: Browsing on the local area network for BZ. Ensure the device is unlocked and attached with a cable or
      associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
[✓] Network resources

! Doctor found issues in 1 category.

Minimal code example

Code sample
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:form_builder_validators/form_builder_validators.dart';

void main() {
  runApp(const MaterialApp(home: SignupForm()));
}

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

  @override
  State<SignupForm> createState() => _SignupFormState();
}

class _SignupFormState extends State<SignupForm> {
  final _formKey = GlobalKey<FormBuilderState>();
  final _emailFieldKey = GlobalKey<FormBuilderFieldState>();
  AutovalidateMode autovalidateMode = AutovalidateMode.disabled;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Signup Form')),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16.0),
        child: FormBuilder(
          key: _formKey,
          autovalidateMode: autovalidateMode,
          child: Column(
            children: [
              FormBuilderTextField(
                name: 'full_name',
                decoration: const InputDecoration(labelText: 'Full Name'),
                validator: FormBuilderValidators.compose([
                  FormBuilderValidators.required(),
                ]),
              ),
              const SizedBox(height: 10),
              FormBuilderTextField(
                key: _emailFieldKey,
                name: 'email',
                decoration: const InputDecoration(labelText: 'Email'),
                validator: FormBuilderValidators.compose([
                  FormBuilderValidators.required(),
                  FormBuilderValidators.email(),
                ]),
              ),
              const SizedBox(height: 10),
              FormBuilderTextField(
                name: 'password',
                decoration: const InputDecoration(labelText: 'Password'),
                obscureText: true,
                validator: FormBuilderValidators.compose([
                  FormBuilderValidators.required(),
                  FormBuilderValidators.minLength(6),
                ]),
              ),
              const SizedBox(height: 10),
              FormBuilderTextField(
                name: 'confirm_password',
                autovalidateMode: AutovalidateMode.onUserInteraction,
                decoration: InputDecoration(
                  labelText: 'Confirm Password',
                  suffixIcon: (_formKey.currentState?.fields['confirm_password']?.hasError ?? false)
                      ? const Icon(Icons.error, color: Colors.red)
                      : const Icon(Icons.check, color: Colors.green),
                ),
                obscureText: true,
                validator: (value) => _formKey.currentState?.fields['password']?.value != value ? 'No coinciden' : null,
              ),
              const SizedBox(height: 10),
              FormBuilderFieldDecoration<bool>(
                name: 'test',
                validator: FormBuilderValidators.compose([
                  FormBuilderValidators.required(),
                  FormBuilderValidators.equal(true),
                ]),
                // initialValue: true,
                decoration: const InputDecoration(labelText: 'Accept Terms?'),
                builder: (FormFieldState<bool?> field) {
                  return InputDecorator(
                    decoration: InputDecoration(
                      errorText: field.errorText,
                    ),
                    child: SwitchListTile(
                      title: const Text('I have read and accept the terms of service.'),
                      onChanged: field.didChange,
                      value: field.value ?? false,
                    ),
                  );
                },
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () {
                  if (_formKey.currentState?.saveAndValidate() ?? false) {
                    if (true) {
                      // Either invalidate using Form Key
                      _formKey.currentState?.fields['email']?.invalidate('Email already taken.');
                      // OR invalidate using Field Key
                      // _emailFieldKey.currentState?.invalidate('Email already taken.');
                    }
                  } else {
                    setState(() {
                      autovalidateMode = AutovalidateMode.onUserInteraction;
                    });
                    debugPrint(_formKey.currentState?.value.toString());
                  }
                },
                child: const Text('Signup'),
              )
            ],
          ),
        ),
      ),
    );
  }
}

Current Behavior

_formKey.currentState?.fields['email']?.invalidate('Email already taken.')
is not working when autovalidateMode = always or onUserInteraction

Expected Behavior

invalidate should show errorr correctly when autovalidateMode = always or onUserInteraction

Steps To Reproduce

from the example code that i provide

  • tap Signup button once to set autovalidateMode = onUserInteraction.
  • and then fill the form
  • tap signup button again.

Aditional information

i think the root cause is forceErrorText in thesuper classof FormBuilderField is null

Image

related issue #1281

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    Status

    Ready

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions