I know, It is asked many time but none of the solution is working.
There is a bank list in first drop down, On bank selection an api is being called for branch in second drop down after selection of branch for first time it is working fine, When bank is changed again api is being called to get branch of respective bank that time issue is coming because already selected branch has value, I’m trying to clear previous selected value of branch and making list empty before populating branch. Issue is coming because branch area is same in other bank also but branch id is unique. when branch list is empty or not having same branch area that time there is no issue.
I tried to "overrried" method for comparing branch but not working
this is model class for branch.
class Branch {
final int? bankId;
final int? branchId;
final String? ifscCode;
final String? descriptionEn;
final dynamic descriptionLl;
Branch({
this.bankId,
this.branchId,
this.ifscCode,
this.descriptionEn,
this.descriptionLl,
});
factory Branch.fromJson(Map<String, dynamic> json) => Branch(
bankId: json["bank_id"],
branchId: json["branch_id"],
ifscCode: json["ifsc_code"],
descriptionEn: json["description_en"],
descriptionLl: json["description_ll"],
);
@override
String toString() {
return descriptionEn.toString();
}
@override
bool operator ==(dynamic other) {
return other != null && branchId == other.branchId &&
descriptionEn == other.descriptionEn;
}
}
After getting state change of branch making previous selected branch null
else if (state is GetBranchSuccessState) {
selectedBranch = null;
ifsc = null;
branchList=[];
branchList = state.data.data!;
}
Whenever choosing same bank as i firstly selected getting no issue it seems selected value is getting store?
My Widget
BlocConsumer<InternalRegistrationBloc, InternalRegistrationState>(
listener: (context, state) {
if (state is GetBankSuccessState) {
dismissProgress();
} else if (state is GetBranchSuccessState) {
dismissProgress();
}
},
builder: (context, state) {
if (state is GetBankSuccessState) {
bankList = state.data.data!;
} else if (state is GetBranchSuccessState) {
selectedBranch = null;
ifsc = null;
branchList = [];
branchList = state.data.data!;
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Form(
key: _gformKey,
child: Column(
children: [
QDropDownList(
title: 'Bank name',
dropdownList: bankList,
selectedItem: selectedBank,
isMandatory: isBankUser,
onChanged: (value) {
selectedBank = value;
if (selectedBank != null) {
bloc.add(BranchEvent(selectedBank!.bankId!));
}
},
),
QDropDownList(
title: 'Branch name',
dropdownList: branchList,
selectedItem: selectedBranch,
isMandatory: isBankUser,
onChanged: (value) {
selectedBranch = value;
bloc.add(
SetIFSCCodeEvent(selectedBranch!.ifscCode!));
},
)
],
),
),
],
);
},
),
In Image, bank of india getting issue because branch list contain the same branch ares name as Axis Bank contain, It has no issue when i select Bank of rajshthan becuase it has no branch list. when selecting Axis Bank bank getting no issue and getting old value.
Custom drop down
import 'package:flutter/material.dart';
class QDropDownList extends StatefulWidget {
final ValueChanged<dynamic> onChanged;
final List<dynamic> dropdownList;
final dynamic selectedItem;
final bool isTitleAbove;
final String title;
final bool isMandatory;
final String dropDownHint;
final Icon arrowIcon;
const QDropDownList(
{super.key,
required this.onChanged,
required this.dropdownList,
required this.selectedItem,
this.isTitleAbove = true,
this.title = 'Title',
this.isMandatory = true,
this.dropDownHint = 'Select',
this.arrowIcon = const Icon(
Icons.keyboard_arrow_down,
size: 15,
)});
@override
State<QDropDownList> createState() => _QDropDownListState();
}
class _QDropDownListState extends State<QDropDownList> {
dynamic selectedItem;
@override
void initState() {
super.initState();
selectedItem = widget.selectedItem;
}
@override
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
widget.isTitleAbove
? Padding(
padding: const EdgeInsets.only(top: 8.0),
child: RichText(
text: TextSpan(
text: widget.title,
style: Theme.of(context).inputDecorationTheme.labelStyle,
children: [
TextSpan(
text: widget.isMandatory ? ' *' : '',
style: Theme.of(context)
.inputDecorationTheme
.labelStyle
?.copyWith(color: Colors.red))
]),
),
)
: const SizedBox(),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: SizedBox(
width: MediaQuery.of(context).size.width,
child: DropdownButtonFormField<dynamic>(
value: selectedItem,
icon: widget.arrowIcon,
isDense: true,
isExpanded: false,
style: Theme.of(context).dropdownMenuTheme.textStyle,
hint: Text(widget.dropDownHint,
style: Theme.of(context).dropdownMenuTheme.textStyle),
// ignore: prefer_is_empty
items:widget.dropdownList.length>0? widget.dropdownList.map((data) {
return DropdownMenuItem<dynamic>(
value: data,
child: Text(
data.toString(),
style: Theme.of(context).dropdownMenuTheme.textStyle,
),
);
}).toList():[],
onChanged: (dynamic value) {
setState(() {
selectedItem = value;
widget.onChanged(value);
debugPrint('Drop down change ---> $selectedItem');
});
},
validator: (value) {
if (widget.isMandatory) {
return value == null ? 'Field required' : null;
} else {
return null;
}
},
),
)),
],
);
}
}
>Solution :
The problem lies in QDropDownList. The widget gets a selectedValue but its state has a separate selectedValue. This one is only set in the initState. Which means that later on when you set the selectedValue to null it will not be changed in its state because that only happens when it’s first initialized in initState My suggestion is to completely remove the one from the state and rely on the widget’s selectedState. So in all:
Remove these lines:
dynamic selectedItem;
@override
void initState() {
super.initState();
selectedItem = widget.selectedItem;
}
Change:
value: selectedItem,
to
value: widget.selectedItem,
And finally change
onChanged: (dynamic value) {
setState(() {
selectedItem = value;
widget.onChanged(value);
debugPrint('Drop down change ---> $selectedItem');
});
},
to
onChanged: (dynamic value) {
setState(() {
widget.onChanged(value);
debugPrint('Drop down change ---> $selectedItem');
});
},
Note that you don’t need to set a selected state here because the widgets onChanged will take care of that
