Issue
This Content is from Stack Overflow. Question asked by Mohammed Bekele
I’m using FutureBuilder
for fetching API request. but it only builds once and it doesn’t update ui unless hot reloded. i aslo tried StreamBuilder
and convert the future
method to stream
. so how can i update my ui. please i already asked this question and got no answer. whay is this happening?
model
import 'dart:convert';
List<User> usersFromJson(String str) =>
List<User>.from(json.decode(str).map((json) => User.fromJson(json)));
String usersToJson(List<User> data) =>
json.encode(List<dynamic>.from(data.map((e) => e.toJson())));
class User {
int? id;
String? name;
String? username;
String? email;
String? role;
User({this.id, this.name, this.username, this.email, this.role});
@override
toString() => 'User: $name';
factory User.fromJson(Map<String, dynamic> json) => User(
email: json['email'],
name: json['name'],
id: json['id'],
username: json['username'],
role: json['role']);
Map<String, dynamic> toJson() =>
{"name": name, "username": username, "email": email, "role": role};
}
api call
Future fetchUsers() async {
Uri url = Uri.parse("${BASE_URL}user");
final response = await http.get(url, headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer $TOKEN',
});
var userview = <User>[];
if (response.statusCode == 200) {
var jsonres = json.decode(response.body);
for (var res in jsonres) {
userview.add(User.fromJson(res));
}
}
return userview;
}
Future createUser(String name, String username, String email, String password,
String roles) async {
Uri url = Uri.parse("${BASE_URL}user");
final response = await http
.post(url,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer $TOKEN',
},
body: jsonEncode(<String, dynamic>{
'name': name,
'email': email,
'username': username,
'password': password,
'roles': roles
}))
.then((value) => fetchUsers());
}
and my page
StreamBuilder(
stream: fetchUsers().asStream(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: [
PaginatedDataTable(
sortColumnIndex: sortColumnIndex,
sortAscending: isAscending,
columns: [
DataColumn(
label: const Text("Id"),
onSort: onSort),
DataColumn(
label: const Text("Name"),
onSort: onSort),
DataColumn(
label: const Text("Username"),
onSort: onSort),
DataColumn(
label: const Text("Email"),
onSort: onSort),
DataColumn(
label: const Text("Roles"),
onSort: onSort),
DataColumn(
label: const Text("Actions"),
onSort: onSort),
],
header: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
"Manage Users",
style: TextStyle(
fontSize: width * 0.04,
fontWeight: FontWeight.normal),
),
MaterialButton(
onPressed: () {
showMaterialModalBottomSheet(
context: context,
builder: (context) => SizedBox(
height: height * 0.9,
child:
BottomSheetWidget(),
),
shape:
const RoundedRectangleBorder(
borderRadius:
BorderRadius.only(
topLeft: Radius
.circular(
15),
topRight: Radius
.circular(
15))));
},
color: const Color.fromRGBO(
30, 119, 66, 1),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(10)),
child: Text(
"Add User",
style: TextStyle(
color: Colors.white,
fontSize: width * 0.03),
),
)
],
),
source: dataSource(
snapshot.data! as List<User>))
],
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return const Center(
child: CircularProgressIndicator());
})
additionally i’m using paginated datatable and this is the code for that.(it’s related)
in the page
DataTableSource dataSource(List<User> userList) =>
MyTable(datasList: userList, context: context);
and the datasource page i’m calling the createUser
here.
class MyTable extends DataTableSource {
MyTable({required this.datasList, required this.context});
final List<User> datasList;
BuildContext context;
Widget Button(String title, Color color, String id) {
return MaterialButton(
onPressed: () {
//deleteUser(id);
//updateUser(id, title);
createUser("name2", "user2", "email2@email.com", "password", "Admin");
},
child: Text(
title,
style: const TextStyle(color: Colors.white),
),
color: color,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
);
}
@override
DataRow? getRow(int index) {
return DataRow.byIndex(index: index, cells: [
DataCell(Text(datasList[index].id.toString())),
DataCell(ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 100),
child: Text(
datasList[index].name.toString(),
overflow: TextOverflow.ellipsis,
),
)),
DataCell(ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 100),
child: Text(
datasList[index].username.toString(),
overflow: TextOverflow.ellipsis,
))),
DataCell(ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 100),
child: Text(
datasList[index].email.toString(),
overflow: TextOverflow.ellipsis,
))),
DataCell(ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 100),
child: Text(
datasList[index].role.toString(),
overflow: TextOverflow.ellipsis,
))),
DataCell(Row(
children: [
Button("Edit", Colors.lightBlue, datasList[index].id.toString()),
const SizedBox(
width: 5,
),
Button("Delete", Colors.red, datasList[index].id.toString()),
],
)),
]);
}
@override
bool get isRowCountApproximate => false;
@override
int get rowCount => datasList.length;
@override
int get selectedRowCount => 0;
}
Solution
Widget rebuilding is scheduled by each interaction, using
State.setState, but is otherwise decoupled from the timing of the
stream.
i see the code and can’t found any issue. but im bit doubt with asStream()
.
as documentation said: asStream method:
Creates a Stream containing the result of this future.
maybe you can try with this : stream.fromFuture
found the issue here: https://stackoverflow.com/a/55169382/12838877
since your fetch method is not common , it is a Future
method that return value of Future
value.
Stream.fromFuture(fetchUsers)
it’s just my doubt. hope solve the problem. because it’s too long to explain in the comments, so I’ll put it in the answer section
This Question was asked in StackOverflow by Mohammed Bekele and Answered by pmatatias It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.