如何在flutter中将项目ID从第一个下拉列表传递到第二个下拉列表?
在此代码中,有三个下拉菜单,我想将第一个部分的ID传递给第二个下拉菜单。部分ID成功传递到第二个dropdwon,但是从第一个dropdowm中选择项目时显示错误:
第一次运行很好,但是第二次选择项目时显示错误
import 'package:async_loader/async_loader.dart';
import 'package:flutter/material.dart';
import 'package:flutter_application_practice/dashboard.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class Homework extends StatefulWidget {
@override
_HomeworkState createState() => _HomeworkState();
}
class _HomeworkState extends State<Homework> {
var stdDesc;
Future api;
Future api1;
Future api2;
Standard _gradeSelection;
Details _sectionSelection;
Subject _subjectSelection;
List <Standard> list = [];
String get schoolCode => '';
String get employeeId => '';
String get imeINo => '';
String get standardId => dropdownStandardId.toString();
String get sectionId => dropdownSectionId.toString();
String get subjectId => '';
var dropdownStandardId;
var dropdownSectionId;
final GlobalKey<AsyncLoaderState> asyncLoaderState =
new GlobalKey<AsyncLoaderState>();
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
var _asyncLoader = new AsyncLoader(
key: asyncLoaderState,
initState: () async => await fetchAssignmentStd(),
renderLoad: () => Center(child: new CircularProgressIndicator()),
renderError: ([error]) => getNoConnectionWidget(),
renderSuccess: ({data}) => standard(),
);
return Stack(
children: <Widget>[
Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
title: Text('Homework'),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () =>
Navigator.push(context,
MaterialPageRoute(
builder: (context) => DashBoard()))),
),
body: ListView(
physics: ScrollPhysics(),
shrinkWrap: true,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10),
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(7.0),
border: Border.all(color: Colors.black)),
height: 40,
margin: EdgeInsets.only(left: 10, right: 10),
padding: EdgeInsets.only(left: 30),
child:_asyncLoader
),
Padding(
padding: EdgeInsets.only(top: 10),
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(7.0),
border: Border.all(color: Colors.black)),
height: 40,
margin: EdgeInsets.only(left: 10, right: 10),
padding: EdgeInsets.only(left: 30),
child:section(),
),
Padding(
padding: EdgeInsets.only(top: 10),
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(7.0),
border: Border.all(color: Colors.black)),
height: 40,
margin: EdgeInsets.only(left: 10, right: 10),
padding: EdgeInsets.only(left: 30),
child: subject(),
),
],
);
}
Widget standard() {
return DropdownButton<Standard>(
icon: Icon(Icons.arrow_drop_down, color: Colors.black),
iconSize: 50,
elevation: 5,
isExpanded: true,
isDense: true,
value: _gradeSelection,
hint: Text('Select Standard'),
onChanged: (Standard newValue) {
setState(() {
_gradeSelection = newValue;
dropdownStandardId = _gradeSelection.stdId;
api1 = fetchAssignmentStdSec(dropdownStandardId);
print('dropdownStandardId ${_gradeSelection.stdDesc} ${_gradeSelection.stdId}');
});
},
items: list.map((Standard standard) {
return DropdownMenuItem<Standard>(
value: standard,
child: Text(standard.stdDesc),
);
}).toList(),
);
}
Widget section() {
return dropdownStandardId!=null
? FutureBuilder<List<Details>>(
future: api1,
builder: (BuildContext context, AsyncSnapshot<List<Details>> snapshot) {
return snapshot.data != null
? DropdownButton<Details>(
icon: Icon(Icons.arrow_drop_down, color: Colors.black),
iconSize: 50,
elevation: 5,
hint: Text('Select Section ID'),
isExpanded: true,
isDense: true,
value: _sectionSelection,
onChanged: (Details newValue) {
setState(() {
_sectionSelection = newValue;
dropdownSectionId = _sectionSelection.secId;
api2 = fetchAssignmentSubj(dropdownStandardId, dropdownSectionId);
print('dropdownStandardId ${_sectionSelection.secDesc} ${_sectionSelection.secId}');
});
},
items: snapshot.data.map((Details section) {
return DropdownMenuItem<Details>(
value: section,
child: Text(section.secDesc),
);
}).toList(),
) : Container();
},
):Container();
}
Widget subject(){
return dropdownStandardId != null && dropdownSectionId !=null ?
FutureBuilder<List<Subject>>(
future: api2,
builder: (BuildContext context, snapshot) {
return snapshot.data != null ?
DropdownButton<Subject>(
icon: Icon(Icons.arrow_drop_down, color: Colors.black),
iconSize: 50,
elevation: 5,
isExpanded: true,
isDense: true,
hint: Text('Select Subject'),
value: _subjectSelection,
onChanged: (newValue) {
setState(() {
_subjectSelection = newValue;
});
},
items: snapshot.data.map((Subject subject) {
return DropdownMenuItem(
value: subject,
child: Text(subject.subDesc),
);
}).toList(),
) : Container();
}
) :Container();
}
Future <List<Standard>> fetchAssignmentStd() async {
var apiUrl =
'url';
Map<String, String> headers = {
'content-type': 'application/x-www-form-urlencoded'
};
Map<String, String> body = {
'imei_no': '',
'school_code': '',
'employee_id': '',
};
http.Response response = await http.post(apiUrl, body: body, headers: headers);
var res = json.decode(response.body);
var standard = res['standard'];
list = standard.map<Standard>((json) => Standard.fromJson(json)).toList();
print('standard $list');
return list;
}
Future <List<Details>> fetchAssignmentStdSec(String standardId) async {
var apiUrl = 'url1';
Map<String, String> headers = {
'content-type': 'application/x-www-form-urlencoded'
};
Map<String, String> body = {
'imei_no': '',
'school_code': '',
'employee_id': '',
'standard_id': standardId,
};
http.Response response = await http.post(
apiUrl, body: body, headers: headers);
var res = json.decode(response.body);
print('res $res');
var section = res['section'];
List <Details> list = [];
list = section.map<Details>((json) => Details.fromJson(json)).toList();
print('section $list');
return list;
}
Future <List<Subject>> fetchAssignmentSubj(String standardId,
String sectionId) async {
var apiUrl = 'url';
Map<String, String> headers = {
'content-type': 'application/x-www-form-urlencoded'
};
Map<String, String> body = {
'imei_no': '',
'school_code': '',
'employee_id': '',
'standard_id': standardId,
'section_id': sectionId,
};
http.Response response = await http.post(
apiUrl, body: body, headers: headers);
var res = json.decode(response.body);
var subject = res['subject'];
List <Subject> list = [];
list = subject.map<Subject>((json) => Subject.fromJson(json)).toList();
print('subject $list');
return list;
}
}
class Standard {
String stdId;
String stdDesc;
Standard({this.stdId, this.stdDesc});
factory Standard.fromJson(Map<String, dynamic> json) {
return Standard(
stdId: json["std_id"].toString(),
stdDesc: json["std_desc"],
);
}
}
class Details {
String secId;
String secDesc;
Details({this.secId, this.secDesc,});
factory Details.fromJson(Map<String, dynamic> json) {
return Details(
secId: json["sec_id"].toString(),
secDesc: json["sec_desc"],
);
}
}
class Subject {
String subId;
String subDesc;
Subject({this.subId, this.subDesc,});
factory Subject.fromJson(Map<String, dynamic> json) {
return Subject(
subId: json["sub_id"].toString(),
subDesc: json["sub_desc"],
);
}
}
How to solve this ?
When select value from first dropdown its section id pass successfully to second dropdown and working well but when I'm selecting second time value from first dropdown it showing error : There should be exactly one item with [DropdownButton]'s value: Instance of 'Details'.
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value
'package:flutter/src/material/dropdown.dart':
Failed assertion: line 805 pos 15: 'items == null || items.isEmpty || value == null ||
items.where((DropdownMenuItem<T> item) {
return item.value == value;
}).length == 1'