The value that I chose from the DropdownMenuItem (eg: Malaysia (+06) ), the chosen value will be displayed, however, when I navigate back or proceed to other interfaces, it will disappear.
Problem:
How to make the chosen value maintained at the dropdown button box?
Is it any solution to solve the problem?
Below is my code segment inside showModalBottomSheet:
String _selectedCountryCode;
List jsonResult = List();
loadJsonData() async {
String data = await rootBundle.loadString('assets/country_code.json');
jsonResult = json.decode(data);
print(jsonResult);
}
#override
void initState() {
super.initState();
loadJsonData();
phoneController = TextEditingController();
}
Widget Part
Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
TextButton(
onPressed: () {
_showModalPhoneWidget();
},
child: Text(
"Request OTP", style: TextStyle(
color: const Color(0xff002aff),
fontSize: 15,
),
),)
],
)
_showModalPhoneWidget method part
_showModalPhoneWidget() {
showModalBottomSheet(
backgroundColor: Colors.green,
context: context,
isDismissible: true,
//transitionAnimationController: Duration(milliseconds: 400),
builder: (context) {
return StatefulBuilder(
builder: (context, setStateSTB) => ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
topRight: Radius.circular(10.0)),
child: Container(
height: 250,
color: Colors.white,
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10.0),
child: Text(
"Update Phone",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
),
),
Padding(
padding: EdgeInsets.only(top: 20.0, left: 10.0),
child: Row(
children: <Widget>[
Text(
"Tel No",
style:
TextStyle(color: Colors.black, fontSize: 15.0),
),
Text(
"*",
style: TextStyle(color: Colors.red, fontSize: 15.0),
),
],
),
),
Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
height: 50.0,
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: const Color(0xffededed))),
child: Stack(
children: <Widget>[
Row(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 5.0, left: 5.0),
height: 40.0,
width: 100.0,
child: DropdownButtonHideUnderline(
child: ButtonTheme(
alignedDropdown: false,
child: DropdownButton(
// child: DropdownButton<Map<String, String>>(
isExpanded: true,
value: _selectedCountryCode,
selectedItemBuilder: (BuildContext context)
{
return jsonResult.map<Widget>((element) {
return Text("${element['dial_code']}", textAlign: TextAlign.center);
}).toList();
},
items: jsonResult.map((element) {
return DropdownMenuItem(
child: Text("${element['name']} (${element['dial_code']})", overflow: TextOverflow.clip, maxLines: 1,),
value: element['dial_code'],
);
}).toList(),
onChanged: (val) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
//* to change on dialog
setStateSTB(() {
_selectedCountryCode = val;
prefs.setString('_selectedCountryCode', _selectedCountryCode);
print('select code: $_selectedCountryCode' );
});
//* to change on StateLevel
setState(() {
_selectedCountryCode = val;
prefs.setString('_selectedCountryCode', _selectedCountryCode);
});
},
),
),
),
),
// if(_isEditingText)
Container(
width: 120,
height: 40,
child: TextField(
controller: phoneController,
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
], // Only numbers can be entered
textAlign: TextAlign.center,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Tel No. Ex:0133333333',
),
onSubmitted: (newPhoneNo) {
setState(() {
initialText = newPhoneNo;
_isEditingText = false;
});
},
),
),
Container(
height: 40,
width: 100,
child: InkWell(
onTap: () {
setState(() {
_isEditingText = true;
});
},
),
),
],
)
],
),
),
Container(
margin: EdgeInsets.all(20.0),
child: ButtonTheme(
minWidth: double.infinity,
height: 50,
child: OutlineButton(
child: Text("Continue",
style: TextStyle(color: Colors.amber, fontSize: 16)),
borderSide: BorderSide(
color: Colors.amber,
),
highlightElevation: 10.0,
onPressed: () {
},
),
),
),
],
),
),
),
);
});
}
and this is my local JSON data:
[
{
"name": "Malaysia",
"dial_code": "+60",
"code": "MY"
},
{
"name": "Afghanistan",
"dial_code": "+93",
"code": "AF"
},
{
"name": "Aland Islands",
"dial_code": "+358",
"code": "AX"
},
{
"name": "Albania",
"dial_code": "+355",
"code": "AL"
},
{
"name": "Algeria",
"dial_code": "+213",
"code": "DZ"
},
{
"name": "AmericanSamoa",
"dial_code": "+1684",
"code": "AS"
},
{
"name": "Andorra",
"dial_code": "+376",
"code": "AD"
},
{
"name": "Angola",
"dial_code": "+244",
"code": "AO"
},
{
"name": "Anguilla",
"dial_code": "+1264",
"code": "AI"
},
{
"name": "Antarctica",
"dial_code": "+672",
"code": "AQ"
},
{
"name": "Antigua and Barbuda",
"dial_code": "+1268",
"code": "AG"
},
{
"name": "Argentina",
"dial_code": "+54",
"code": "AR"
},
{
"name": "Armenia",
"dial_code": "+374",
"code": "AM"
},
{
"name": "Aruba",
"dial_code": "+297",
"code": "AW"
},
{
"name": "Australia",
"dial_code": "+61",
"code": "AU"
},
{
"name": "Austria",
"dial_code": "+43",
"code": "AT"
},
{
"name": "Azerbaijan",
"dial_code": "+994",
"code": "AZ"
},
{
"name": "Bahamas",
"dial_code": "+1242",
"code": "BS"
},
{
"name": "Bahrain",
"dial_code": "+973",
"code": "BH"
},
{
"name": "Bangladesh",
"dial_code": "+880",
"code": "BD"
},
{
"name": "Barbados",
"dial_code": "+1246",
"code": "BB"
},
{
"name": "Belarus",
"dial_code": "+375",
"code": "BY"
},
{
"name": "Belgium",
"dial_code": "+32",
"code": "BE"
},
]
For problem 1 you can have the Map for DropdownMenuItem. While showing only name and dial_code you can set child like
items: jsonResult.map((element) {
return DropdownMenuItem(
child: Text(
"${element['name']} ${element['dial_code']}"),
value: element,
);
}).toList(),
For problem 2 updating state on dialog needs to use StatefulBuilder and use its setstate to update on dialog, prefer renaming this.
return StatefulBuilder(
builder: (context, setStateSTB) => ClipRRect(
......
onChanged: (_selectedCountryCode) {
//* to change on dialog
setStateSTB(() {
_defaultCountryCode = _selectedCountryCode;
});
//* to change on StateLevel
setState(() {
_defaultCountryCode = _selectedCountryCode;
});
},
Update the issue was on loadJsonData()
Future<void> loadJsonData() async {
///
String data = await rootBundle.loadString('assets/country_code.json');
final jsonString = jsonDecode(data) as List;
final item = jsonString.map((e) {
return {
'name': e['name'] as String,
'dial_code': e['dial_code'] as String,
'code': e['code'] as String,
};
}).toList();
setState(() {
jsonResult = item;
});
}
Full snippet
class _TFTState extends State<TFT> {
Map<String, String>? _defaultCountryCode;
late List<Map<String, String>> jsonResult;
#override
void initState() {
super.initState();
loadJsonData();
}
Future<void> loadJsonData() async {
///
String data = await rootBundle.loadString('assets/country_code.json');
final jsonString = jsonDecode(data) as List;
final item = jsonString.map((e) {
return {
'name': e['name'] as String,
'dial_code': e['dial_code'] as String,
'code': e['code'] as String,
};
}).toList();
setState(() {
jsonResult = item;
});
}
final phoneController = TextEditingController();
_showModalPhoneWidget() {
showModalBottomSheet(
backgroundColor: Colors.green,
context: context,
isDismissible: true,
//transitionAnimationController: Duration(milliseconds: 400),
builder: (context) {
return StatefulBuilder(
builder: (context, setStateSTB) => ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
topRight: Radius.circular(10.0)),
child: Container(
height: 250,
color: Colors.white,
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10.0),
child: Text(
"Update Phone",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
),
),
Padding(
padding: EdgeInsets.only(top: 20.0, left: 10.0),
child: Row(
children: <Widget>[
Text(
"Tel No",
style:
TextStyle(color: Colors.black, fontSize: 15.0),
),
Text(
"*",
style: TextStyle(color: Colors.red, fontSize: 15.0),
),
],
),
),
Container(
margin:
EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
height: 50.0,
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: const Color(0xffededed))),
child: Row(
children: <Widget>[
DropdownButtonHideUnderline(
child: ButtonTheme(
alignedDropdown: true,
child: DropdownButton<Map<String, String>>(
value: _defaultCountryCode,
hint: Text("Hint textOn null"),
items: jsonResult.map((element) {
return DropdownMenuItem(
child: Text(
"${element['name']} ${element['dial_code']}"),
value: element,
);
}).toList(),
onChanged: (_selectedCountryCode) {
//* to change on dialog
setStateSTB(() {
_defaultCountryCode = _selectedCountryCode;
});
//* to change on StateLevel
setState(() {
_defaultCountryCode = _selectedCountryCode;
});
},
),
),
),
Container(
width: 250,
height: 40,
child: TextField(
controller: phoneController,
textAlign: TextAlign.start,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Tel No. Ex:0133333333',
),
),
),
],
),
),
Container(
margin: EdgeInsets.all(20.0),
child: ButtonTheme(
minWidth: double.infinity,
height: 50,
child: OutlineButton(
child: Text("Continue",
style:
TextStyle(color: Colors.amber, fontSize: 16)),
borderSide: BorderSide(
color: Colors.amber,
),
highlightElevation: 10.0,
onPressed: () {},
),
),
),
],
),
),
),
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
ElevatedButton(
onPressed: () {
// json loaded on initState
print(jsonResult.length);
_showModalPhoneWidget();
},
child: Text("s"),
)
],
),
);
}
}
Related
I have a profile page with some widgets which after saving and redrawing, they keep their new states, but my checkboxes do not, and I have not modified them at all. The new value is being saved on the database, but on the UI it's not preserved. If I turn the email checkbox to true, the 'true' boolean is saved, but it's not displayed on the frontend after pressing the submit button.
class _ProfilePageState extends State<ProfilePage> {
final _formKey = GlobalKey<FormState>();
bool? emailIsChecked = false;
bool? smsisChecked = false;
bool isTextFieldEnabled = false;
bool isIgnored = true;
bool isVisible = false;
bool editIsVisible = true;
bool emailIsEnabled = false;
bool smsIsEnabled = false;
bool nameEdit = false;
late TextEditingController countryController;
late TextEditingController languageController;
#override
void initState() {
super.initState();
countryController = TextEditingController(text: globals.signedInUser!.country);
languageController = TextEditingController(text: globals.signedInUser!.language);
selectedCountry = globals.signedInUser!.country;
selectedLanguage = globals.signedInUser!.language;
globals.signedInUser!.notifications.forEach(
(element) {
if ((element['type']) == 'Email') {
emailIsChecked = element['status'];
}
if ((element['type']) == 'SMS') {
smsisChecked = element['status'];
}
},
);
cleanInputStates();
}
#override
void dispose() {
countryController.dispose();
languageController.dispose();
super.dispose();
}
checkEditVisibility() {
if (editIsVisible == true) {
return true;
}
if (editIsVisible == false) {
return false;
}
}
checkEditAvailability() {
if (editIsVisible == false) {
return true;
}
if (editIsVisible == true) {
return false;
}
}
cleanInputStates() {
isTextFieldEnabled = false;
isIgnored = true;
editIsVisible = true;
isVisible = false;
smsIsEnabled = false;
emailIsEnabled = false;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Form(
key: _formKey,
child: Row(
children: [
Flexible(
flex: 5,
child: Padding(
padding: const EdgeInsets.only(top: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 30,
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Visibility(
visible: editIsVisible,
maintainSize: true,
maintainAnimation: true,
maintainState: true,
child: ElevatedButton.icon(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.green)),
icon: const Icon(Icons.edit),
label: Text('Edit'),
onPressed: () {
setState(() {
isTextFieldEnabled = true;
isIgnored = false;
isVisible = true;
editIsVisible = false;
smsIsEnabled = true;
emailIsEnabled = true;
});
}),
),
SizedBox(
width: 250,
)
],
),
SizedBox(
height: 30,
),
Flexible(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 20,
),
... // TextFieldInputs
Row(
children: [
Container(
child: Text(
"Country: ",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 22,
color: Colors.black.withOpacity(0.3),
),
),
),
SizedBox(
width: 100,
),
Container(
width: 300,
child: IgnorePointer(
ignoring: isIgnored,
child: DropdownButtonFormField2(
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.zero,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
),
),
isExpanded: true,
hint: const Text(
'Select Your Country',
style: TextStyle(fontSize: 14),
),
icon: const Icon(
Icons.arrow_drop_down,
color: Colors.black45,
),
iconSize: 30,
buttonHeight: 60,
buttonPadding: const EdgeInsets.only(left: 20, right: 10),
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
),
items: countryItems
.map((item) => DropdownMenuItem<String>(
value: item,
child: Text(
item,
style: const TextStyle(
fontSize: 14,
),
),
))
.toList(),
validator: (valueCountry) {
if (valueCountry == null) {
return 'Please select country.';
}
return null;
},
value: selectedCountry,
onChanged: (String? valueCountry) {
selectedCountry = valueCountry;
setState(() {
valueCountry;
});
},
),
),
),
// ),
],
),
SizedBox(
height: 20,
),
Row(
children: [
Container(
child: Text(
"Language: ",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 22,
color: Colors.black.withOpacity(0.3),
),
),
),
SizedBox(
width: 80,
),
Container(
width: 300,
child: IgnorePointer(
ignoring: isIgnored,
child: DropdownButtonFormField2(
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.zero,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
),
),
isExpanded: true,
hint: const Text(
'Select Your Language',
style: TextStyle(fontSize: 14),
),
icon: const Icon(
Icons.arrow_drop_down,
color: Colors.black45,
),
iconSize: 30,
buttonHeight: 60,
buttonPadding: const EdgeInsets.only(left: 20, right: 10),
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
),
items: languageItems
.map((item) => DropdownMenuItem<String>(
value: item,
child: Text(
item,
style: const TextStyle(
fontSize: 14,
),
),
))
.toList(),
value: selectedLanguage,
validator: (valueLanguage) {
if (valueLanguage == null) {
return 'Please select language.';
}
return null;
},
onChanged: (String? valueLanguage) {
selectedLanguage = valueLanguage;
setState(() {
valueLanguage;
});
},
),
),
),
// ),
],
),
Row()
],
),
SizedBox(
width: 120,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
child: Row(
children: [
Text(
"Receive notifications by: ",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 22,
color: Colors.black.withOpacity(0.3),
),
),
],
),
),
],
),
SizedBox(
height: 10,
),
Row(
children: [
Container(
width: 300,
child: CheckboxListTile(
enabled: emailIsEnabled,
title: Text("E-mail"),
value: emailIsChecked,
onChanged: (bool? newEmailValue) {
setState(() {
emailIsChecked = newEmailValue;
});
},
activeColor: Colors.green,
),
),
],
),
Row(
children: [
Container(
width: 300,
child: CheckboxListTile(
enabled: smsIsEnabled,
title: Text("SMS"),
value: smsisChecked,
onChanged: (bool? newSmsValue) {
setState(() {
smsisChecked = newSmsValue;
});
},
activeColor: Colors.green,
),
),
],
),
SizedBox(
height: 100,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Visibility(
visible: isVisible,
child: Row(
children: <Widget>[
ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.red)),
onPressed: () {
setState(() {
cleanInputStates();
_formKey.currentState!.reset();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProfilePage()));
});
print("Cleaning states");
},
child: Text("Dismiss"),
),
SizedBox(
width: 100,
),
ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.green)),
onPressed: () {
if (_formKey.currentState!.validate()) {
final userInfo = {
"_id": globals.signedInUser!.userId,
"firstName": firstnameTextController.text,
"lastName": lastnameTextController.text,
"email": emailTextController.text,
"phoneNumber": phoneNumberTextController.text,
"country": selectedCountry.toString(),
"language": selectedLanguage.toString(),
"notifications": [
{"type": "Email", "status": emailIsChecked},
{"type": "SMS", "status": smsisChecked}
]
};
globals.socketController.updateUser(userInfo);
Fluttertoast.showToast(
msg: "Applying changes.", // message
toastLength: Toast.LENGTH_LONG, // length
gravity: ToastGravity.BOTTOM_RIGHT, // location
timeInSecForIosWeb: 2,
webBgColor: "#4caf50",
);
}
print("DATA IS BEING SAVED");
setState(() {
if (_formKey.currentState!.validate()) {
globals.signedInUser!.email =
emailTextController.text;
globals.signedInUser!.phoneNumber =
phoneNumberTextController.text;
globals.signedInUser!.firstName =
firstnameTextController.text;
globals.signedInUser!.lastName =
lastnameTextController.text;
globals.signedInUser!.country =
selectedCountry as String;
globals.signedInUser!.language =
selectedLanguage as String;
cleanInputStates();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProfilePage()));
} else {
print("ingresando else");
}
});
},
child: Text("Save"),
),
],
),
)
],
)
],
),
],
),
),
),
],
), //Column ends here
),
),
],
),
),
);
}
}
Update: After some testings and workarounds, I found that the second issue was due to not assigning a new value prior to returning to the initState. To do that, I added the following code segment into the setState() of the submit button, which is the fetch of the notification parameters within the initState() but assigning the new checkbox values into the array. Additionally, I removed the cleanInputStates(); on the initState as #Paulo mentioned and everything else kept the same.
globals.signedInUser!.notifications.forEach(
(element) {
if ((element['type']) == 'Email') {
element['status'] = emailIsChecked;
}
if ((element['type']) == 'SMS') {
element['status'] = smsisChecked;
}
},
);
I have trouble displaying data, all data is received correctly from Get method, but I can not handle it to show values.
in the getDataLadder successfully received data in response.body and i can see result with print('Response Body : ${response.body}');
with this section i store data in stringResponse value , but i can't show json data in this section:
Widget getBody() {
var size = MediaQuery.of(context).size;
return Container(
width: size.width,
height: size.height,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10)),
color: Colors.white),
child: SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Container(
height: 1,
decoration:
BoxDecoration(color: Colors.grey.withOpacity(0.2)),
),
),
SizedBox(
width: 10,
),
Text(
stringResponse.toString(),
style: TextStyle(color: Colors.black54),
),
SizedBox(
width: 10,
),
Flexible(
child: Container(
height: 1,
decoration:
BoxDecoration(color: Colors.grey.withOpacity(0.2)),
),
),
],
),
SizedBox(
height: 15,
),
Column(
children: List.generate(nardeban_data.length, (index) {
return Column(
children: [
Padding(
padding: const EdgeInsets.only(right: 5, left: 5),
child: Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage("assets/images/bg.png"),
fit: BoxFit.fill,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: 90,
// width: (size.width - 20) * 0.68,
child: Row(
children: [
SizedBox(width: 20), // give it width
Container(
width: 40,
decoration: BoxDecoration(
color: Colors.blue,
border:
Border.all(color: Colors.blue),
borderRadius:
BorderRadius.circular(40.0)),
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text("14",
style: TextStyle(
fontSize: 13.0,
fontWeight: FontWeight.bold,
color: Colors.white)))),
SizedBox(
width: 10,
),
Container(
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
nardeban_data[index]['name'],
style: TextStyle(
fontSize: 14,
color: Colors.black54,
fontWeight: FontWeight.w400),
overflow: TextOverflow.ellipsis,
),
],
),
)
],
),
),
Container(
width: (size.width - 120) * 0.32,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.blue)),
child: Padding(
padding: const EdgeInsets.only(
right: 10,
bottom: 4,
left: 10,
top: 4),
child: Row(
children: [
SizedBox(
width: 25,
height: 25,
child: TextField(
textAlign: TextAlign.center,
keyboardType:
TextInputType.number,
decoration: InputDecoration(
hintText: '4%',
border: InputBorder.none,
contentPadding: EdgeInsets.only(
bottom: 8,
top: 3,
),
),
),
)
],
),
),
),
// Icon(
// Icons.notifications,
// size: 22,
// color: Colors.blue.withOpacity(0.7),
// )
],
),
)
],
),
)),
],
);
})),
],
),
),
);
}
this is my json style when i get from api:
{
"pellekan": [
{
"name": "1",
"form": null,
"to": "1000000",
"percent": 1
},
{
"name": "2",
"form": "1000000",
"to": 1100000,
"percent": 2.89
},
{
"name": "3",
"form": "1000000",
"to": 1200000,
"percent": 4.79
},
]
}
also this is my class and i difine stringResponse value out of that
var stringResponse = [];
class ResultLadder extends StatefulWidget implements PreferredSizeWidget {
#override
Size get preferredSize => const Size.fromHeight(100);
const ResultLadder({Key? key}) : super(key: key);
#override
_ResultLadderState createState() => _ResultLadderState();
}
Future<String> getToken() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getString('login')!;
}
class _ResultLadderState extends State<ResultLadder> {
String token = "";
#override
void initState() {
// getInfo();
getDataLadder();
super.initState();
}
generally, for example how i can show name in json data instead of "14" , in this below:code:
child: Text("14",
style: TextStyle(
fontSize: 13.0,
fontWeight: FontWeight.bold,
color: Colors.white))
this is getDataLadder Code :
Future getDataLadder() async {
print('bye');
String token = await getToken();
var response = await http.get(
Uri.parse('https://mylocalapiurl.com/backend/api/v1/pellekan/main/active'),
headers: {
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token',
});
print('Token : ${token}');
print('Response Body : ${response.body}');
if (response.statusCode == 200) {
setState(() {
stringResponse = json.decode(response.body);
});
}
}
nardeban ladder is one file in data folder and i add this values for show data demo (this is working):
const List nardeban_data = [
{
"img":
"https://images.unsplash.com/image.jpg",
"name": "mark wiliams",
"takhfif": "description item"
},
{
"img":
"https://images.unsplash.com/photo-1610859923380-c8e5a13165d1?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1000&q=80",
"name": "joe mark",
"takhfif": "description item"
},
];```
So now use your stringResponse since it has already been decoded into JSON, I'd create a small PODO (Plain Ol' Dart Object) to map my JSON to the data you're receiving, as in:
class NardebanData {
String? name;
String? form;
String? to;
double? percent;
NardebanData({ this.name, this.form, this.to, this.percent });
factory NardebanData.fromJson(Map<String, dynamic> json) {
return NardebanData(
name: json['name'],
form: json['form'],
to: json['to'],
percent: json['percent']
);
}
}
Inside your setState() call, then map it as such:
setState(() {
stringResponse = json.decode(response.body);
nardeban_data = (stringResponse['pellekan'] as List<dynamic>).map((d) => NardebanData.fromJson(d)).toList();
});
So make your nardeban_data not a const anymore, but a List of NardebanData objects:
List<NardebanData> narbeban_data = [];
And when you consume it (inside of your List.generate) you could fetch the current object in the iteration, as in:
children: List.generate(nardeban_data.length, (index) {
// fetch the item in the collection by the index provided
NardebanData dataItem = nardeban_data[index];
// ALL YOUR WIDGET STRUCTURE HERE
// LIKE YOUR TEXT WIDGETS AS IN:
Text(
dataItem.name!, // pull the data out of the dataItem using the provided properties
style: TextStyle(
fontSize: 14,
color: Colors.black54,
fontWeight: FontWeight.w400),
overflow: TextOverflow.ellipsis,
),
}
Also make sure your JSON data coming from your API is consistent as far as the type of data in each field, otherwise the decoding will fail (i.e. make sure that name, form, to are Strings, and percent is a double).
See if that works for you.
I am currently working on a tasks app. Whenever I select the priority from the drop down or the date the values in the text fields above get resets to null, and also the selected date and priority are set back to default.
Would really like some help on the same.
Code snippet is below -
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:ssms_new/Models/ToDoModel.dart';
import 'package:http/http.dart' as http;
import 'package:date_time_picker/date_time_picker.dart';
import 'package:ssms_new/Tasks/AllTasksTabsView.dart';
import '../Configurations/configurations.dart';
class AddTaskModalSheet extends StatefulWidget {
const AddTaskModalSheet({Key? key}) : super(key: key);
#override
_AddTaskModalSheetState createState() => _AddTaskModalSheetState();
}
class _AddTaskModalSheetState extends State<AddTaskModalSheet> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
var screenHeight = MediaQuery.of(context).size.height;
var screenWidth = MediaQuery.of(context).size.width;
final TextEditingController taskTitle = TextEditingController();
final TextEditingController taskNotes = TextEditingController();
String selectedPriority = "Normal";
String _dueDate = "${DateTime.now().toString()}";
Future<ToDoModel?> postNewTask() async {
var response;
String encodedPath = "task/new/$savedUserID";
if (devMode == "development") {
response = await http.post(Uri.parse('$devUrl$encodedPath'), body: {
"name": taskTitle.text,
"note": taskNotes.text,
"title": taskTitle.text,
"done": "0",
"priority": "$selectedPriority",
"due_date": "$_dueDate",
"TaskOwner": "$savedUserID",
"img": "NA",
"studentId": "$savedUserID",
"assignerId": "0",
"closeTaskNotes": "NA",
});
} else {
print(selectedPriority);
response = await http.post(Uri.parse('$prodUrl$encodedPath'), body: {
"name": taskTitle.text,
"note": taskNotes.text,
"title": taskTitle.text,
"done": "0",
"priority": "$selectedPriority",
"due_date": "$_dueDate",
"TaskOwner": "$savedUserID",
"img": "NA",
"studentId": "$savedUserID",
"assignerId": "0",
"closeTaskNotes": "NA",
});
}
print(response.statusCode);
String responseString = response.body;
toDoFromJson(responseString);
print(response.body);
return null;
}
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
child: Form(
key: _formKey,
child: Container(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
color: Color(0xff737373),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
),
child: Column(children: [
SizedBox(height: 20),
Text(
"Add New Task",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
SizedBox(height: 20),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
TextField(
controller: taskTitle,
decoration: InputDecoration(
labelText: "Task Title",
border: OutlineInputBorder(),
),
),
SizedBox(height: 10),
TextField(
controller: taskNotes,
maxLines: 3,
decoration: InputDecoration(
labelText: "Task Notes",
border: OutlineInputBorder(),
),
),
],
),
),
SizedBox(height: 2),
Container(
padding: EdgeInsets.only(left: 4, right: 3),
width: screenWidth / 1.05,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 2),
borderRadius: BorderRadius.circular(5)),
child: DropdownButtonFormField(
items: priorityList.map((String category) {
return DropdownMenuItem(
value: category,
child: Row(
children: <Widget>[
Text(category),
],
));
}).toList(),
onTap: () =>
FocusManager.instance.primaryFocus!.unfocus(),
onChanged: (newValue) {
// do other stuff with _category
selectedPriority = newValue.toString();
},
value: selectedPriority,
),
),
DateTimePicker(
type: DateTimePickerType.date,
dateMask: 'd MMM, yyyy',
initialValue: DateTime.now().toString(),
firstDate: DateTime.now(),
lastDate: DateTime(2100),
icon: Icon(Icons.event),
dateLabelText: 'Date',
onChanged: (val) {
_dueDate = val;
},
onSaved: (val) {
_dueDate = val!;
},
), //Select Work Date
SizedBox(height: 10),
ElevatedButton(
style:
ElevatedButton.styleFrom(primary: Color(0xffe9c46a)),
onPressed: () {
postNewTask();
Navigator.pushAndRemoveUntil(context,
MaterialPageRoute(builder: (context) {
return AllTasksTabView(id: savedUserID);
}), (route) => true);
}, //TODO: add task here
child: Text("Add Task",
style: TextStyle(color: Colors.black))),
SizedBox(height: 30),
]),
),
),
),
),
),
);
}
}
You are storing all your state inside the build method, so whenever the widget is rebuilt, all the state is overwritten.
Please take a look at this tutorial to understand the difference between StatefulWidget and StatelessWidget and how to add interactivity/
I'm trying to do an HTTP post request to the postman URL. In code, I can't find any error but it doesn't work in the flutter app.
though the data is entered in the text box, the response is not showing in a flutter. i have attached the image
enter image description here
Request body in postman code attached.
This is the response body in postman:
{enter image description here
"processingTime": 1,
"result": {
"id": "fa6a14d5-2888-4634-8158-efcaa0690211",
"noteType": "PRIVATE_NOTE",
"privacy": "PRIVATE",
"reaction": "NEUTRAL",
"description": "KUSHAN 1",
"status": "ACTIVE",
"author": "Test User",
"authorId": "00000000-0000-0000-0000-000000000000",
"modified": "2021-09-07T13:59:33.9926797Z",
"flagged": false
}
}
This is my code:
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
postData() async {
try {
var response = await http.post(
Uri.parse("https://zen-api-1010.azure-api.net/notes/v1/create"),
headers: {
"Ocp-Apim-Subscription-Key": "008c47b597e54aedadbd5e4d270b35ed",
"Ocp-Apim-Trace": "true"
},
body: {
"noteType": 0.toString(),
"description": "KUSHAN 1".toString(),
"authorReaction": 0.toString(),
"privacy": 0.toString(),
});
print(response.body);
} catch (e) {
print(e);
}
}
class NavPrivatePage extends StatefulWidget {
#override
_NavPrivatePageState createState() => _NavPrivatePageState();
}
class _NavPrivatePageState extends State<NavPrivatePage> {
TextEditingController noteTypeController = TextEditingController();
TextEditingController descriptionController = TextEditingController();
TextEditingController authorReactionController = TextEditingController();
TextEditingController privacyController = TextEditingController();
bool inVisible = true;
bool isNotVisible = false;
#override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: Text(
'Private Note Auto Expand',
style: TextStyle(
fontSize: 14,
),
),
centerTitle: true,
backgroundColor: const Color.fromRGBO(255, 191, 0, 1),
),
body: SingleChildScrollView(
child: Center(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Visibility(
visible: inVisible,
child: TextButton(
onPressed: () {
setState(() {
isNotVisible = !isNotVisible;
});
},
child: Text(
'Create Private Note',
style: TextStyle(
color: Colors.white,
),
),
style: TextButton.styleFrom(
backgroundColor: Colors.grey[900],
),
),
),
Visibility(
visible: isNotVisible,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
controller: descriptionController,
autofocus: false,
onChanged: (text) {
print("Text $text");
},
minLines: 2,
maxLines: 20,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
hintText: 'Enter your message here',
hintStyle: TextStyle(
color: Colors.grey[600],
fontSize: 12,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(5)),
),
),
),
),
),
Visibility(
visible: isNotVisible,
child: TextButton(
onPressed: () {
postData();
},
child: Text(
'Submit',
style: TextStyle(
color: Colors.white,
),
),
style: TextButton.styleFrom(
backgroundColor: Colors.grey[600],
),
),
),
Visibility(
visible: isNotVisible,
child: Center(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
color: Colors.grey[300],
child: Container(
padding: EdgeInsets.all(10),
height: 130,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
trailing: Icon(Icons.more_horiz),
leading: CircleAvatar(
backgroundImage: NetworkImage(
'https://images.pexels.com/photos/220453/pexels-photo-220453.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500'),
),
subtitle: Text(
'2 days ago',
style: TextStyle(
color: Colors.grey[800],
),
),
),
Text(
'This is a private note that auto expands based on the text entered. The background will determine the privacy level of the post',
style: TextStyle(
fontSize: 10,
color: Colors.black87,
),
textAlign: TextAlign.justify),
],
),
),
),
),
),
],
),
),
),
),
);
}
Change your postData() with
postData() async {
try {
var response = await http.post(
Uri.parse("https://zen-api-1010.azure-api.net/notes/v1/create"),
headers: {
"Content-type": "application/json",
"Accept": "application/json",
"Ocp-Apim-Subscription-Key": "008c47b597e54aedadbd5e4d270b35ed",
"Ocp-Apim-Trace": "true"
},
body: jsonEncode({
"noteType": 0.toString(),
"description": "KUSHAN 1".toString(),
"authorReaction": 0.toString(),
"privacy": 0.toString(),
}));
print(response.statusCode);
} catch (e) {
print(e);
}
}
The problem is the api accept the json data but you are sending the map which needs to be encoded to json first and secondly the header has two missing parameters.
I would suggest making your TextButton's onPressed an async method and try await postData() inside it.
I have a Column with some widgets. Inside the Column are some TextFields. When the textfields receive and lose focus I want to hide a widget. I think when calling SetState it is not redrawing the conditional below.
AutoCompleteTextField:
child: AutoCompleteTextView(
suggestionsApiFetchDelay: 300,
focusGained: () {
_pauseStream(
stream: Streams.dropoff);
_startStream(
stream: Streams.pickup);
setState(() {
_showCurrentLocalTile = true;
});
},
focusLost: () {
setState(() {
_showCurrentLocalTile = false;
});
_pauseStream(
stream: Streams.dropoff);
}
)
void _showBottomSheet() {
setState(() {
_showPersBottomSheetCallBack = null;
});
// Be sure to set to get and set current physical address
LocationService().getAddressFromLatLng().then((value) {
if (value != null) {
_currentAddress = value;
}
});
_scaffoldKey.currentState
.showBottomSheet((context) {
return new Container(
height: 400.0,
color: Colors.white,
padding: const EdgeInsets.only(left: 2, right: 2),
child: new Center(
// child: new Text('Persistent Bottom Sheet'),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 125,
child: Row(
children: [
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
IconButton(
icon: Icon(Icons.arrow_back),
color: Colors.black,
onPressed: () {},
),
],
),
Expanded(
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Container(
alignment: Alignment.topCenter,
height: 35,
margin: const EdgeInsets.only(
top: 40, left: 0, right: 0),
child: AutoCompleteTextView(
suggestionsApiFetchDelay: 300,
focusGained: () {
_pauseStream(
stream: Streams.dropoff);
_startStream(
stream: Streams.pickup);
setState(() {
_showCurrentLocalTile = true;
});
},
onTapCallback: (_) async {
_startStream(
stream: Streams.dropoff);
// locationSavedStatus = LocationSaveStatus.inProgress;
// saveLocationValuesFromGeoCoding(bloc).then(
// (_) =>
// locationSavedStatus = LocationSaveStatus.saved,
// );
},
focusLost: () {
setState(() {
_showCurrentLocalTile = false;
});
_pauseStream(
stream: Streams.dropoff);
// locationSavedStatus = LocationSaveStatus.saved;
// if (startEditingController.text.isEmpty) {
// city = '';
// state = '';
// country = '';
// startEditingController.text = '';
// } else {
// startEditingController.text = getLocationString(
// country: country, state: state, city: city);
// }
},
onValueChanged: (String text) {
// locationSavedStatus = text.isNotEmpty
// ? (getLocationString(
// city: '', state: '', country: '')
// .trim() ==
// text.trim())
// ? LocationSaveStatus.saved
// : LocationSaveStatus.notSaved
// : LocationSaveStatus.saved;
},
controller: startEditingController,
suggestionStyle: Theme.of(context)
.textTheme
.bodyText2,
getSuggestionsMethod:
getLocationSuggestionsList,
tfTextAlign: TextAlign.left,
tfCursorColor: Colors.black,
tfStyle: TextStyle(
fontSize: 16,
color: Theme.of(context)
.textTheme
.bodyText2
.color,
),
tfTextDecoration: InputDecoration(
contentPadding: EdgeInsets.only(
top: 0, left: 8.0),
filled: true,
fillColor: Colors.grey[200],
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
width: 1.0),
borderRadius: BorderRadius.zero,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
width: 1.0),
borderRadius: BorderRadius.zero,
),
hintText: "",
labelText: 'Start',
labelStyle:
kPurpleLabelStyle,
),
),
),
Container(
height: 35,
margin: const EdgeInsets.only(
top: 5,
left: 0,
right: 0,
bottom: 5),
child: AutoCompleteTextView(
suggestionsApiFetchDelay: 300,
focusGained: () {
setState(() {
_showCurrentLocalTile = true;
});
_pauseStream(
stream: Streams.pickup);
_startStream(
stream: Streams.dropoff);
},
onTapCallback: (_) async {
_startStream(
stream: Streams.pickup);
// locationSavedStatus = LocationSaveStatus.inProgress;
// saveLocationValuesFromGeoCoding(bloc).then(
// (_) =>
// locationSavedStatus = LocationSaveStatus.saved,
// );
},
focusLost: () {
setState(() {
_showCurrentLocalTile = false;
});
_pauseStream(
stream: Streams.pickup);
// locationSavedStatus = LocationSaveStatus.saved;
// if (startEditingController.text.isEmpty) {
// city = '';
// state = '';
// country = '';
// startEditingController.text = '';
// } else {
// startEditingController.text = getLocationString(
// country: country, state: state, city: city);
// }
},
onValueChanged: (String text) {
// locationSavedStatus = text.isNotEmpty
// ? (getLocationString(
// city: '', state: '', country: '')
// .trim() ==
// text.trim())
// ? LocationSaveStatus.saved
// : LocationSaveStatus.notSaved
// : LocationSaveStatus.saved;
},
controller:
destinationEditingController,
suggestionStyle: Theme.of(context)
.textTheme
.bodyText2,
getSuggestionsMethod:
getLocationSuggestionsList,
tfTextAlign: TextAlign.left,
tfCursorColor: Colors.black,
tfStyle: TextStyle(
fontSize: 16,
color: Theme.of(context)
.textTheme
.bodyText2
.color,
),
tfTextDecoration: InputDecoration(
contentPadding: EdgeInsets.only(
top: 0, left: 8.0),
filled: true,
fillColor: Colors.grey[300],
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
width: 1.0),
borderRadius: BorderRadius.zero,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
width: 1.0),
borderRadius: BorderRadius.zero,
),
hintText: "",
labelText: 'Destination',
labelStyle:
kPurpleLabelStyle,
),
),
)
]),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Stack(
alignment: Alignment.bottomLeft,
children: [
ButtonTheme(
padding: EdgeInsets.symmetric(
vertical: 4.0,
horizontal:
8.0), //adds padding inside the button
materialTapTargetSize:
MaterialTapTargetSize
.shrinkWrap, //limits the touch area to the button area
minWidth: 45, //wraps child's width
height: 45, //wraps child's height
child: FlatButton(
color: Colors.white,
textColor: Colors.black,
disabledColor: Colors.grey[100],
disabledTextColor: Colors.white,
padding: EdgeInsets.only(
top: 10,
left: 8,
bottom: 8,
right: 12),
splashColor: Colors.grey[100],
onPressed: () {
/*...*/
},
child: Text(
"Done",
style:
TextStyle(fontSize: 14.0),
),
),
),
// IconButton(
// icon: Icon(Icons.add),
// color: Colors.black,
// onPressed: () {},
// ),
]),
],
),
]),
),
],
),
),
SizedBox(
height: 15.0,
),
_showCurrentLocalTile
? GestureDetector(
onTap: () {
_setPickupAddressToAutoComplete(_currentAddress);
print(_currentAddress);
},
child: Container(
height: 48,
child: Padding(
padding: const EdgeInsets.fromLTRB(
16.0, 8.0, 16.0, 0.0),
child: Row(
children: <Widget>[
Icon(Icons.my_location),
Padding(
padding: EdgeInsets.only(
left: 8.0, top: 0.0, bottom: 0.0),
child: Text("Current Location"),
)
],
),
),
),
)
: SizedBox(
height: 15.0,
),
Container(
height: 200,
child: Padding(
padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0),
child: StreamBuilder<List<GoogleAddress>>(
stream: pickupStreamController.stream,
builder: (context, snapshot) => snapshot.data != null
? ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
print('Render $index');
if (snapshot.data != null) {
print("${snapshot.data}");
return _createListItem(
icon: Icons.location_on,
googleplace: snapshot.data[index],
onTap: () {
_setPickupAddressToAutoComplete(
snapshot.data[index].address);
print("${snapshot.data[index]}");
});
} else {}
},
)
: SizedBox(height: 15.0),
),
),
),
],
),
),
);
})
.closed
.whenComplete(() {
if (mounted) {
setState(() {
_showPersBottomSheetCallBack = _showBottomSheet;
});
}
});
}