Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[General]: FormField gains focus back after a modal/dialog is closed #1429

Open
3 of 7 tasks
mhmzdev opened this issue Sep 19, 2024 · 6 comments
Open
3 of 7 tasks

[General]: FormField gains focus back after a modal/dialog is closed #1429

mhmzdev opened this issue Sep 19, 2024 · 6 comments
Labels
bug Something isn't working help wanted Extra attention is needed originates from dependency The issue originates from package dependency

Comments

@mhmzdev
Copy link

mhmzdev commented Sep 19, 2024

Is there an existing issue for this?

  • I have searched the existing issues

Package/Plugin version

9.3.0 <Tried on latest 9.4.1 as well>

Platforms

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

Flutter doctor

Flutter doctor
[✓] Flutter (Channel stable, 3.24.0, on macOS 14.6.1 23G93 darwin-arm64, locale en-PK)
    • Flutter version 3.24.0 on channel stable at /Users/hamza/Development/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 80c2e84975 (7 weeks ago), 2024-07-30 23:06:49 +0700
    • Engine revision b8800d88be
    • Dart version 3.5.0
    • DevTools version 2.37.2

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/hamza/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • ANDROID_HOME = /Users/hamza/Library/Android/sdk
    • ANDROID_SDK_ROOT = /Users/hamza/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.10+0-17.0.10b1087.21-11609105)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.4)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15F31d
    • CocoaPods version 1.14.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2024.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.10+0-17.0.10b1087.21-11609105)

[✓] VS Code (version 1.92.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.96.0

[✓] Connected device (4 available)
    • iPhone 15 Pro (mobile)          • 2DFED524-E171-445E-B631-828D239B1B43 • ios            • com.apple.CoreSimulator.SimRuntime.iOS-17-5 (simulator)
    • macOS (desktop)                 • macos                                • darwin-arm64   • macOS 14.6.1 23G93 darwin-arm64
    • Mac Designed for iPad (desktop) • mac-designed-for-ipad                • darwin         • macOS 14.6.1 23G93 darwin-arm64
    • Chrome (web)                    • chrome                               • web-javascript • Google Chrome 128.0.6613.138

[✓] Network resources
    • All expected network resources are available.

• No issues found!

Minimal code example

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

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter FormBuilder Example',
      debugShowCheckedModeBanner: false,
      localizationsDelegates: const [
        FormBuilderLocalizations.delegate,
        ...GlobalMaterialLocalizations.delegates,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: FormBuilderLocalizations.supportedLocales,
      home: const _ExamplePage(),
    );
  }
}

class _ExamplePage extends StatefulWidget {
  const _ExamplePage();

  @override
  State<_ExamplePage> createState() => _ExamplePageState();
}

class _ExamplePageState extends State<_ExamplePage> {
  final _formKey = GlobalKey<FormBuilderState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FormBuilder(
        key: _formKey,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            FormBuilderTextField(
              name: 'full_name',
              decoration: const InputDecoration(labelText: 'Full Name'),
              validator: FormBuilderValidators.compose([
                FormBuilderValidators.required(),
              ]),
            ),
            const SizedBox(height: 10),
            ElevatedButton(
              onPressed: () {
                final isValid = _formKey.currentState!.saveAndValidate();
                if (!isValid) return;
                FocusScope.of(context).unfocus();

                showDialog(
                  context: context,
                  builder: (context) {
                    return AlertDialog(
                      title: const Text('Form Data'),
                      content: Text(_formKey.currentState!.value.toString()),
                      actions: [
                        TextButton(
                          onPressed: () => Navigator.of(context).pop(),
                          child: const Text('Close'),
                        ),
                      ],
                    );
                  },
                );
              },
              child: const Text('Open Dialog'),
            ),
          ],
        ),
      ),
    );
  }
}

Current Behavior

When any text field is tap to enter some value, and any dialog or modal is opened with the field still in focus. When the dialog exit the focus goes back to the text field. Which is weird, it shouldn't happen.

I've already tried the FocusScope.of(context).unfocus() call before opening the keyboard but doesn't work.

Expected Behavior

When a text field is in focus and any dialog or modal is opened, the field should lose its focus i.e. unfocus and shouldn't gain focus back after the modal or dialog is closed.

Steps To Reproduce

  1. Create a simple text field using the package
  2. Tap it and enter some value
  3. Create a very simple modal or dialog
  4. Open the modal/dialog without unfocusing the text field.
  5. Once the modal/dialog exit, the field will gain its focus back

FYI:
This won't happen if you unfocus the field yourself i.e. tap on the screen or the "done" button on keyboard.

Aditional information

It only happens if the text field has gained its focus one time, if you don't tap the field, it won't gain its focus on closing of modal or dialog.

@mhmzdev mhmzdev added the bug Something isn't working label Sep 19, 2024
@deandreamatias
Copy link
Collaborator

Hi!
I need a minimal code example to can execute:

  • Without external packages and dependencies
  • Without refereces of imports
  • With only Flutter Material or Cupertino widgets and FormBuilder widgets
  • Starting from main Dart method

Example:

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

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter FormBuilder Example',
      debugShowCheckedModeBanner: false,
      localizationsDelegates: const [
        FormBuilderLocalizations.delegate,
        ...GlobalMaterialLocalizations.delegates,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: FormBuilderLocalizations.supportedLocales,
      home: const _ExamplePage(),
    );
  }
}

class _ExamplePage extends StatefulWidget {
  const _ExamplePage();

  @override
  State<_ExamplePage> createState() => _ExamplePageState();
}

class _ExamplePageState extends State<_ExamplePage> {
  final _formKey = GlobalKey<FormBuilderState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FormBuilder(
        key: _formKey,
        child: Column(
          children: [
            FormBuilderTextField(
              name: 'full_name',
              decoration: const InputDecoration(labelText: 'Full Name'),
              validator: FormBuilderValidators.compose([
                FormBuilderValidators.required(),
              ]),
            ),
            const SizedBox(height: 10),
            ElevatedButton(
              onPressed: () {
                _formKey.currentState?.saveAndValidate();
                debugPrint(_formKey.currentState?.value.toString());
              },
              child: const Text('Print'),
            )
          ],
        ),
      ),
    );
  }
}

Thanks a lot

@mhmzdev
Copy link
Author

mhmzdev commented Dec 30, 2024

Hi @deandreamatias
I've updated your code with reproducible example, you can copy paste it directly

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

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter FormBuilder Example',
      debugShowCheckedModeBanner: false,
      localizationsDelegates: const [
        FormBuilderLocalizations.delegate,
        ...GlobalMaterialLocalizations.delegates,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: FormBuilderLocalizations.supportedLocales,
      home: const _ExamplePage(),
    );
  }
}

class _ExamplePage extends StatefulWidget {
  const _ExamplePage();

  @override
  State<_ExamplePage> createState() => _ExamplePageState();
}

class _ExamplePageState extends State<_ExamplePage> {
  final _formKey = GlobalKey<FormBuilderState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FormBuilder(
        key: _formKey,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            FormBuilderTextField(
              name: 'full_name',
              decoration: const InputDecoration(labelText: 'Full Name'),
              validator: FormBuilderValidators.compose([
                FormBuilderValidators.required(),
              ]),
            ),
            const SizedBox(height: 10),
            ElevatedButton(
              onPressed: () {
                final isValid = _formKey.currentState!.saveAndValidate();
                if (!isValid) return;
                FocusScope.of(context).unfocus();

                showDialog(
                  context: context,
                  builder: (context) {
                    return AlertDialog(
                      title: const Text('Form Data'),
                      content: Text(_formKey.currentState!.value.toString()),
                      actions: [
                        TextButton(
                          onPressed: () => Navigator.of(context).pop(),
                          child: const Text('Close'),
                        ),
                      ],
                    );
                  },
                );
              },
              child: const Text('Open Dialog'),
            ),
          ],
        ),
      ),
    );
  }
}

Results:

Screen.Recording.2024-12-30.at.8.35.04.PM.mov

@deandreamatias
Copy link
Collaborator

Related to #1297

@deandreamatias
Copy link
Collaborator

I can replicate this error with Flutter pure components, so this bug maybe is a behavior of Flutter SDK.

Form(
  child: TextFormField(
      decoration: InputDecoration(labelText: "Full name"),
      validator: FormBuilderValidators.compose([
        FormBuilderValidators.required(),
        FormBuilderValidators.minLength(1)
      ]),
    ),
)

Related to flutter/flutter#153079, flutter/flutter#92349 and flutter/flutter#145155

I think that would exist a way to skip this behavior, but can't think a some way right now

@deandreamatias deandreamatias added help wanted Extra attention is needed originates from dependency The issue originates from package dependency labels Jan 1, 2025
@mhmzdev
Copy link
Author

mhmzdev commented Jan 2, 2025

Probably we can open an issue on Flutter SDK itself? @deandreamatias

@deandreamatias
Copy link
Collaborator

I think that the best way is follow the flutter/flutter#153079 issue and when Flutter team solve this, we try again if our use cases are solved.
This and there issue is the same, I think

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed originates from dependency The issue originates from package dependency
Projects
None yet
Development

No branches or pull requests

2 participants