how to return a form widget in futureBuild in flutter - flutter

I have this code as am trying to code something to update data in firestore.
#override
Widget build(BuildContext context) {
// Use the Todo to create the UI.
return Scaffold(
appBar: AppBar(
title: Text(mid.toString()),
),
body: FutureBuilder<Member?>(
future: readMember(mid),
builder: (context, snapshot) {
if (snapshot.hasData) {
final member = snapshot.data;
/// return a form
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
);
}
if snapshot hasData I want to return a form like this
Card(
child: Row(
children: <Widget>[
TextField(
controller: controllerName,
decoration: decoration('name'),
),
const SizedBox(height: 24),
TextField(
controller: controllerAge,
decoration: decoration('Age'),
keyboardType: TextInputType.number,
),
const SizedBox(height: 24),
ElevatedButton(
child: const Text('Create'),
onPressed: () {},
),
],
));
All my attempt yield no success please I need help.

Check others state like error or if the data is null or not
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text("Got Error");
}
if (snapshot.data == null) {
return Text("No data");
}
if (snapshot.hasData) {
final member = snapshot.data;
return Card( ///here form
child: Row(
children: <Widget>[],
));
} else {
return const Center(child: CircularProgressIndicator());
}
},
And provide width on TextFiled to fix overflow, TextFiled and row are trying to get infinite with.
just wrap with Expanded
Expanded(child: TextField(...)),
You can find more about unbound height& width

Related

How to display streambuilder and dropdown correctly in flutter

I'm a new flutter developer and a bit confused here, I want to display a dropdown menu and the streambuilder in my screen. Here's the code for the dropdown.
DropdownButton<String>(
value: selectedItem,
items: services,
.map((item) => DropdownMenuItem<String>(
value:item,
child: Text(item, style: TextStyle(fonSize: 24))
)).toList(),
onChanged: (item) => setState(() => selectedItem - item),
)
Here's the scaffold with streambuilder
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: StreamBuilder<List<SportBooking>>(
stream: readBooking(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong! ${snapshot.error}');
} else if (snapshot.hasData) {
final booking = snapshot.data!;
return ListView(
children: booking.map(buildBooking).toList(),
);
} else {
return const Center(child: CircularProgressIndicator());
}
}),
);
}
Problem is I have tried with a Column widget here like below with a simple text widget, but it throws an Assertion error
body: Column(
children: [
Text('data'),
StreamBuilder<List<SportBooking>>(
stream: readBooking(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong! ${snapshot.error}');
} else if (snapshot.hasData) {
final booking = snapshot.data!;
return ListView(
children: booking.map(buildBooking).toList(),
);
} else {
return const Center(child: CircularProgressIndicator());
}
}),
],
),
How do I display both the dropdown and the streambuilder in the scaffold?
You can wrap it inside a Column Widget and now you can add as many Widgets as you want.
You can either wrap ListView with Column Widget.
Make sure to Wrap ListView with Expanded Widget otherwise it will give exception.
return Scaffold(
backgroundColor: Colors.black,
body: Column(
children: [
DropdownButton<String>(
value: selectedItem,
items: services,
.map((item) => DropdownMenuItem<String>(
value:item,
child: Text(item, style: TextStyle(fonSize: 24))
)).toList(),
onChanged: (item) => setState(() => selectedItem - item),
),
StreamBuilder<List<SportBooking>>(
stream: readBooking(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong! ${snapshot.error}');
} else if (snapshot.hasData) {
final booking = snapshot.data!;
return ListView(
children: booking.map(buildBooking).toList(),
);
} else {
return const Center(child: CircularProgressIndicator());
}
}),
],
),
);
In the ListView add the following properties
ListView(
scrollDirection: Axis.vertical,
shrinkWrap: true,

Flutter how to user setState()

One of my routes shows current data which is stored in firestore database. I am calling the function to retrieve the data from firestore in the initState method. The page will show all the data which are retrieved from firestore. It works fine i.e, when the user navigates to this page (quotesPage) it shows the data. But while navigating, for some fraction of seconds it shows error that the local variable which stores the retrieved data is null. It happens for only that fraction of seconds after which it receives the data and shows the data. So when the user navigates to that page, I want to show a progress indicator untill it receive the data. here is my code,
Map<String, dynamic> userInfo = {};
Future<void> getQoutes() async {
var data = await FirebaseFirestore.instance.collection('user').doc(auth.currentUser!.uid).get();
setState(() {
userInfo = data.data() as Map<String, dynamic>;
});
}
#override
void initState() {
getQoutes();
super.initState();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Some Quotes',
),
backgroundColor: Colors.deepOrange,
),
body: SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: ListView.builder(
itemCount: 3,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return Card_fun(userInfo['quotes'][index]);
}
)
)
],
),
)
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await popUpForm();
},
),
);
I am calling the function getQuotes() from initState() which will store the data to Map variable userInfo. So how to show a progress indicator untill the variable 'userInfo' gets data ?
Can anyone help ?
This is the updated code
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Some Quotes',
),
backgroundColor: Colors.deepOrange,
),
body: SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
FutureBuilder<void>(
future: getQoutes(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
if(snapshot.hasError) {
return Text('Error : ${snapshot.error}');
}
return Expanded(
child: ListView.builder(
itemCount: 3,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return Card_fun(userInfo['quotes'][index]);
}
)
);
default:
return const CircularProgressIndicator();
}
},
)
],
),
)
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await popUpForm();
},
),
);
You should try with Future builder or stream builder and here is the example with Future builder
FutureBuilder<String>(
future: getQoutes(), // async work
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting: return CircularProgressIndicator();
default:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
else
return Expanded(
child: ListView.builder(
itemCount: 3,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return Card_fun(userInfo['quotes'][index]);
}
)
);
}
},
)
For more read this article
another approach that might be worth looking at is using a addPostFrameCallback method called from your initState in which you can await the necessary condition and take appropriate action and trigger a setState.

FutureBuilder has empty snapshot despite Future returns proper data

I have FutureBuilder widget as Scaffold's body and I want to display a list of widgets when database returns required info but while database is properly returning data the FutureBuilder does not show any widgets(like CircularProgressIndicator or required List as it finishes its job). Code shown below:
Future<List<Widget>> getList() async{
List<Widget> list = [];
var db = dbMethods();
db.getConnection().then((conn) async {
await Future.delayed(const Duration(seconds: 1));
var result = await conn.query("select * from info", []);
for(var row in result) {
var item = BilbordItem(
firm: row[2],
constructionType: row[3],
demonstrationType: row[4],
lat: double.parse(row[5]),
long: double.parse(row[6]),
sizeX: double.parse(row[7]),
sizeY: double.parse(row[8]),
address: row[9],
positionRate: int.parse(row[10]),
colorsRate: int.parse(row[11]),
passabilityRate: int.parse(row[12]),
typeRate: int.parse(row[13])
);
print(item.address); //here i was checking if database fetch is working and it does print required info
list.add(item);
}
conn.close();
});
return list;
}
class _ListPage extends State<ListPage>{
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Список билбордов"),
centerTitle: true,
),
body: FutureBuilder(
future: getList(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.connectionState == ConnectionState.done){
if(snapshot.hasData && !snapshot.hasError){
return Center(
child: Column(
children: snapshot.data,
),
);
}
else if(snapshot.hasError){
return SingleChildScrollView(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(Icons.error_outline, color: Colors.red,),
Text(snapshot.error.toString()),
],
),
),
);
}
}else {
return Center(child: CircularProgressIndicator());
}
return Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Text("Empty"),
],
),
);
},
),
);
}
}

How to turn off CircularProgressIndicator flutter

There is a list that displays data from the database that comes to it at the time the data is fetched and until the data appears, the CircularProgressIndicator () appears so that the user knows that there is a process happening in the background.
Excellent but there is a problem with this CircularProgressIndicator () continues to work non-stop if there is no data in the database. Herein lies the problem.
It is supposed to work for a specified time and if there is no data in the database it will stop working and disappear.
Is there a way to do this? So that if there is no data that can be fetched it stops working?
My code:
class MainListView extends StatefulWidget {
MainListViewState createState() => MainListViewState();
}
class MainListViewState extends State {
final String apiURL = 'http://====================/getStudentInfo.php';
Future<List<Studentdata>> fetchStudents() async {
var response = await http.get(apiURL);
if (response.statusCode == 200) {
final items = json.decode(response.body).cast<Map<String, dynamic>>();
List<Studentdata> studentList = items.map<Studentdata>((json) {
return Studentdata.fromJson(json);
}).toList();
return studentList;
}
else {
throw Exception('Failed to load data from Server.');
}
}
#override
Widget build(BuildContext context) {
return FutureBuilder<List<Studentdata>>(
future: fetchStudents(),
builder: (context, snapshot) {
if (!snapshot.hasData)
return Center(
child: CircularProgressIndicator()
);
return ListView(
children: snapshot.data
.map((data) => Column(children: <Widget>[
GestureDetector(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.fromLTRB(20, 5, 0, 5),
child: Text(data.studentName,
style: TextStyle(fontSize: 21),
textAlign: TextAlign.left))
]),),
Divider(color: Colors.black),
],))
.toList(),
);
},
);
}
}
You can try with the below lines
return FutureBuilder<List<Studentdata>>(
future: fetchStudents(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView(
children: snapshot.data
.map((data) =>
Column(children: <Widget>[
GestureDetector(
child: Row(
crossAxisAlignment: CrossAxisAlignment
.start,
children: [
Padding(
padding: EdgeInsets.fromLTRB(
20, 5, 0, 5),
child: Text(data.studentName,
style: TextStyle(fontSize: 21),
textAlign: TextAlign.left))
]),),
Divider(color: Colors.black),
],))
.toList(),
);
}
else if (!snapshot.hasData) {
return Text("No data Available");
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return Center(
child: CircularProgressIndicator()
);
},
);
You can also set a value to CircularProgressIndicator() to stop at full circle indicator.
Just do this:
if (!snapshot.hasData && !snapshot.hasError) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(
child: Text("No data Found"),
);
} else {
// do something here
}
It means that if status code is 200 and there is no data then you are going to get an error.

UnimplementedError error in FutureBuilder while displaying inserted data from database

I'm trying to create a Futurebuilder function to call and display all data that inserted in database unfortunately I got this error 'UnimplementedError' and im pretty stock on this any suggestion will be appreciated.
Here in my full code for implementation to display data in been trying to fix my error 'UnimplementedError' in which I'm trying to do is to display inserted in list view not in web view any suggestion will be appreciated.
body: Center(
child: Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FutureBuilder<ContactsDao>(
future: _calltheStream(),
builder: (BuildContext context,
AsyncSnapshot<ContactsDao> snapshot) {
if (!snapshot.hasData ||
snapshot.connectionState == ConnectionState.none) {
return Container(
child: CircularProgressIndicator(),
);
} else {
return StreamBuilder<List<ContactObject>>(
stream: snapshot.data.findallContactsById(),
builder: (context, snapshot) {
if (!snapshot.hasData ||
snapshot.connectionState ==
ConnectionState.none) {
return Container(
child: CircularProgressIndicator(),
);
} else {
if(widget.Contactlist.length != snapshot.data.length){
widget.Contactlist = snapshot.data;
}
if(snapshot.data.length == 0){
return Center(
child: Text('No Data Found'),
);
}
return Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: snapshot.data.length,
itemBuilder:
(BuildContext context, int index) {
return Card(
child: ListTile(
leading: Checkbox(
value: widget.Contactlist[index].isSelect,
onChanged: (bool value) {
setState(() {
widget.Contactlist[index].isSelect = value;
});
},
),
trailing: GestureDetector(
onTap: () {
_selectedDetele(snapshot.data[index].id);
},
child: Icon(Icons.delete),
),
title: Text('${snapshot.data[index].task}',maxLines: 1,),
subtitle: Text('${snapshot.data[index].time}',style: TextStyle(fontSize: 10),),
));
}),
);
}
}); //DATA
} //DATA
}), // DATA
], // DATA
), // DATA
),//DATA
),
Future<ContactsDao> _calltheStream() async { //GET ALL DATA HERE
ContactDatabase contactDatabase = await widget.database;
widget._contactsdao = contactDatabase.contactsDao;
return contactDatabase.contactsDao;
}