Reputation: 303
The following minimally reproducible dummy code throws this error:
════════ Exception caught by widgets library ═══════════════════════════════════
Multiple widgets used the same GlobalKey.
════════════════════════════════════════════════════════════════════════════════
Restarted application in 987ms.
I/flutter (10106): Key: [LabeledGlobalKey<FormBuilderState>#070c0 GlobalFormKey #SignIn ]
════════ Exception caught by widgets library ═══════════════════════════════════
The following assertion was thrown while finalizing the widget tree:
Multiple widgets used the same GlobalKey.
The key [LabeledGlobalKey<FormBuilderState>#070c0 GlobalFormKey #SignIn ] was used by multiple widgets. The parents of those widgets were:
- FormBuilderWrapper-[LabeledGlobalKey<FormBuilderState>#070c0 GlobalFormKey #SignIn ]
- _BodyBuilder
A GlobalKey can only be specified on one widget at a time in the widget tree.
Dummy Code:
class SignInScreen extends StatelessWidget {
final GlobalKey<FormBuilderState> key =
GlobalKey<FormBuilderState>(debugLabel: 'GlobalFormKey #SignIn ');
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Dummy")),
body: FormBuilderWrapper(
key: key,
childrenInColumn: [
FormBuilderEmail(),
FormBuilderPassword(identifierForField: "password")
],
),
);
}
}
class FormBuilderWrapper extends StatelessWidget {
final List<Widget> childrenInColumn;
final Key key;
const FormBuilderWrapper({
@required this.key,
@required this.childrenInColumn,
});
@override
Widget build(BuildContext context) {
print("Key: $key");
return FormBuilder(
key: key,
child: Column(
children: this.childrenInColumn,
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
class FormBuilderEmail extends StatelessWidget {
const FormBuilderEmail({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return FormBuilderTextField(
name: "email",
);
}
}
class FormBuilderPassword extends StatelessWidget {
final String hintText;
final String identifierForField;
const FormBuilderPassword({
@required this.identifierForField,
this.hintText = "Password",
});
@override
Widget build(BuildContext context) {
return FormBuilderTextField(
name: identifierForField,
);
}
}
What I don't understand is that only 1 widget uses the Key and that's the FormBuilder
widget(I didn't count 'FormBuilderWrapper' as it merely passes the key to FormBuilder
)
Can anyone point me in the right direction as to why this is happening? An explanation of which are the "multiple widgets" using the same GlobalKey
would be great
Upvotes: 3
Views: 8887
Reputation: 2221
I received this same error in a form and it was quiet hard to debug where it was coming from.
I had a scaffold which redirected to an addItem
scaffold in a new screen. There I had a scaffold with the form and a GlobalKey
to work with the form.
This was the code I was using to save my item:
void _saveNewItem() {
if (_formKey.currentState != null) {
_formKey.currentState!.save();
final isValid = _formKey.currentState!.validate();
if (!isValid) {
return;
}
if (_editItem.id == 0) {
_editItem.copyWith(
id: (DateTime.now().millisecondsSinceEpoch / 10000).round(),
);
Provider.of<MyProvider>(context, listen: false).add(_editItem);
} else {
print('TODO: Save edit item');
}
Navigator.of(context).pop();
}
}
My mistake was creating an item that I did not pass to to my provider, instead I just had too change it to:
void _saveNewItem() {
if (_formKey.currentState != null) {
_formKey.currentState!.save();
final isValid = _formKey.currentState!.validate();
if (!isValid) {
return;
}
if (_editItem.id == 0) {
var addItem = _editItem.copyWith(
id: (DateTime.now().millisecondsSinceEpoch / 10000).round(),
);
Provider.of<MyProvider>(context, listen: false).add(addItem );
} else {
print('TODO: Save edit item');
}
Navigator.of(context).pop();
}
}
This does not seem to be related but the error of the question was then triggered and this solved the issue crashing with that Multiple widgets used the same GlobalKey.
after saving the form the second time.
Upvotes: 0
Reputation: 403
I got it why you were getting the error. It was because of this statement. It is recognizing variable name key as keyword key.
final GlobalKey<FormBuilderState> key =
GlobalKey<FormBuilderState>(debugLabel: 'GlobalFormKey #SignIn ');
Below is the modified version of the dummy code you uploaded. I didn't get any errors after execution but please check at your end.
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
class SignInScreen extends StatelessWidget {
final GlobalKey<FormBuilderState> _formkey =
GlobalKey<FormBuilderState>(debugLabel: 'GlobalFormKey #SignIn ');
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Dummy")),
body: FormBuilderWrapper(
fomrkey: _formkey,
childrenInColumn: [
FormBuilderEmail(),
FormBuilderPassword(identifierForField: "password")
],
),
);
}
}
class FormBuilderWrapper extends StatelessWidget {
final List<Widget> childrenInColumn;
final Key fomrkey;
const FormBuilderWrapper({
required this.fomrkey,
required this.childrenInColumn,
});
@override
Widget build(BuildContext context) {
print("Key: $fomrkey");
return FormBuilder(
key: fomrkey,
child: Column(
children: this.childrenInColumn,
),
);
}
}
class FormBuilderEmail extends StatelessWidget {
const FormBuilderEmail({
Key? fomrkey1,
}) : super(key: fomrkey1);
@override
Widget build(BuildContext context) {
return FormBuilderTextField(
name: "email",
);
}
}
class FormBuilderPassword extends StatelessWidget {
final String hintText;
final String identifierForField;
const FormBuilderPassword({
required this.identifierForField,
this.hintText = "Password",
});
@override
Widget build(BuildContext context) {
return FormBuilderTextField(
name: identifierForField,
);
}
}
Upvotes: 2
Reputation: 1319
They are using the same key because when you create the FormBuilderWrapper
you pass the key to it, and then inside you return a formBuilder passing the same key you gave the FormBuilderWrapper
.
for what i understand, it does not matter that the key just "passes by" and goes to the FormBuilder
, because FormBuilderWrapper
is still being created with that key.
Upvotes: 0