[英]How to make dependent multilevel DropDown in flutter?
我试图使依赖的多级下拉列表首先包含州列表,第二个包含城市列表,所有数据都是从 API 获取的。 最初,我加载状态下拉列表,当我选择状态时,然后加载该状态的城市,如果我选择城市,则城市选择成功,但是当我更改状态值时会发生错误。 如果在第一个下拉列表中进行更改,重新加载第二个下拉列表的正确方法是什么?
错误:应该只有一项具有 [DropdownButton] 的值:“城市”的实例。 检测到零个或 2 个或更多 [DropdownMenuItem] 具有相同的值
Future _state;
Future _city;
@override
void initState() {
super.initState();
_state = _fetchStates();
}
Future<List<StateModel>> _fetchStates() async {
final String stateApi = "https://dummyurl/state.php";
var response = await http.get(stateApi);
if (response.statusCode == 200) {
final items = json.decode(response.body).cast<Map<String, dynamic>>();
List<StateModel> listOfUsers = items.map<StateModel>((json) {
return StateModel.fromJson(json);
}).toList();
return listOfUsers;
} else {
throw Exception('Failed to load internet');
}
}
Future<List<City>> _fetchCities(String id) async {
final String cityApi = "https://dummyurl/city.php?stateid=$id";
var response = await http.get(cityApi);
if (response.statusCode == 200) {
final items = json.decode(response.body).cast<Map<String, dynamic>>();
print(items);
List<City> listOfUsers = items.map<City>((json) {
return City.fromJson(json);
}).toList();
return listOfUsers;
} else {
throw Exception('Failed to load internet');
}
}
状态下拉菜单
FutureBuilder<List<StateModel>>(
future: _state,
builder: (BuildContext context,
AsyncSnapshot<List<StateModel>> snapshot) {
if (!snapshot.hasData)
return CupertinoActivityIndicator(animating: true,);
return DropdownButtonFormField<StateModel>(
isDense: true,
decoration: spinnerDecoration('Select your State'),
items: snapshot.data
.map((countyState) => DropdownMenuItem<StateModel>(
child: Text(countyState.billstate),
value: countyState,
))
.toList(),
onChanged:(StateModel selectedState) {
setState(() {
stateModel = selectedState;
_city = _fetchCities(stateModel.billstateid);
});
},
value: stateModel,
);
}),
城市下拉菜单
FutureBuilder<List<City>>(
future: _city,
builder: (BuildContext context,
AsyncSnapshot<List<City>> snapshot) {
if (!snapshot.hasData)
return CupertinoActivityIndicator(animating: true,);
return DropdownButtonFormField<City>(
isDense: true,
decoration: spinnerDecoration('Select your City'),
items: snapshot.data
.map((countyState) => DropdownMenuItem<City>(
child: Text(countyState.billcity)
.toList(),
onChanged: (City selectedValue) {
setState(() {
cityModel = selectedValue;
});
},
value: cityModel,
);
}),
class StateModel {
String billstateid;
String billstate;
String billcountryid;
StateModel({this.billstateid, this.billstate, this.billcountryid});
StateModel.fromJson(Map<String, dynamic> json) {
billstateid = json['billstateid'];
billstate = json['billstate'];
billcountryid = json['billcountryid'];
}
}
class City {
String billcityid;
String billcity;
String billstateid;
City({this.billcityid, this.billcity, this.billstateid});
City.fromJson(Map<String, dynamic> json) {
billcityid = json['billcityid'];
billcity = json['billcity'];
billstateid = json['billstateid'];
}
您必须在 State 下拉菜单的onChanged
回调中使cityModel = null
。
setState(() {
cityModel = null;
stateModel = selectedState;
_city = _fetchCities(stateModel.billstateid);
});
应该只有一项具有 [DropdownButton] 的值:“城市”的实例。 检测到零个或 2 个或更多 [DropdownMenuItem] 具有相同的值
此处发生此错误,因为您传递的value
不在DropdownButtonFormField
(城市下拉列表)的items
中。
当您选择一个州时,您正在获取城市列表的新列表并将其传递给 CityDropDown 但忘记清除先前选择的城市( cityModel
)。
你也可以参考这个例子: DartPad
我也面临一个问题,直到未获取新状态数据它显示以前的状态数据。 我使用的方法是不同的。 我没有使用未来的构建器。 这是我的代码:
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Expanded(
child: new Container(
width: 450,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Source",
style: TextStyle(
fontSize: 15, fontWeight: FontWeight.bold),
),
source1 != null ? DropdownButtonFormField<String>(
isExpanded: true,
validator: (value) => value == null ? 'field required' : null,
hint: Text("Select Source"),
items: source1.data.map((item) {
// print("Item : $item");
return DropdownMenuItem<String>(
value: item.descr,
child: Text(item.descr),
);
}).toList(),
onChanged: (String cat) {
setState(() {
subsourseStr = null;
sourceStr = cat;
getSubSource2(sourceStr);
});
},
value: sourceStr,
):SizedBox(height: 10),
],
),
),
)
],
),
),
//
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Expanded(
child: new Container(
width: 450,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Sub Source",
style: TextStyle(
fontSize: 15, fontWeight: FontWeight.bold),
),
subSource2 != null ? DropdownButtonFormField<String>(
isExpanded: true,
validator: (value) => value == null ? 'field required' : null,
hint: Text("Select Sub Source"),
items: subSource2.data.map((item) {
return DropdownMenuItem<String>(
value: item.descr,
child: Text(item.descr),
);
}).toList(),
onChanged: (String cat) {
setState(() {
subsourseStr = cat;
});
},
value: subsourseStr,
):SizedBox(height: 10,),
],
),
),
)
],
),
),
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.