flutter-form-builder-ecosystem / form_builder_extra_fields

Additional ready-made form input fields for flutter_form_builder package
https://pub.dev/packages/form_builder_extra_fields
BSD 3-Clause "New" or "Revised" License
28 stars 48 forks source link

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

Open cds-reis opened 4 months ago

cds-reis commented 4 months ago

Is there an existing issue for this?

Package/Plugin version

10.1.0

Platforms

Flutter doctor

Flutter doctor ```bash [✓] 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 ```dart 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 createState() => _ExampleState(); } class _ExampleState extends State { 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( 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 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 createState() => _ExampleState(); }

class _ExampleState extends State { 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( name: 'name', controller: _controller, itemBuilder: (context, itemData) => const SizedBox(), suggestionsCallback: (pattern) => [], ); } }

2. See the error.

### Aditional information

A way to fix this problem is using the same validation that FormBuilderTextField uses:
```dart
  @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();
  }
deandreamatias commented 3 months ago

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