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

[FormBuilderTypeAhead]: Calls dispose on the TextEditingController even when it is passed in #113

Open
2 of 7 tasks
cds-reis opened this issue Jul 17, 2024 · 1 comment
Open
2 of 7 tasks
Labels
bug Something isn't working

Comments

@cds-reis
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Package/Plugin version

10.1.0

Platforms

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

Flutter doctor

Flutter doctor
[✓] Flutter (Channel stable, 3.16.9, on macOS 14.2.1 23C71 darwin-arm64, locale en-BR)
    • Flutter version 3.16.9 on channel stable at /Users/cardosoOReis/fvm/versions/3.16.9
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 41456452f2 (6 months ago), 2024-01-25 10:06:23 -0800
    • Engine revision f40e976bed
    • Dart version 3.2.6
    • DevTools version 2.28.5

[✗] Android toolchain - develop for Android devices
    ✗ Unable to locate Android SDK.
      Install Android Studio from: https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK components.
      (or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
      If the Android SDK has been installed to a custom location, please use
      `flutter config --android-sdk` to update to that location.


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

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

[✓] Android Studio (version 2023.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.7+0-17.0.7b1000.6-10550314)

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

[✓] Connected device (2 available)
    • macOS (desktop) • macos  • darwin-arm64   • macOS 14.2.1 23C71 darwin-arm64
    • Chrome (web)    • chrome • web-javascript • Google Chrome 126.0.6478.128

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

! Doctor found issues in 1 category.

Minimal code example

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

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

  @override
  State<Example> createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  final _controller = TextEditingController();

  @override
  void dispose() {
    // This will throw a `TextEditingController was used after being disposed`
    // exception, since it was already disposed by the FormBuilderTypeAhead.
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return FormBuilderTypeAhead<String>(
      name: 'name',
      controller: _controller,
      itemBuilder: (context, itemData) => const SizedBox(),
      suggestionsCallback: (pattern) => [],
    );
  }
}

Current Behavior

When I call a dispose on a controller I have created, and pass it to a FormBuilderTypeAhead, it throws a:

A TextEditingController was used after being disposed.

Once you have called dispose() on a TextEditingController, it can no longer be used.
The relevant error-causing widget was ...

Expected Behavior

I expect the FormBuilderTypeAhead widget to dispose the controllers it created itself, and not to dispose the controller created outside of it.

Steps To Reproduce

  1. Run:
import 'package:flutter/material.dart';
import 'package:form_builder_extra_fields/form_builder_extra_fields.dart';

void main(List<String> args) {
  runApp(
    const MaterialApp(
      home: HomeWidget(),
    ),
  );
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: TextButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => Scaffold(
                  appBar: AppBar(),
                  body: const Center(child: Example()),
                ),
              ),
            );
          },
          child: const Text('Open page'),
        ),
      ),
    );
  }
}

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

  @override
  State<Example> createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  final _controller = TextEditingController();

  @override
  void dispose() {
    // This will throw a `TextEditingController was used after being disposed`
    // exception, since it was already disposed by the FormBuilderTypeAhead.
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return FormBuilderTypeAhead<String>(
      name: 'name',
      controller: _controller,
      itemBuilder: (context, itemData) => const SizedBox(),
      suggestionsCallback: (pattern) => [],
    );
  }
}
  1. See the error.

Aditional information

A way to fix this problem is using the same validation that FormBuilderTextField uses:

  @override
  void dispose() {
    // Dispose the _controller when initState created it
    _controller!.removeListener(_handleControllerChanged);
    if (null == widget.controller) {
      _controller!.dispose();
    }
    super.dispose();
  }

Disposing the controller only when initState creates it. Currently it disposes anyway:

  @override
  void dispose() {
    // Dispose the _typeAheadController when initState created it
    super.dispose();
    _typeAheadController.dispose();
  }
@cds-reis cds-reis added the bug Something isn't working label Jul 17, 2024
@deandreamatias
Copy link
Contributor

@cardosoOReis Take a look if the last version (11.0) solved this issue
Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants