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

Error when name of field is changed #1173

Closed
Clavum opened this issue Jan 5, 2023 · 1 comment · Fixed by #1178
Closed

Error when name of field is changed #1173

Clavum opened this issue Jan 5, 2023 · 1 comment · Fixed by #1178
Labels
bug Something isn't working

Comments

@Clavum
Copy link

Clavum commented Jan 5, 2023

Environment

Package version: 7.7.0

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

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

final _formKey = GlobalKey<FormBuilderState>();

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Example',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: Scaffold(
        appBar: AppBar(),
        body: Builder(
          builder: (context) {
            return Center(
              child: ElevatedButton(
                onPressed: () => Navigator.of(context).push(
                  MaterialPageRoute(builder: (_) => const FormScreen()),
                ),
                child: const Text('Navigate to form'),
              ),
            );
          }
        ),
      ),
    );
  }
}

class FormScreen extends StatefulWidget {
  const FormScreen();

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

class _FormScreenState extends State<FormScreen> {
  int nameInt = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Column(
          children: [
            FormBuilder(
              key: _formKey,
              child: FormBuilderTextField(
                name: nameInt.toString(),
              ),
            ),
            ElevatedButton(
              onPressed: () => setState(() {
                nameInt++;
              }),
              child: const Text('Change field name'),
            )
          ],
        ),
      ),
    );
  }
}

Description

ISSUE: If the name parameter of a form field changes, the form breaks.

Steps to reproduce:

  1. Run the code sample
  2. Navigate to the form page
  3. Click the button to change the field name
  4. Tap the back button in the app bar (Error # 1 is thrown - '_fields.containsKey(name)': is not true)
  5. Navigate to the form page again (Error # 2 is thrown - failed Flutter element mounting)
  6. At this point, the form page is entirely broken and unusable
Error # 1
======== Exception caught by widgets library =======================================================
The following assertion was thrown while finalizing the widget tree:
'package:flutter_form_builder/src/form_builder.dart': Failed assertion: line 194 pos 12: '_fields.containsKey(name)': is not true.

When the exception was thrown, this was the stack: 
#2      FormBuilderState.unregisterField (package:flutter_form_builder/src/form_builder.dart:194:12)
#3      FormBuilderFieldState.dispose (package:flutter_form_builder/src/form_builder_field.dart:161:24)
#4      _FormBuilderTextFieldState.dispose (package:flutter_form_builder/src/fields/form_builder_text_field.dart:455:11)
-- Lots of duplicate lines removed here --
#208    ListIterable.forEach (dart:_internal/iterable.dart:39:13)
#209    _InactiveElements._unmountAll (package:flutter/src/widgets/framework.dart:1926:25)
#210    BuildOwner.lockState (package:flutter/src/widgets/framework.dart:2523:15)
#211    BuildOwner.finalizeTree (package:flutter/src/widgets/framework.dart:2947:7)
#212    WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:885:19)
#213    RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:378:5)
#214    SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1175:15)
#215    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1104:9)
#216    SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1015:5)
#217    _invoke (dart:ui/hooks.dart:148:13)
#218    PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:318:5)
#219    _drawFrame (dart:ui/hooks.dart:115:31)
(elided 2 frames from class _AssertionError)
====================================================================================================
Error # 2

This error is thrown because we use a global key for the form, which was not properly disposed due to the first error. This error is less important because it would get fixed in the first error is fixed.

======== Exception caught by widgets library =======================================================
The following assertion was thrown building KeyedSubtree-[GlobalKey#388b5]:
SingleChildRenderObjectElement unmounted
'package:flutter/src/widgets/framework.dart':
Failed assertion: line 5667 pos 12: '_renderObject != null'


Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=2_bug.md

The relevant error-causing widget was: 
  Scaffold Scaffold:file:///Users/H010675/StudioProjects/personal/projects/framework_example/lib/main.dart:45:12
When the exception was thrown, this was the stack: 
#2      RenderObjectElement.renderObject (package:flutter/src/widgets/framework.dart:5667:12)
#3      RenderObjectElement.detachRenderObject (package:flutter/src/widgets/framework.dart:6089:61)
#4      Element.detachRenderObject.<anonymous closure> (package:flutter/src/widgets/framework.dart:3738:13)
#5      ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:4931:14)
#6      Element.detachRenderObject (package:flutter/src/widgets/framework.dart:3737:5)
#7      Element.detachRenderObject.<anonymous closure> (package:flutter/src/widgets/framework.dart:3738:13)
#8      ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:4931:14)
#9      Element.detachRenderObject (package:flutter/src/widgets/framework.dart:3737:5)
#10     Element.detachRenderObject.<anonymous closure> (package:flutter/src/widgets/framework.dart:3738:13)
#11     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:4931:14)
#12     Element.detachRenderObject (package:flutter/src/widgets/framework.dart:3737:5)
#13     Element.detachRenderObject.<anonymous closure> (package:flutter/src/widgets/framework.dart:3738:13)
#14     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:4931:14)
#15     Element.detachRenderObject (package:flutter/src/widgets/framework.dart:3737:5)
#16     Element.detachRenderObject.<anonymous closure> (package:flutter/src/widgets/framework.dart:3738:13)
#17     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:4931:14)
#18     Element.detachRenderObject (package:flutter/src/widgets/framework.dart:3737:5)
#19     Element.detachRenderObject.<anonymous closure> (package:flutter/src/widgets/framework.dart:3738:13)
#20     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:4931:14)
#21     Element.detachRenderObject (package:flutter/src/widgets/framework.dart:3737:5)
#22     Element.detachRenderObject.<anonymous closure> (package:flutter/src/widgets/framework.dart:3738:13)
#23     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:4931:14)
#24     Element.detachRenderObject (package:flutter/src/widgets/framework.dart:3737:5)
#25     Element.detachRenderObject.<anonymous closure> (package:flutter/src/widgets/framework.dart:3738:13)
#26     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:4931:14)
#27     Element.detachRenderObject (package:flutter/src/widgets/framework.dart:3737:5)
#28     Element.detachRenderObject.<anonymous closure> (package:flutter/src/widgets/framework.dart:3738:13)
#29     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:4931:14)
#30     Element.detachRenderObject (package:flutter/src/widgets/framework.dart:3737:5)
#31     Element.detachRenderObject.<anonymous closure> (package:flutter/src/widgets/framework.dart:3738:13)
#32     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:4931:14)
#33     Element.detachRenderObject (package:flutter/src/widgets/framework.dart:3737:5)
#34     Element.deactivateChild (package:flutter/src/widgets/framework.dart:3905:11)
#35     Element._retakeInactiveElement (package:flutter/src/widgets/framework.dart:3799:14)
#36     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3845:35)
#37     MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6435:36)
#38     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6447:32)
...     Normal element mounting (28 frames)
#66     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3863:16)
#67     MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6435:36)
#68     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6447:32)
...     Normal element mounting (136 frames)
#204    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3863:16)
#205    MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6435:36)
#206    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6447:32)
...     Normal element mounting (175 frames)
#381    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3863:16)
#382    MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6435:36)
#383    Element.updateChild (package:flutter/src/widgets/framework.dart:3592:18)
#384    RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:5964:32)
#385    MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6460:17)
#386    Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#387    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#388    StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11)
#389    Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#390    StatefulElement.update (package:flutter/src/widgets/framework.dart:5082:5)
#391    Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#392    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#393    Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#394    ProxyElement.update (package:flutter/src/widgets/framework.dart:5228:5)
#395    Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#396    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#397    Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#398    ProxyElement.update (package:flutter/src/widgets/framework.dart:5228:5)
#399    _InheritedNotifierElement.update (package:flutter/src/widgets/inherited_notifier.dart:107:11)
#400    Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#401    SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6307:14)
#402    Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#403    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#404    StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11)
#405    Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#406    StatefulElement.update (package:flutter/src/widgets/framework.dart:5082:5)
#407    Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#408    SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6307:14)
#409    Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#410    SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6307:14)
#411    Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#412    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#413    Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#414    ProxyElement.update (package:flutter/src/widgets/framework.dart:5228:5)
#415    Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#416    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#417    StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11)
#418    Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#419    BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2667:19)
#420    WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:882:21)
#421    RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:378:5)
#422    SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1175:15)
#423    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1104:9)
#424    SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1015:5)
#425    _invoke (dart:ui/hooks.dart:148:13)
#426    PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:318:5)
#427    _drawFrame (dart:ui/hooks.dart:115:31)
(elided 2 frames from class _AssertionError)
====================================================================================================

Solution:

I imagine the solution would involve checking the new widget name in didUpdateWidget, and properly handling the new field name. It could be as simple as unregisterField followed by registerField.

@Clavum Clavum added the bug Something isn't working label Jan 5, 2023
@deandreamatias
Copy link
Collaborator

Nice solution @Clavum
Thanks for contribution

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

Successfully merging a pull request may close this issue.

2 participants