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

Strange error in FormBuilderDropdown #61

Closed
shariful2011 opened this issue May 19, 2019 · 14 comments
Closed

Strange error in FormBuilderDropdown #61

shariful2011 opened this issue May 19, 2019 · 14 comments

Comments

@shariful2011
Copy link

I have 3 FormBuilderDropdown which's item are filling from the database. They are totally linked. Like:

  1. Country
  2. Governorate
  3. District and so on...

My Scope is if Country selected it will refresh all FormBuilderDropdown.
Not getting any exception until I select a data on 3rd FormBuilderDropdown that is the District. If I not selecting any data on that FormBuilderDropdown nothing is raising, but when I change any Governorate FormBuilderDropdown I got following exception but I still have items for the District FormBuilderDropdown which is 5 as print. This is my code:

Widget districtDropDown(
{ValueChanged changed,
List<DropdownMenuItem> items,
String attribute}) {
print('district=${items.length}');
return items.length == 0
? FormBuilderDropdown(
attribute: attribute,
hint: Text('Select District'),
onChanged: changed,
decoration: InputDecoration(
labelText: 'District',
labelStyle: TextStyle(
fontFamily: 'Open Sans',
),
),
validators: [
FormBuilderValidators.required(
errorText: 'Please select District.'),
],
initialValue: '',
items: [],
)
: FormBuilderDropdown(
attribute: attribute,
hint: Text('Select District'),
onChanged: changed,
decoration: InputDecoration(
labelText: 'District',
labelStyle: TextStyle(
fontFamily: 'Open Sans',
),
),
validators: [
FormBuilderValidators.required(
errorText: 'Please select District.'),
],
items: items,
);
}

I/flutter ( 6651): district=5
I/flutter ( 6651): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 6651): The following assertion was thrown building
I/flutter ( 6651): FormField-[LabeledGlobalKey<FormFieldState>#8e04e](dirty, dependencies:
I/flutter ( 6651): [_FormScope], state: FormFieldState#2e15b):
I/flutter ( 6651): 'package:flutter/src/material/dropdown.dart': Failed assertion: line 609 pos 15: 'items == null ||
I/flutter ( 6651): items.isEmpty || value == null || items.where((DropdownMenuItem item) => item.value ==
I/flutter ( 6651): value).length == 1': is not true.
I/flutter ( 6651):

@danvick
Copy link
Collaborator

danvick commented May 19, 2019

Hi @shariful2011,
This assertion fail is actually not a big issue. Here's where it comes from: Your initial value for the DropdownButton is empty - '' which is not part of the options in provided for the user to select.

You could avoid this assertion fail by having initialValue to be null instead of ''

@danvick danvick closed this as completed May 19, 2019
@shariful2011
Copy link
Author

I update as per you said but still same error. I did check if the items is null or not so why still the exception. Please see the image http://prntscr.com/nqnd0h

@danvick
Copy link
Collaborator

danvick commented May 19, 2019

Kindly paste your updated code

@danvick danvick reopened this May 19, 2019
@shariful2011
Copy link
Author

Widget districtDropDown(
{ValueChanged changed,
List<DropdownMenuItem> items,
String attribute}) {
print('district=${items.length}');
return items.length == 0
? FormBuilderDropdown(
attribute: attribute,
hint: Text('Select District'),
onChanged: changed,
decoration: InputDecoration(
labelText: 'District',
labelStyle: TextStyle(
fontFamily: 'Open Sans',
),
),
validators: [
FormBuilderValidators.required(
errorText: 'Please select District.'),
],
initialValue: null,
items: [],
)
: FormBuilderDropdown(
attribute: attribute,
hint: Text('Select District'),
onChanged: changed,
decoration: InputDecoration(
labelText: 'District',
labelStyle: TextStyle(
fontFamily: 'Open Sans',
),
),
validators: [
FormBuilderValidators.required(
errorText: 'Please select District.'),
],
initialValue: null,
items: items,
);

@danvick
Copy link
Collaborator

danvick commented May 19, 2019

Unfortunately, I'm unable to reproduce your issue - when I make the initialValue: null the app works as expected (no errors).

Try restarting your app instead of hot reload.

@shariful2011
Copy link
Author

Problem is not with initialValue, See the error:
I/flutter ( 6651): items.isEmpty || value == null || items.where((DropdownMenuItem item) => item.value ==
I/flutter ( 6651): value).length == 1': is not true.

I did a test by restarting the app. The problem occurs only on the 3rd DropDown when it has selected item.

@danvick
Copy link
Collaborator

danvick commented May 19, 2019

Kindly note first that the error is from the underlying Flutter's DropdownButton and is a common error.

Here's what I understand from the error. The dropdown tries to assert that either of these conditions are met.

  1. Either your list of options is empty
  2. Or the initial value set is null
  3. If you have a list of options - and the selected item is not null - then there should be at least one option from the list of options whose value matches the item that was selected.

Is it possible for you to share more code - especially the part where you are calling the districtDropDown function.

@shariful2011
Copy link
Author

class DistrictDropDown extends StatelessWidget {
final MainModel model;
final ValueChanged onChanged;
final String attribute;
const DistrictDropDown({Key key, this.model, this.onChanged, this.attribute})
: super(key: key);

@OverRide
Widget build(BuildContext context) {
return model.selectedGovernorate == null
? districtDropDown(
attribute: attribute,
changed: onChanged,
items: [],
)
: FutureBuilder<List>(
future: DBProvider.db.getAllDistrict(model.selectedGovernorate),
builder:
(BuildContext context, AsyncSnapshot<List> snapshot) {
if (!snapshot.hasData) {
return districtDropDown(
attribute: attribute,
changed: onChanged,
items: [],
);
} else {
return districtDropDown(
attribute: attribute,
changed: onChanged,
items: snapshot.data.map((District c) {
return DropdownMenuItem(
value: c.id.toString(),
child: Text(
c.name,
),
);
}).toList(),
);
}
},
);
}
}

Future<List> getAllDistrict(int governorateid) async {
final db = await database;
var res = await db.query(
"district",
where: 'governorateid = ?',
whereArgs: [governorateid],
orderBy: 'name',
);
List list =
res.isNotEmpty ? res.map((c) => District.fromMap(c)).toList() : [];
return list;
}

@shariful2011
Copy link
Author

Please see the video https://mega.nz/#!uttGgCDY!ipUCrFw5zarVAqClZaQmtnC21Y2XH5XDpHkv6aUSHUc from which you can undrstand.

@danvick
Copy link
Collaborator

danvick commented May 20, 2019

Sorry for the late response. Timezone issues.

I've seen the video. Does your District options change depending on the Governorate dropdown?

@shariful2011
Copy link
Author

Yes, as I said all my dropdown are interlinked.

@dwhub
Copy link

dwhub commented May 20, 2019

@shariful2011 - if your dropdown item list is changed depend on other form field, I think you should use FormBuilderCustomField instead just like in the readme description.
I got this issue as well and solve it using FormBuilderCustomField.

@danvick
Copy link
Collaborator

danvick commented May 20, 2019

Here's what's happening in your specific scenario: Since your list of options will change at runtime, there will be a point in time where option you already selected is not part of the newly available options that's the point where the assertion will fail.
Steps happening in your video:

  1. Select Country (Somalia) - list of options added to Governorates dropdown

  2. Select Governorate (Bay)-> list of options added to Districts dropdown

  3. Select District (Qansahdere) - At this point everything is working fine at this point...

  4. Change Governorate to Galgadud - Now the list of options for Districts changes, but you had already selected Qansahdere which is not in the updated list of options for Districts, right?
    So essentially at that point in time you have an option selected which is not part of the updated list of options - and that's where the assertion fails.

Point to note: Your error in an assertion error which essentially means it will be ignored in production, you can choose to ignore it during development.

Another option you have is that before changing the Governorate, make sure nothing is selected in District.

Last point - This is not an assertion failure on Flutter's underlying DropdownButton and not in FormBuilderDropdown

@danvick danvick closed this as completed May 20, 2019
@shariful2011
Copy link
Author

How can I make sure nothing is selected in District? Is there an option to clear it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants