Skip to content

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

@cds-reis

Description

@cds-reis

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();
  }

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Status

    Ready

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions