How to get parameters from URL in with Flutter - flutter

I want to show a list from LoanSimulation pages based on periodtime, interestpermonth and loanamountrequest
This is my Simulators function
static Future<LoanModel> simulators({String periodtime, String interestpermonth, String loanamountrequest, String idUser, String url}) async {
var uri = Uri(
scheme: 'http',
host: '192.168.0.23',
path: 'edufund-api/Api/loansimulation.php',
queryParameters: {
'periodtime': [periodtime], //from here get value
'interestpermonth' : [interestpermonth],
'loanamountrequest' : [loanamountrequest]
},
);
print(uri);
final response = await http.get(uri,headers:{"Content-Type":
"application/json"},
);
var res = LoanModel.fromJson(jsonDecode(response.body)[0]);
print(response.body);
return res;
}
This is my fetchdata from Simulator.dart
Future<LoanModel> _fetchData() async {
setState(() {
loading = true;
});
var uri = Uri(
scheme: 'http',
host: '192.168.0.23',
path: 'edufund-api/Api/loansimulation.php',
queryParameters: {
'periodtime': ["48"], //this is hard code i want to change the value same as simulators but it make error
'interestpermonth' : ["1"],
'loanamountrequest' : ["120000000"]
},
);
print(uri);
final response = await http.get(uri,headers:{"Content-Type":
"application/json"});
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
setState(() {
for (Map i in data) {
_loanmodel.add(LoanModel.fromJson(i));
}
loading = false;
});
}
}
So here is the result with hard code
And this is my Loan Model
LoanModel(
{this.no,
this.interest,
this.balance,
this.principal,
this.installment,
this.status,
this.message});
LoanModel.fromJson(Map<String, dynamic> json) {
interest = json['interest'];
balance = json['balance'];
principal = json['principal'];
installment = json['Installment'];
status = json['Status'];
message = json['message'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['No'] = this.no;
data['interest'] = this.interest;
data['balance'] = this.balance;
data['principal'] = this.principal;
data['Installment'] = this.installment;
data['Status'] = this.status;
data['message'] = this.message;
return data;
}
How to get the value from simulators and showing list view in fetch data? So on another pages just showing in list based on picture 2.
This is my widget build
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: kYellow,
key: _scaffoldKey,
body: Form(
key: _key,
child: Padding(
padding: EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
margin: EdgeInsets.all(20.0),
height: 150.0,
width: 150.0,
child: Image.asset('assets/img/lemonlime.png'),
),
TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Period time cannot be Empty';
}
return null;
},
onSaved: (value) => periodtime = value,
decoration: kTextFieldDecoration.copyWith(hintText: 'Period time'),
),
SizedBox(
height: 20.0,
),
TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Interest per month cannot be Empty';
}
return null;
},
onSaved: (value) => interestpermonth = value,
decoration: kTextFieldDecoration.copyWith(hintText: 'Interest Per Month'),
),
SizedBox(
height: 20.0,
),
SizedBox(
height: 20.0,
),
TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Loan Amount Request cannot be Empty';
}
return null;
},
onSaved: (value) => loanamountrequest = value,
decoration: kTextFieldDecoration.copyWith(hintText: 'Loan Amount Request'),
),
SizedBox(
height: 20.0,
),
FullWidthRoundButton(
textButton: 'Loan Simulation',
getPressed: () {
check();
},
),
],
),
),
),
);
}
And then here is my widget build on simulator.dart
#override
Widget build(BuildContext context) {
timeDilation = 2.0;
return WillPopScope(
onWillPop: () async => false,
child: Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: kYellow,
appBar: AppBar(
leading: Hero(
tag: 'animasilogo',
child: Container(
margin: EdgeInsets.all(5.0),
child: Image.asset('assets/img/lemonlime.png'),
),
),
title: Text('Simulator'),
actions: [
IconButton(
icon: const Icon(Icons.exit_to_app),
onPressed: () {
SharedPref.signOut();
Navigator.pushNamed(context, LoginScreen.id);
},
)
],
),
body: RefreshIndicator(
onRefresh: () => _fetchData(),
child: loading
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: _loanmodel.length,
itemBuilder: (context, index) {
return Container(
alignment: Alignment.topLeft,
margin: const EdgeInsets.only(top: 15.0),
padding: EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Interest : " + _loanmodel[index].interest , style: DefaultTextStyle.of(context).style.apply(fontSizeFactor: 1.5), textAlign: TextAlign.justify),
Text("Balance : " + _loanmodel[index].balance, style: DefaultTextStyle.of(context).style.apply(fontSizeFactor: 1.5),textAlign: TextAlign.justify),
Text("Principal : " + _loanmodel[index].principal, style: DefaultTextStyle.of(context).style.apply(fontSizeFactor: 1.5),textAlign: TextAlign.justify),
Text("Installment :" + _loanmodel[index].installment, style: DefaultTextStyle.of(context).style.apply(fontSizeFactor: 1.5),textAlign: TextAlign.justify),
Divider(
color: Colors.black,
),
],
),
);
},
),
),
),
);
}

Related

Error : Failed to detect image file format using the file header. File header was [0x3c 0x68 0x74 0x6d 0x6c 0x3e 0x0a 0x20 0x20 0x20]

I'm trying to display an image from Firestore in to my UI. But it returns the error above, and the file format also changes when I run it on Edge (not on physical device or Emulator). I can't figure out how. Here's my code.
class ViewPola extends StatefulWidget {
const ViewPola({Key? key}) : super(key: key);
static String id = 'view_pola';
#override
State<ViewPola> createState() => _ViewPolaState();
}
class _ViewPolaState extends State<ViewPola> {
Function getSnaps = () async {
final polaMap = {
'Kode Pola': '',
'Bagian Pola': '',
'image_url': '',
};
FirebaseFirestore.instance
.collection('PolaWillyJKT')
.limit(1)
.get()
.then((snapshot) {
if (snapshot.size == 0) {
FirebaseFirestore.instance.collection('PolaWillyJKT').add(polaMap);
FirebaseFirestore.instance.collection('PolaWillyJKT');
print('add');
} else {
print('disini nge get');
var a = FirebaseFirestore.instance.collection('PolaWillyJKT').get();
Map<String, dynamic> data = a as Map<String, dynamic>;
print(data);
}
});
};
var _selectedItem;
var _showList = false;
#override
void initState() {
getSnaps();
super.initState();
}
final Stream<QuerySnapshot> _polaWilly =
FirebaseFirestore.instance.collection('PolaWillyJKT').snapshots();
#override
Widget build(BuildContext context) {
final screenHeight = ScreenInfo.screenHeight(context);
final screenWidth = ScreenInfo.screenWidth(context);
return StreamBuilder<QuerySnapshot>(
stream: _polaWilly,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return SafeArea(
child: Scaffold(
body: Padding(
padding: EdgeInsets.all(25),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Text(
'Pilih Bagian Pola',
style: TextStyle(fontSize: 25),
),
const SizedBox(
height: 20,
),
DropdownButton(
isExpanded: true,
value: _selectedItem,
items: snapshot.data?.docs
.map(
(value) => DropdownMenuItem(
value: value.get("Bagian Pola"),
child: Text('${value.get("Bagian Pola")}'),
),
)
.toList(),
onChanged: (newValue) {
setState(() {
_selectedItem = newValue.toString();
_showList = true;
});
}),
Padding(
padding: const EdgeInsets.all(25),
child: Visibility(
visible: _showList,
child: Container(
height: screenHeight * 0.4,
child: ListView(
children: snapshot.data!.docs
.where(
(e) => e.get("Bagian Pola") == _selectedItem)
.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return Center(
child: Column(
children: [
Text(
'Bagian Pola: ${data["Bagian Pola"]}',
style: TextStyle(fontSize: 15),
),
const SizedBox(
height: 15,
),
Text(
'Kode Pola : ${data["Kode Pola"]}',
style: TextStyle(fontSize: 15),
),
const SizedBox(
height: 15,
),
Image(
image:
NetworkImage(document.get("Foto Pola")),
height: 200,
width: 200,
), // this is the Image widget where I tried to put the image from firestore
Text(document.get('Foto Pola').toString()),
],
),
);
}).toList(),
),
),
),
),
],
),
),
),
);
},
);
}
}
and here's the class that uploads the image to Firestore
class Input_Pola extends StatefulWidget {
const Input_Pola({Key? key}) : super(key: key);
static String id = 'input_pola';
#override
State<Input_Pola> createState() => _Input_PolaState();
}
class _Input_PolaState extends State<Input_Pola> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
void _checkDuplicate() {
if (options.contains(_textfieldValue.text)) {
// Display bottom sheet that says item already exists
_scaffoldKey.currentState?.showBottomSheet((context) => Container(
height: 300,
child: Column(
children: [
const Text('Item already exists'),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Dismiss'))
],
),
));
} else {
// Add item to options list
setState(() {
options.add(_textfieldValue.text);
});
}
}
XFile? image;
final ImagePicker picker = ImagePicker();
String _image_url = '';
void _addToFirebase(String dropdownValue, String _kodePolaController) {
var imageFile = File(image!.path);
String fileName = pth.basename(imageFile.path);
FirebaseStorage storage = FirebaseStorage.instance;
Reference ref = storage.ref().child("WillyJKT/polaWillyJKT");
UploadTask uploadTask = ref.putFile(imageFile);
uploadTask.whenComplete(() async {
var url = await ref.getDownloadURL();
_image_url = url.toString();
});
FirebaseFirestore.instance
.collection('PolaWillyJKT')
.doc(_selectedOption)
.set({
'Bagian Pola': _selectedOption,
'Kode Pola': _kodePolaController,
'Foto Pola': _image_url
});
}
String _dropdownValue = 'kg';
String _property1 = '';
String _property2 = '';
String _property3 = '';
bool _isOptionSelected = false;
final TextEditingController _kodePolaController = TextEditingController();
var _selectedOption;
final TextEditingController _textfieldValue = TextEditingController();
final List<String> options = [];
#override
void initState() {
super.initState();
_selectedOption = options.isNotEmpty ? options[0] : null;
}
//we can upload image from camera or from gallery based on parameter
Future getImage(ImageSource media) async {
var img = await picker.pickImage(source: media);
setState(() {
image = img;
});
}
void myAlert() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
title: Text('Please choose media to select'),
content: Container(
height: MediaQuery.of(context).size.height / 6,
child: Column(
children: [
ElevatedButton(
//if user click this button, user can upload image from gallery
onPressed: () {
Navigator.pop(context);
getImage(ImageSource.gallery);
},
child: Row(
children: [
Icon(Icons.image),
Text('From Gallery'),
],
),
),
ElevatedButton(
//if user click this button. user can upload image from camera
onPressed: () {
Navigator.pop(context);
getImage(ImageSource.camera);
},
child: Row(
children: [
Icon(Icons.camera),
Text('From Camera'),
],
),
),
],
),
),
);
});
}
#override
Widget build(BuildContext context) {
final screenHeight = ScreenInfo.screenHeight(context);
final screenWidth = ScreenInfo.screenWidth(context);
return SafeArea(
child: Scaffold(
key: _scaffoldKey,
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
_addToFirebase(_dropdownValue, _kodePolaController.text);
},
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(25),
child: Container(
height: screenHeight,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextFormField(
decoration: const InputDecoration(
hintText: 'Input Pola',
border: UnderlineInputBorder(),
),
onChanged: (value) {
setState(() {
_textfieldValue.text = value;
});
},
),
DropdownButton<String>(
value: _selectedOption,
onChanged: (value) {
setState(() {
_selectedOption = value!;
_isOptionSelected = true;
_kodePolaController.clear();
});
},
hint: const Text('Input from Text Field Above'),
items: options.map((option) {
return DropdownMenuItem<String>(
value: option,
child: Text(option),
);
}).toList(),
),
TextButton(
onPressed: _checkDuplicate,
child: const Text("Add Option"),
),
Visibility(
visible: _isOptionSelected,
child: Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
TextField(
controller: _kodePolaController,
decoration: const InputDecoration(
labelText: "Kode Pola"),
onChanged: (value) {
setState(() {
_property1 = value;
});
},
),
const SizedBox(height: 20,),
ElevatedButton(
onPressed: () {
myAlert();
},
child: Text('Upload Photo'),
),
SizedBox(
height: 10,
),
//if image not null show the image
//if image null show text
image != null
? Padding(
padding:
const EdgeInsets.symmetric(horizontal: 20),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.file(
//to show image, you type like this.
File(image!.path),
fit: BoxFit.cover,
width: MediaQuery.of(context).size.width,
height: 300,
),
),
)
: const Text(
"No Image",
style: TextStyle(fontSize: 20),
),
],
),
),
)
],
),
),
),
),
),
);
}
}
It also displays the error on Edge, but when I build the apk and run it on my physical device, it just shows nothing on the screen except for the data that's got above it. Any idea on how I can fix this?
var a = FirebaseFirestore.instance.collection('PolaWillyJKT').get();
This returns a promise but not the actual data. In fact it could still be fetching the data when you attempt to convert it to a map.
You can await
var a = await FirebaseFirestore.instance.collection('PolaWillyJKT').get();
myDoc = a.docs.first();
Or use a callback that will run once the collection fetch completes:
FirebaseFirestore.instance.collection('PolaWillyJKT').get().then((response) => {
print(response);
});

flutter firestore - How to retrieve the new document id after adding to firestore

I want to retrieve the new created document id and display the document data in a new page. How can i get the document id? When onPressed() the elevated button, I want to retrieve the document data based on its id.
How can I bring the document id from addDiagnose(_type, _symptomsResult) so that I can navigate it to another page.
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DiagnosisPage(documentId: documentId),
)
);
This is my current code.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:multiselect_formfield/multiselect_formfield.dart';
import 'package:petbuddies/user/diagnosis/diagnose_history.dart';
import 'package:petbuddies/user/diagnosis/diagnosis.dart';
class CheckerPage extends StatefulWidget {
const CheckerPage({Key? key}) : super(key: key);
#override
_CheckerPageState createState() => _CheckerPageState();
}
class _CheckerPageState extends State<CheckerPage> {
//retrieve options
final _formKey = GlobalKey<FormState>();
void _petTypeDropDownItemSelected(String newValueSelected) {
setState(() {
petType = newValueSelected;
});
}
clearText(){
_symptoms?.clear();
}
#override
void initState(){
super.initState();
_symptoms = [];
_symptomsResult = [];
}
List? _symptoms;
late List<dynamic> _symptomsResult;
var petType;
var _type;
final Stream<QuerySnapshot> petTypeStream = FirebaseFirestore.instance.collection('pet type').orderBy('name').snapshots();
final Stream<QuerySnapshot> symptomsStream = FirebaseFirestore.instance.collection('symptoms').orderBy('name').snapshots();
DocumentReference diagnosis = FirebaseFirestore.instance.collection('diagnosis').doc();
//store the diagnosis result
User? user = FirebaseAuth.instance.currentUser;
Future<void> addDiagnose(_type, _symptomsResult) async {
String petChosen = this._type;
List symptomsChosen = this._symptomsResult.toList();
QuerySnapshot<Map<String, dynamic>> snapshot =
await FirebaseFirestore.instance.collection("disease")
.where('petType',isEqualTo: petChosen)
.where('symptoms',arrayContainsAny: symptomsChosen)
.get();
List<String> diseaseRef = snapshot.docs.map((e) => e.id).toList();
String createdby = user!.uid;
Timestamp date = Timestamp.now();
List possibleDisease = diseaseRef.toList();
final data = {
'created by': createdby,
'date': date,
'pet chosen': petChosen,
'symptoms chosen': symptomsChosen,
'possible disease': possibleDisease,
};
//set document data
return diagnosis
.set(data)
.then((value) => print('Diagnose Report Added'))
.catchError((error)=>print("Failed to add: $error")
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue[900],
title: const Text("Pet Symptoms Checker",
style: TextStyle(color: Colors.white),
),
),
body: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 30),
child: ListView(
children: [
Align(
alignment: Alignment.bottomRight,
child: TextButton(
child: const Text(
'History',
style: TextStyle(fontSize: 18),
),
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => const DiagnoseHistoryPage(),));
},
),
),
Container(
padding: const EdgeInsets.all(12.0),
decoration: BoxDecoration(
border: Border.all(width: 3, color: Colors.indigo,),
borderRadius: const BorderRadius.all(Radius.circular(30)),
),
child: Column(
children: [
StreamBuilder<QuerySnapshot>(
stream: petTypeStream,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Container(
padding: const EdgeInsets.only(bottom: 16.0),
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
padding: const EdgeInsets.fromLTRB(12.0, 10.0, 10.0, 10.0),
child: const Text(
"Pet Type",
style: TextStyle(fontSize: 20),
),
),
),
Expanded(
flex: 3,
child: Row(
children: [
const SizedBox(width: 30,),
DropdownButton(
value: petType,
onChanged: (valueSelectedByUser) {
_petTypeDropDownItemSelected(valueSelectedByUser.toString());
},
hint: const Text('Choose Pet Type',),
underline: Container(),
items: snapshot.data!.docs.map((DocumentSnapshot document) {
return DropdownMenuItem<String>(
value: document.get('name'),
child: Text(document.get('name')),
);
}).toList(),
),
],
),
),
],
),
);
}),
StreamBuilder(
stream: symptomsStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if(snapshot.hasError){
print('Something went wrong');
}
if(snapshot.connectionState == ConnectionState.waiting){
return const Center(
child: CircularProgressIndicator(),
);
}
final List symptomsList = [];
snapshot.data!.docs.map((DocumentSnapshot document){
Map a = document.data() as Map<String, dynamic>;
symptomsList.add(a['name']);
a['id'] = document.id;
}).toList();
return MultiSelectFormField(
autovalidate: AutovalidateMode.disabled,
chipBackGroundColor: Colors.blue[900],
chipLabelStyle: const TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
dialogTextStyle: const TextStyle(fontWeight: FontWeight.bold),
checkBoxActiveColor: Colors.blue[900],
checkBoxCheckColor: Colors.white,
dialogShapeBorder: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0))),
title: const Text(
"Symptoms",
style: TextStyle(fontSize:20),
),
validator: (value) {
if (value == null || value.length == 0) {
return 'Please select one or more symptoms';
}
return null;
},
dataSource: [
for (String i in symptomsList) {'value' : i}
],
textField: 'value',
valueField: 'value',
okButtonLabel: 'OK',
cancelButtonLabel: 'CANCEL',
hintWidget: const Text('Please choose one or more symptoms'),
initialValue: _symptoms,
onSaved: (value) {
if (value == null) return;
setState(() {
_symptoms = value;
}
);
},
);
}
),
const SizedBox(height:50,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
onPressed: () async{
if(_formKey.currentState!.validate()){
setState(() {
_type = petType.toString();
_symptomsResult = _symptoms!.toList();
addDiagnose(_type,_symptomsResult);
final documentId = diagnosis.id;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DiagnosisPage(documentId: documentId),
)
);
clearText();
}
);
}
},
child: const Text(
'Diagnose',
style: TextStyle(fontSize: 18),
),
style: ElevatedButton.styleFrom(primary: Colors.blue[900]),
),
],
),
],
),
)
],
),
),
),
);
}
}

How to provide filled places in Flutter

First I want to introduce the pages.
Form Page
This is where I fill a form. When I click save as draft it will save the form data to the SQLite database. For now, I haven't implemented SQLite yet. Anyway, But I have a list that buffers the form input. When you click on Save as draft, I create a FormData object and add that data to a list and provide that list with Provider.
Form Page Code
class FormPage extends StatefulWidget {
FormData? formData = FormData();
FormPage({Key? key, this.formData}) : super(key: key);
#override
State<FormPage> createState() => _HomePageState();
}
class _HomePageState extends State<FormPage> {
String? isEmpty(String val) {
String? text;
setState(() {
if (val.isEmpty) {
text = 'Boş bırakılamaz';
}
});
return text;
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xffffe0b2),
appBar: AppBar(
// backgroundColor: Colors.teal.shade400,
title: const Text('Hasta Etkileşim Kaydı'),
centerTitle: true,
backgroundColor: const Color(0xffffb74d),
elevation: 0,
),
body: SafeArea(
child: FutureBuilder(
future: readJsonData(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text(snapshot.error.toString());
} else if (snapshot.hasData) {
var items = snapshot.data as List<dynamic>;
var listStajTuru = items[0].stajTuruItems;
var listCinsiyet = items[0].cinsiyetItems;
var listEtkilesim = items[0].etkilesimTuruItems;
var listKapsam = items[0].kapsamItems;
var listOrtam = items[0].ortamItems;
var listDoktor = items[0].doktorItems;
return Form(
key: _formKey,
child: ListView(
shrinkWrap: true,
children: [
myDropDownContainer(_valueStajTuru, listStajTuru,
hintTextStajTuru, onChangedStajTuru),
myDropDownContainer(_valueDoktor, listDoktor,
hintTextDoktor, onChangedDoktor),
myDropDownContainer(_valueCinsiyet, listCinsiyet,
hintTextCinsiyet, onChangedCinsiyet),
myDropDownContainer(_valueEtkilesim, listEtkilesim,
hintTextEtkilesim, onChangedEtkilesim),
myDropDownContainer(_valueKapsam, listKapsam,
hintTextKapsam, onChangedKapsam),
myDropDownContainer(_valueOrtam, listOrtam,
hintTextOrtam, onChangedOrtam),
myTextFieldRow(20, "Kayıt No: ", 10,
_formData.setKayitNo, isEmpty),
myTextFieldRow(
20, "Hastanın Yaşı:", 3, _formData.setYas, isEmpty),
myTextFieldRow(
20, "Şikayet:", 10, _formData.setSikayet, isEmpty),
myTextFieldRow(50, "Ayırıcı Tanı:", 50,
_formData.setAyiriciTani, isEmpty),
myTextFieldRow(50, "Kesin Tanı:", 50,
_formData.setKesinTani, isEmpty),
myTextFieldRow(50, "Tedavi Yöntemi:", 100,
_formData.setTedaviYontemi, isEmpty),
const SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
submitButton(context, "Sava as Draft"),
submitButton(context, "GÖNDER"),
],
),
],
),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
})),
);
}
//Kullanıcı kaydet butonuna basarsa local olarak kaydedecek
Container submitButton(BuildContext context, String title) {
return Container(
width: 120,
height: 50,
margin: const EdgeInsets.all(12),
child: TextButton(
onPressed: () {
setState(() {
if (_formKey.currentState!.validate()) {
Provider.of<FormAdd>(context, listen: false)
.addNewFormToList(_formData);
alertDialog(context).then((_) =>_formKey.currentState!.reset());
}
});
},
child: Text(
title,
style: kTextStyle.copyWith(
fontSize: 14, color: Colors.white, fontWeight: FontWeight.bold),
),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(
const Color(0xffffa726),
),
),
),
);
}
//DropDownWidget
Container myDropDownContainer(String initialVal, List<String> listItems,
String text, Function myFunc) {
return Container(
margin: const EdgeInsets.all(8),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
width: 120,
child: Text(
text,
style: kTextStyle,
),
),
const SizedBox(
width: 20,
),
Expanded(
child: Container(
height: 50,
decoration: BoxDecoration(
color: Colors.orangeAccent,
borderRadius: BorderRadius.circular(5)),
child: DropdownButtonFormField<String>(
// autovalidateMode: AutovalidateMode.always,
//menuMaxHeight: 300,
validator: (value) {
if (value!.isEmpty) {
return "485s4a8sd4as85";
}
},
decoration: const InputDecoration(border: InputBorder.none),
isExpanded: true,
//onTap: () => myFunc,
//borderRadius: BorderRadius.circular(5),
value: initialVal,
icon: const Icon(
Icons.arrow_downward,
color: Colors.black38,
),
iconSize: 24,
elevation: 16,
dropdownColor: Colors.deepOrange,
style: kTextStyle.copyWith(color: Colors.black),
onChanged: (val) => myFunc(val),
items: listItems.map<DropdownMenuItem<String>>((String? val) {
return DropdownMenuItem(
//TODO: Set default values
value: val == null ? val = initialVal : val = val,
child: Text(
val,
style: kTextStyle.copyWith(color: Colors.black),
),
);
}).toList(),
),
),
)
],
),
);
}
//TextFieldWidget
Row myTextFieldRow(double height, String text, int? maxLength,
Function function, Function regexFunction) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 80,
height: height,
child: Text(
text,
style: kTextStyle.copyWith(color: Colors.black54),
),
),
const SizedBox(
width: 10,
),
Expanded(
child: TextFormField(
validator: (value) => regexFunction(value),
// focusNode: FocusNode(),
onChanged: (input) {
function(input);
},
autofocus: false,
textAlignVertical: TextAlignVertical.bottom,
style: kTextStyle.copyWith(fontSize: 16),
maxLength: maxLength,
maxLines: null, //TODO:Arrange maxlines for the inputs
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.fromLTRB(0, 0, 0, height),
border: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.green),
borderRadius: BorderRadius.all(Radius.circular(3))),
// labelStyle:kTextStyle.copyWith(fontSize: 16, color: Colors.white54),
),
),
),
],
);
}
Future<List<FormContent>> readJsonData() async {
final jsonData =
await rootBundle.rootBundle.loadString('assets/json/formdata.json');
return [
for (final e in json.decode(jsonData)) FormContent.fromJson(e),
];
}
final _formKey = GlobalKey<FormState>();
final FormData _formData = FormData();
String _valueEtkilesim = "Gözlem";
String _valueKapsam = "Öykü";
String _valueOrtam = "Poliklinik";
String _valueDoktor = "Diğer";
String _valueStajTuru = "Ortopedi";
String _valueCinsiyet = "Erkek"; // initial value
final String hintTextCinsiyet = "Cinsiyet:";
final String hintTextStajTuru = "Staj Türü:";
final String hintTextEtkilesim = "Etkileşim Türü:";
final String hintTextKapsam = "Kapsam:";
final String hintTextOrtam = "Gerçekleştiği Ortam:";
final String hintTextDoktor = "Klinik Eğitici:";
void onChangedCinsiyet(String? newVal) {
setState(() {
_valueCinsiyet = newVal!;
_formData.setCinsiyet(_valueCinsiyet);
});
}
void onChangedStajTuru(String newVal) {
setState(() {
_valueStajTuru = newVal;
_formData.setStajTuru(newVal);
});
}
void onChangedEtkilesim(String newVal) {
setState(() {
_valueEtkilesim = newVal;
_formData.setEtkilesimTuru(newVal);
});
}
void onChangedKapsam(String newVal) {
setState(() {
_valueKapsam = newVal;
_formData.setKapsam(newVal);
});
}
void onChangedOrtam(String newVal) {
setState(() {
_valueOrtam = newVal;
_formData.setOrtam(newVal);
});
}
void onChangedDoktor(String newVal) {
setState(() {
_valueDoktor = newVal;
_formData.setDoktor(newVal);
});
}
}
Assume, we saved the form as a draft. Now, It is in the DraftsPage.
Drafts Page
Everything is alright up to now. I have a list of the saved in draft forms. When I click on any list item I could get the form information (3rd picture).
Here is the question.
When I click on the Edit button. I want to renavigate to the Form Page.However this time I want to fill the places with the relevant data. For instance, this time Kayıt No: TextField shouldn't be empty it must be filled with 555, because it was saved to draft. And unfilled places must be blank. I know I need to provide an object of the form(formData) but, I couldn't manage it. When I click on the Edit button. I should provide that object and use it in the Form Page to fill those forms. But, how?
Draft Code
class Drafts extends StatelessWidget {
#override
Widget build(BuildContext context) {
void pushToFormPage(FormData formData) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FormView(
formData: formData,
)));
}
List<FormData> _forms = Provider.of<FormAdd>(context).getForms();
return Scaffold(
backgroundColor: Colors.grey,
appBar: AppBar(
title: const Text("Taslaklar"),
centerTitle: true,
),
body: ListView.separated(
separatorBuilder: (BuildContext context, int index) => const Divider(
height: 5,
color: Colors.blueAccent,
),
itemCount: _forms.length,
itemBuilder: (BuildContext context, int index) {
return studentListViewInstanceContainer(
const Color.fromARGB(200, 200, 130, 240),
pushToFormPage,
_forms[index], context);
},
),
);
}
}
GestureDetector studentListViewInstanceContainer(
Color color, Function function, FormData formData,BuildContext context) {
return GestureDetector(
onTap: () => function(formData),
child: Container(
height: 100,
color: color,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Kayıt No: ${formData.getKayitNo()}',
style: kTextStyle,
),
Text(
'Tarih: ${formData.getKayitNo()}',
style: kTextStyle.copyWith(fontSize: 15),
) //TODO: implement DateT
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ElevatedButton(onPressed: (){
// taslağa kaydedilmiş bilgiler tekrar yüklenecek.
FormData data= Provider.of<FormData>(context,listen: false);
Navigator.push(context, MaterialPageRoute(builder: (context)=>FormPage(formData: data,)));
},
child:const Text('Edit'),
),
const SizedBox(width: 5,),
ElevatedButton(onPressed: (){
},
child: const Text('Delete'),
),
],
),
],
),
),
);
}
This is my FormData model class.
class FormData with ChangeNotifier{
String? _kayitNo;
String? _stajTuru;
String? _doktor; //TODO: Convert string to AttendingPhysician type object
// late AttendingPhysician klinikEgitici;
String? _yas; // TODO: Convert to string later
String? _cinsiyet;
String? _sikayet;
String? _ayiriciTani;
String? _kesinTani;
String? _tedaviYontemi;
String? _etkilesimTuru;
String? _kapsam;
String? _gerceklestigiOrtam;
//DateTime tarih;
String getKayitNo()=>_kayitNo!;
String getStajTuru()=>_stajTuru!;
String getDoktor()=>_doktor!;
String getYas()=>_yas!;
String getCinsiyet()=>_cinsiyet!;
String getSikayet()=>_sikayet!;
String getAyiriciTani()=>_ayiriciTani!;
String getKesinTani()=>_kesinTani!;
String getTedaviYontemi()=>_tedaviYontemi!;
String getEtkilesimTuru()=>_etkilesimTuru!;
String getKapsam()=>_kapsam!;
String getOrtam()=>_gerceklestigiOrtam!;
void setStajTuru(String stajTuru) {
_stajTuru = stajTuru;
notifyListeners();
}
void setCinsiyet(String cinsiyet) {
_cinsiyet = cinsiyet;
notifyListeners();
}
void setEtkilesimTuru(String etkilesim) {
_etkilesimTuru = etkilesim;
notifyListeners();
}
void setKapsam(String kapsam) {
_kapsam = kapsam;
notifyListeners();
}
void setOrtam(String ortam) {
_gerceklestigiOrtam = ortam;
notifyListeners();
}
void setKayitNo(String kayitNo) {
_kayitNo = kayitNo;
notifyListeners();
}
void setYas(String yas) {
_yas = yas;
notifyListeners();
}
void setSikayet(String sikayet) {
_sikayet = sikayet;
notifyListeners();
}
void setAyiriciTani(String ayiriciTani) {
_ayiriciTani = ayiriciTani;
notifyListeners();
}
void setKesinTani(String kesinTani) {
_kesinTani = kesinTani;
notifyListeners();
}
void setTedaviYontemi(String tedaviYontemi) {
_tedaviYontemi = tedaviYontemi;
notifyListeners();
}
void setDoktor(String doktor){
_doktor=doktor;
notifyListeners();
}
}
To make it easier to understand the question. This process is the same as saving mail as a draft. When you want to edit the mail, the unfinished mail will show up not an empty mail.

Map<dynamic,dynamic> is null after loading currencies from API

Any idea why my currencies map is null in the CurrencyConverterState class? I am loading currencies from an API to my currencies map in class API (see code for class API) and also trying to set state after the loading is done. After loading the currencies from the API to my currencies map I can also access the rates from the map so that means that my map is working fine and is not null. I did that test by printing a currency rate and it was fine. But that works just in the API class. The problem is that as soon as I test my currencies map in class CurrencyConverterState it says that the map is null and I am stuck in circular progress indicator (see code for class CurrencyConverterState). I dont really know why it says that the map is null. Any help appreciated.
API class code:
class API
{
var fromTextController = new TextEditingController();
Map<dynamic, dynamic> currencies;
String fromCurrency;
String toCurrency;
String result;
API(String from, String to){
fromCurrency = from;
toCurrency = to;
}
Future<dynamic> loadCurrencies() async {
String uri = "http://api.openrates.io/latest";
var response = await http
.get(Uri.encodeFull(uri), headers: {"Accept": "application/json"});
var responseBody = json.decode(response.body);
Map curMap = responseBody['rates'];
currencies = curMap;
setState(() {});
print (currencies["SEK"]);
}
Future<dynamic> doConversion() async {
String uri =
"http://api.openrates.io/latest?base=$fromCurrency&symbols=$toCurrency";
var response = await http
.get(Uri.encodeFull(uri), headers: {"Accept": "application/json"});
var responseBody = json.decode(response.body);
setState(() {
result = (double.parse(fromTextController.text) *
(responseBody["rates"][toCurrency]))
.toString();
});
setState(() {});
return "Success";
}
void setState(Null Function() param0) {}
}
CurrencyConverterState class code:
class CurrencyConverterState extends State<CurrencyConverter> {
final API api = new API("USD", "SEK");
CurrencyConverterState();
int i = 1;
#override
void initState() {
super.initState();
api.loadCurrencies();
api.fromTextController.addListener(doConversion);
setState(() {
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false,
backgroundColor: Theme.of(context).primaryColor,
body: api.currencies?.keys == null
? Center(child: CircularProgressIndicator())
: Stack(children: [
Positioned(
top: 30,
child: Container(
alignment: Alignment.center,
height: MediaQuery.of(context).size.height / 2,
width: MediaQuery.of(context).size.width,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 10,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
'Converter',
style: TextStyle(
color: Colors.black, fontSize: 22.0),
),
ListTile(
title: TextField(
controller: api.fromTextController,
decoration: InputDecoration(
hintText: 'Enter a number'),
style: TextStyle(
fontSize: 20.0, color: Colors.black),
keyboardType: TextInputType.numberWithOptions(
decimal: true),
),
trailing:
buildDropDownButton(api.fromCurrency),
),
ListTile(
title: Chip(
label: api.result != null
? Container(
width: 1000,
height: 40,
child: Text(
api.result,
style: Theme.of(context)
.textTheme
.headline4,
),
)
: Container(
width: 1000,
height: 40,
child: Text(" "))),
trailing:
buildDropDownButton(api.toCurrency),
),
],
)),
),
),
),
]));
}
Widget buildDropDownButton(String currencyCategory) {
return DropdownButton(
value: currencyCategory,
dropdownColor: Colors.white,
icon: Icon(Icons.arrow_downward),
iconSize: 24,
items: api.currencies.keys.map((dynamic value) => DropdownMenuItem(
value: value,
child: Row(children: <Widget>[
Text(value),
])))
.toList(),
onChanged: (dynamic value) {
if (currencyCategory == api.fromCurrency) {
api.fromCurrency = value;
} else {
api.toCurrency = value;
}
setState(() {});
});
}
doConversion() {
api.doConversion();
setState(() {});
}
}
Actually, you are retrieving currencies before they get retrieved and you are never updating the UIs when they are retrieved.
This is a possible solution:
//In API class
Future<Map<String,dynamic>> loadCurrencies() async {
String uri = "http://api.openrates.io/latest";
var response = await http
.get(Uri.encodeFull(uri), headers: {"Accept": "application/json"});
var responseBody = json.decode(response.body);
Map<String,dynamic> curMap = responseBody['rates'];
print (currencies["SEK"]);
return curMap;
}
Then in your main class use a futureBuilder:
return Scaffold(
resizeToAvoidBottomPadding: false,
backgroundColor: Theme.of(context).primaryColor,
body: FutureBuilder(
future: api.loadCurrencies(),
builder: (context, currencies) =>{
return currencies==null?
? Center(child: CircularProgressIndicator())
: Stack(/*rest of your code*/);
})
);

How to implement a network data fetch and then display in checkbox in alert inside showDialog with setState

I couldn't find a way to fetch data from network API inside showDialog > StatefulBuilder > AlertDialog. After fetching, this data should display in checkboxes and then finally on click ok, the selected checkboxes data is returned to the parent widget. There are more states other than these checkbox states in the alert. But the Navigator.of(context).pop() can return only single value.
Is there a way to rebuild the StatefulBuilder with setState on parent widget. Or some easy hack to rebuild the StatefulBuilder from an outside function like fetchOrderStatus() in the below code. (might be possible with a key on StatefulBuilder, but don't know how).
Below is my code
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
import 'dart:convert';
import 'package:recase/recase.dart';
import 'package:woocommerceadmin/src/orders/widgets/OrderDetailsPage.dart';
import 'package:barcode_scan/barcode_scan.dart';
class OrdersListPage extends StatefulWidget {
final String baseurl;
final String username;
final String password;
OrdersListPage({
Key key,
#required this.baseurl,
#required this.username,
#required this.password,
}) : super(key: key);
#override
_OrdersListPageState createState() => _OrdersListPageState();
}
class _OrdersListPageState extends State<OrdersListPage> {
String baseurl;
String username;
String password;
List ordersListData = List();
int page = 1;
bool hasMoreToLoad = true;
bool isListLoading = false;
bool isSearching = false;
String searchValue = "";
String sortOrderByValue = "date";
String sortOrderValue = "desc";
bool isOrderStatusOptionsReady = false;
bool isOrderStatusOptionsError = false;
String orderStatusOptionsError;
Map<String, bool> orderStatusOptions = {};
final scaffoldKey = new GlobalKey<ScaffoldState>();
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
new GlobalKey<RefreshIndicatorState>();
#override
void initState() {
super.initState();
baseurl = widget.baseurl;
username = widget.username;
password = widget.password;
fetchOrdersList();
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
appBar: _myAppBar(),
body: RefreshIndicator(
key: _refreshIndicatorKey,
onRefresh: handleRefresh,
child: Column(
children: <Widget>[
Expanded(
child: NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification scrollInfo) {
if (hasMoreToLoad &&
!isListLoading &&
scrollInfo.metrics.pixels ==
scrollInfo.metrics.maxScrollExtent) {
handleLoadMore();
}
},
child: ListView.builder(
itemCount: ordersListData.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OrderDetailsPage(
id: ordersListData[index]["id"],
),
),
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
_orderDate(ordersListData[index]),
_orderIdAndBillingName(
ordersListData[index]),
_orderStatus(ordersListData[index]),
_orderTotal(ordersListData[index])
]),
),
)
]),
),
);
}),
),
),
if (isListLoading)
Container(
height: 60.0,
color: Colors.white,
child: Center(
child: SpinKitFadingCube(
color: Colors.purple,
size: 30.0,
)),
),
],
),
),
);
}
Future<void> fetchOrderStatus() async {
String url =
"$baseurl/wp-json/wc/v3/reports/orders/totals?consumer_key=$username&consumer_secret=$password";
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = false;
});
dynamic response;
try {
response = await http.get(url);
if (response.statusCode == 200) {
if (json.decode(response.body) is List &&
!json.decode(response.body).isEmpty) {
json.decode(response.body).forEach((item) {
if (item is Map) {
orderStatusOptions.putIfAbsent(item["slug"], () => false);
}
});
setState(() {
isOrderStatusOptionsReady = true;
});
} else {
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = true;
orderStatusOptionsError = "Failed to fetch order status options";
});
}
} else {
String errorCode = "";
if (json.decode(response.body) is Map &&
json.decode(response.body).containsKey("code") &&
json.decode(response.body)["code"] is String) {
errorCode = json.decode(response.body)["code"];
}
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = true;
orderStatusOptionsError =
"Failed to fetch order status options. Error: $errorCode";
});
}
} catch (e) {
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = true;
orderStatusOptionsError =
"Failed to fetch order status options. Error: $e";
});
}
}
Widget _myAppBar() {
Widget myAppBar;
myAppBar = AppBar(
title: Text("Orders List"),
actions: <Widget>[
GestureDetector(
child: Padding(
padding: const EdgeInsets.only(left: 10),
child: Icon(Icons.search),
),
onTap: () {
setState(() {
isSearching = !isSearching;
});
},
),
GestureDetector(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Icon(Icons.filter_list),
),
onTap: _orderFilter,
),
],
);
}
return myAppBar;
}
void _orderFilter() async {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context){
// fetchOrderStatus();
return StatefulBuilder(builder: (context, StateSetter setState) {
return AlertDialog(
title: Text("Sort & Filter"),
titlePadding: EdgeInsets.fromLTRB(15, 20, 15, 0),
content: Container(
width: 300,
height: 400,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Sort by",
style: Theme.of(context).textTheme.subhead,
),
Row(
children: <Widget>[
Expanded(
child: Container(
child: DropdownButton<String>(
underline: SizedBox.shrink(),
value: sortOrderByValue,
onChanged: (String newValue) {
FocusScope.of(context)
.requestFocus(FocusNode());
setState(() {
sortOrderByValue = newValue;
});
},
items: <String>[
"date",
"id",
"title",
"slug",
"include"
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value.titleCase,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.body1,
),
);
}).toList(),
),
),
),
InkWell(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 10),
child: Icon(
Icons.arrow_downward,
color: (sortOrderValue == "desc")
? Theme.of(context).primaryColor
: Colors.black,
),
),
onTap: () {
setState(() {
sortOrderValue = "desc";
});
},
),
InkWell(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 10),
child: Icon(
Icons.arrow_upward,
color: (sortOrderValue == "asc")
? Theme.of(context).primaryColor
: Colors.black,
),
),
onTap: () {
setState(() {
sortOrderValue = "asc";
});
},
),
],
),
Text(
"Filter by",
style: Theme.of(context).textTheme.subhead,
),
Text(
"Order Status",
style: Theme.of(context).textTheme.body1.copyWith(
fontWeight: FontWeight.bold, fontSize: 16),
),
isOrderStatusOptionsReady
? ListView(
children:
orderStatusOptions.keys.map((String key) {
return new CheckboxListTile(
title: Text(key),
value: orderStatusOptions[key],
onChanged: (bool value) {
setState(() {
orderStatusOptions[key] = value;
});
},
);
}).toList(),
)
: Container(
child: Center(
child: SpinKitFadingCube(
color: Theme.of(context).primaryColor,
size: 30.0,
),
),
)
],
),
),
),
contentPadding: EdgeInsets.fromLTRB(15, 10, 15, 0),
actions: <Widget>[
FlatButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
});
}
}
You have a couple of options
Fetch the data before showing the dialog. Using either async/await keywords or .then, you wait for the fetching of data to complete, then use the data in the dialog
void _orderFilter() async {
await fetchOrderStatus();
showDialog(...); //Use the response in the dialog
}
Create a new stateful widget for the dialog and have fetchOrderStatus() be a method in that class. This allows you to have more control over what to display as well as state changes in the dialog.
#gaurav-jain I have followed your question from Github where you asked a question about my answer to this problem. How I did it is i have a button that when clicked immediately opens the dialog that then waits for the Future to load data from the API: The async function _showOptions() renders the dialog that renders a list of checkboxes with options fetched from API:
new RaisedButton(
color: Colors.green,
padding: EdgeInsets.all(20.0),
onPressed: () {
if (state._isLoading){
// don't do anything when form is submitting and this button is pressed again
return null;
}
else {
if (state._formKey.currentState.validate()) {
state._showOptions().then((selected){
print(state.selectedOptions);
if (state.selectedOptions.isNotEmpty) {
_submitForm();
}
else {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text('You have not selected any option'),
actions: <Widget>[
FlatButton(
child: Text('OK'),
onPressed: () {
Navigator.of(context, rootNavigator: true).pop();
},
),
],
);
}
);
}
});
}
else {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Your form has errors. Rectify them and submit again'),
)
);
}
}
},
child: Text(state._isLoading ? 'Submitting...' : 'Submit', style: new TextStyle(color: Colors.white)),
),
The state here is the parent widget's state, but the async dialog has it's own state to make it work. You can refer back to the github comment for the other pieces of the code here https://github.com/flutter/flutter/issues/15194#issuecomment-450490409
As suggested by #wxker, 2nd approach, I have implemented other stateful widget which returns AlertDialog.
Parent Widget Calling showDialog on tap:
IconButton(
icon: Icon(Icons.filter_list),
onPressed: () {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return OrdersListFiltersModal(
baseurl: widget.baseurl,
username: widget.username,
password: widget.password,
sortOrderByValue: sortOrderByValue,
sortOrderValue: sortOrderValue,
orderStatusOptions: orderStatusOptions,
onSubmit:
(sortOrderByValue, sortOrderValue, orderStatusOptions) {
setState(() {
this.sortOrderByValue = sortOrderByValue;
this.sortOrderValue = sortOrderValue;
this.orderStatusOptions = orderStatusOptions;
});
handleRefresh();
},
);
},
);
},
),
Child stateful widget returning alert with default value and function callback in constructor to change parent widget state.
Widget build(BuildContext context) {
return AlertDialog(
title: Text("Sort & Filter"),
titlePadding: EdgeInsets.fromLTRB(15, 20, 15, 0),
content: Container(
height: 400,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Sort by",
style: Theme.of(context).textTheme.subhead,
),
Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: Row(
children: <Widget>[
Expanded(
child: Container(
child: DropdownButton<String>(
underline: SizedBox.shrink(),
value: sortOrderByValue,
onChanged: (String newValue) {
FocusScope.of(context).requestFocus(FocusNode());
setState(() {
sortOrderByValue = newValue;
});
},
items: <String>[
"date",
"id",
"title",
"slug",
"include"
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value.titleCase,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.body1,
),
);
}).toList(),
),
),
),
InkWell(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Icon(
Icons.arrow_downward,
color: (sortOrderValue == "desc")
? Theme.of(context).primaryColor
: Colors.black,
),
),
onTap: () {
setState(() {
sortOrderValue = "desc";
});
},
),
InkWell(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Icon(
Icons.arrow_upward,
color: (sortOrderValue == "asc")
? Theme.of(context).primaryColor
: Colors.black,
),
),
onTap: () {
setState(() {
sortOrderValue = "asc";
});
},
),
],
),
),
Text(
"Filter by",
style: Theme.of(context).textTheme.subhead,
),
SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
"Order Status",
style: Theme.of(context)
.textTheme
.body1
.copyWith(fontWeight: FontWeight.bold, fontSize: 16),
),
),
SizedBox(
height: 10,
),
isOrderStatusOptionsError
? Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
child: Text(
orderStatusOptionsError,
style: Theme.of(context).textTheme.body1,
),
),
),
],
)
: isOrderStatusOptionsReady
? Column(
children: orderStatusOptions.keys.map((String key) {
return GestureDetector(
onTap: () {
setState(() {
orderStatusOptions[key] =
!orderStatusOptions[key];
});
},
child: Container(
color: Colors.transparent,
height: 30,
child: Row(
children: <Widget>[
Checkbox(
value: orderStatusOptions[key],
onChanged: (bool value) {
setState(() {
orderStatusOptions[key] = value;
});
},
),
Expanded(
child: Text(
key.titleCase,
style:
Theme.of(context).textTheme.body1,
),
),
],
),
),
);
}).toList(),
)
: Container(
padding: EdgeInsets.fromLTRB(0, 20, 0, 0),
child: Center(
child: SpinKitPulse(
color: Theme.of(context).primaryColor,
size: 50,
),
),
)
],
),
),
),
contentPadding: EdgeInsets.fromLTRB(15, 10, 15, 0),
actions: <Widget>[
FlatButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text("Ok"),
onPressed: () {
widget.onSubmit(
sortOrderByValue, sortOrderValue, orderStatusOptions);
Navigator.of(context).pop();
},
)
],
);
}
Future<void> fetchOrderStatusOptions() async {
String url =
"${widget.baseurl}?consumer_key=${widget.username}&consumer_secret=${widget.password}";
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = false;
});
http.Response response;
try {
response = await http.get(url);
if (response.statusCode == 200) {
if (json.decode(response.body) is List &&
!json.decode(response.body).isEmpty) {
Map<String, bool> tempMap = orderStatusOptions;
json.decode(response.body).forEach((item) {
if (item is Map &&
item.containsKey("slug") &&
item["slug"] is String &&
item["slug"].isNotEmpty) {
tempMap.putIfAbsent(item["slug"], () => false);
}
});
setState(() {
isOrderStatusOptionsReady = true;
orderStatusOptions = tempMap;
});
} else {
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = true;
orderStatusOptionsError = "Failed to fetch order status options";
});
}
} else {
String errorCode = "";
if (json.decode(response.body) is Map &&
json.decode(response.body).containsKey("code") &&
json.decode(response.body)["code"] is String) {
errorCode = json.decode(response.body)["code"];
}
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = true;
orderStatusOptionsError =
"Failed to fetch order status options. Error: $errorCode";
});
}
} catch (e) {
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = true;
orderStatusOptionsError =
"Failed to fetch order status options. Error: $e";
});
}
}
}