flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond
https://flutter.dev
BSD 3-Clause "New" or "Revised" License
165.71k stars 27.36k forks source link

[web] TextFormField does not get blurred when tapped outside of the widget. #64245

Closed Sulav-Beehave closed 1 year ago

Sulav-Beehave commented 4 years ago

Steps to Reproduce

  1. Click on the TextFormField.
  2. Now click on any other area of screen.

Expected results: Expected behaviour is textfield must lose focus. Actual results: The focus is still on Textformfield

Note: This functionality previously worked upto version 1.19.0-4.3.pre (BETA channel)

Demo Code: main.dart

`

                      import 'package:flutter/material.dart';
                      import 'dart:html' as html;

                      void main() {
                        runApp(MyApp());
                      }

                      class MyApp extends StatelessWidget {
                        @override
                        Widget build(BuildContext context) {
                          return MaterialApp(
                            title: 'TextField Issue',
                            theme: ThemeData(
                              primarySwatch: Colors.purple,
                            ),
                            home: MyHomePage(title: 'TextField Issue'),
                          );
                        }
                      }

                      class MyHomePage extends StatefulWidget {
                        MyHomePage({Key key, this.title}) : super(key: key);
                        final String title;

                        @override
                        _MyHomePageState createState() => _MyHomePageState();
                      }

                      class _MyHomePageState extends State<MyHomePage> {
                        FocusNode _focusNode;

                        @override
                        void initState() {
                          _focusNode = FocusNode(
                            canRequestFocus: true,
                          );
                          _focusNode.addListener(() => print("FocusNode changed"));

                          super.initState();
                        }

                        @override
                        Widget build(BuildContext context) {
                          return Scaffold(
                            appBar: AppBar(
                              title: Text(widget.title),
                            ),
                            body: Center(
                              child: Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: <Widget>[
                                  Container(
                                    padding: EdgeInsets.all(24),
                                    child: TextFormField(
                                      focusNode: _focusNode,
                                    ),
                                  ),
                                  Container(
                                    padding: EdgeInsets.all(24),
                                    child: Column(
                                      crossAxisAlignment: CrossAxisAlignment.start,
                                      children: [
                                        Text("Demo displaying blur issue on web"),
                                        Text("\n1) Click on the top-most TextFormField above"),
                                        Text("2) Now click on any other area of screen. Basic expected behaviour is textfield must lose focus but it doesnt lose focus."),
                                        Wrap(
                                          children: [
                                            Text("3) The blur was removed in recent PR "),
                                            InkWell(
                                              child: Text('https://github.com/flutter/engine/pull/18743'),
                                              onTap: () {
                                                html.window.open('https://github.com/flutter/engine/pull/18743', '_blank');
                                              },
                                            )
                                          ],
                                        ),
                                        Text("4) This functionality previously worked upto version 1.19.0-4.3.pre (BETA channel)"),
                                      ],
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          );
                        }
                      }

`

hamdikahloun commented 4 years ago

hi @Sulav-Beehave

Container( padding: EdgeInsets.all(24), child: Column( children: [ TextFormField( focusNode: _focusNode, ), TextFormField(), ], ))

it's because nothing else Focusable. If you add other TextFormField you will see right behavior.

image

Sulav-Beehave commented 4 years ago

Hi @hamdikahloun.

Thanks for replying.

Actually it was working up to version 1.19.0-4.3.pre (BETA channel). The main issue that it causes is:

When Textfield is focused the keyboard appears and the keyboard should go away when we tap outside but since the focus is still on Textfield there is no way to dismiss the keyboard other than pressing back. We do have an option in keyboard but it is still an issue when we have multi-line keyboard input type. Also the issue with multi-line causes issue in web since when we press enter the cursor is sent to next line rather than losing focus.

Also if we have a dropdown in same screen and when we click the dropdown in this screen the natural behavior is to unfocus the widget but the focus still stays there when we select a item from dropdown.

Only solution that i found for it currently is https://flutterigniter.com/dismiss-keyboard-form-lose-focus/ but i don't think this technique works when there are multiple nested stateful widgets.

Is there any way to fix this behaviour because it was working in previous versions? I haven't been able to update to latest beta version due to this issue.

Also it wasn't working in mobile devices but it did work on web browsers but they have removed the functionality in this pr https://github.com/flutter/engine/pull/18743

HansMuller commented 4 years ago

CC @gspencergoog

gspencergoog commented 4 years ago

cc @nturgut is this an expected side effect of flutter/engine#18743?

nturgut commented 4 years ago

Yes, for web, this is an expected side effect. It is requested in other issues (which are noted on the PR). The PR only changes web behavior though. For web, mobile vs desktop browsers have different behaviour. PR only changes desktop browsers (to the behavior which is also adopted by the desktop flutter apps).

I don't know the current use case but if the use case is filling out a form and pressing next (as the example gif), we also have another alternative:

finalizediting

When the button is pressed you can call finishAutofillContext with shouldSave=false

This behaviour is meant to use with Autofill, since context is finished, text connection will be closed by the engine.

Sulav-Beehave commented 4 years ago

Hi @nturgut

Thanks for replying. The normal behaviour that user expects in a web page is to lose focus from input field when clicked outside. It works in every html page as shown in gif below. html1

But it doesnt work as expected as in flutter web currently as shown in gif below. flutter1

I understand that the PR https://github.com/flutter/engine/pull/18743 was done to address the issues reported in its description, which consists in avoiding to trigger onFieldSubmitted when the text field looses focus, the purpose being to trigger onFieldSubmitted only when the users press the enter or tab keys. However this PR has introduced the current issue with focus. The solution could be to re-introduce the previous behavior which is the natural one for a web page, still avoiding to call onFieldSubmitted when the focus is lost. Only onEditingComplete should be called when the focus is lost.

Fabrice-TEICHTEIL-KOENIGSBUCH commented 4 years ago

Looking at PRs mentioned in https://github.com/flutter/engine/pull/18743 the main point seems to be whether flutter for web should behave like a web page or if it should behave the same way across all platforms.

According to the below comment it seems that the later choice has been made: https://github.com/flutter/flutter/issues/58207#issuecomment-639921667

@eddie-at-work Thanks for filing the issue. We changed our approach this week. Previously, Flutter for Web behaved like a web page. If user click on an area other than the input field itself, the input field is blurred, thus the connection is closed. We changed this behavior for Desktop Browsers. Now only, pressing enter, tab changes the focus of the input fields. Therefore clicking on a button as you suggested also won't change the focus. Please check the PR: flutter/engine#18743

There is another issue with a longer discussion: #49785 Please also have a look there.

Even though this choice makes a lot of sense as it would be a burden for the developer to test the different behaviour across all platforms, it introduces a major regression for applications that were relying on the previous way of working, and there is no simple way as I see to revert to the previous behaviour programatically.

The simplest and quickest solution imho would be to keep the current behaviour as default, and to add an optional parameter to TextField and TextFormField constructors to let the developer decide if the input field shall be blurred when the user clicks on an area other than the input field itself.

pedromassangocode commented 4 years ago

Still valid with on the latest master channel.

flutter doctor -v ``` [✓] Flutter (Channel master, 1.22.0-10.0.pre.88, on Mac OS X 10.15.6 19G2021, locale en) • Flutter version 1.22.0-10.0.pre.88 at /Users/pedromassango/dev/SDKs/flutter_master • Framework revision e10bdbbd9d (13 hours ago), 2020-09-07 11:40:03 -0700 • Engine revision ac8b9c4c52 • Dart version 2.10.0 (build 2.10.0-86.0.dev) [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.1) • Android SDK at /Users/pedromassango/Library/Android/sdk • Platform android-30, build-tools 30.0.1 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.7) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.7, Build version 11E801a • CocoaPods version 1.9.3 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [!] Android Studio (version 4.0) • Android Studio at /Applications/Android Studio.app/Contents ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) [✓] IntelliJ IDEA Community Edition (version 2020.2.1) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 48.1.4 • Dart plugin version 202.7206 [✓] VS Code (version 1.48.2) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.13.2 [✓] Connected device (4 available) • sdk gphone x86 arm (mobile) • emulator-5554 • android-x86 • Android 11 (API 30) (emulator) • macOS (desktop) • macos • darwin-x64 • Mac OS X 10.15.6 19G2021 • Web Server (web) • web-server • web-javascript • Flutter Tools • Chrome (web) • chrome • web-javascript • Google Chrome 85.0.4183.83 ! Doctor found issues in 1 category. ```
mariamhas commented 4 years ago

We should keep the callback functionality to match Flutter framework, but perhaps provide a configuration that can allow developers to make TextformFields act "webby". marking as P5 as new feature

Fabrice-TEICHTEIL-KOENIGSBUCH commented 4 years ago

@mariamhas @yjbanov we have a flutter web app in production which is currently stuck with beta version 1.19 since the framework behaviour changed for text field focus. For us, this issue is not a P5 nice to have new feature, but is critical so that we can release the app with latest flutter versions.

Basically we have a requirement to send user input to the backend each time the user finishes editing a field in a form, a bit like google sheet that sync with backend after each user action. We cannot wait that the user presses a submit button after filling all fields.

With the current framework version, when the user finishes editing a text field and then goes to the next one which is a drop down, we don't get notified that text field edition is completed when the drop down is pressed and therefore cannot send text field value to the backend.

If you're not going to release the configuration solution anytime soon, would you have any recommendation to us to implement the above feature with current framework version?

Many thanks :)

pedromassangocode commented 3 years ago

Related issues (close ones): https://github.com/flutter/flutter/issues/58207 https://github.com/flutter/flutter/issues/67646

Maybe a duplicate of https://github.com/flutter/flutter/issues/32433

darshankawar commented 1 year ago

Verified this issue using latest master and stable versions and ran on web, confirmed that tapping outside the textfield loses the focus as expected:

https://github.com/flutter/flutter/assets/67046386/916963fd-16ad-4c79-8c99-a06be5d4b0a2

runnable code sample ``` import 'package:flutter/material.dart'; import 'dart:html' as html; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'TextField Issue', theme: ThemeData( primarySwatch: Colors.purple, ), home: MyHomePage(title: 'TextField Issue'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State { late FocusNode _focusNode; @override void initState() { _focusNode = FocusNode( canRequestFocus: true, ); _focusNode.addListener(() => print("FocusNode changed")); super.initState(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: EdgeInsets.all(24), child: TextFormField( focusNode: _focusNode, ), ), Container( padding: EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Demo displaying blur issue on web"), Text("\n1) Click on the top-most TextFormField above"), Text("2) Now click on any other area of screen. Basic expected behaviour is textfield must lose focus but it doesnt lose focus."), Wrap( children: [ Text("3) The blur was removed in recent PR "), InkWell( child: Text('https://github.com/flutter/engine/pull/18743'), onTap: () { html.window.open('https://github.com/flutter/engine/pull/18743', '_blank'); }, ) ], ), Text("4) This functionality previously worked upto version 1.19.0-4.3.pre (BETA channel)"), ], ), ), ], ), ), ); } } ```

Closing this as fixed and working as expected.

github-actions[bot] commented 1 year ago

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.