Flutter Http call List<t> always result Null in UI - flutter

I have try many sample in stack but still can`t get the idea which part i miss, the result in UI always display null, ..
here is the code i try :
class PointBallance {
String id, date, datetime, companyid, storecode, customercode, topup, amount, remark, cashier, invoice ;
PointBallance({this.id, this.date, this.datetime, this.companyid, this.storecode, this.customercode, this.topup, this.amount, this.remark, this.cashier, this.invoice});
factory PointBallance.fromJson(Map<String, dynamic> json) {
return PointBallance(
id: json['id'],
date: json['date'],
datetime: json['datetime'],
companyid: json['company_id'],
storecode: json['store_code'],
customercode: json['customer_code'],
topup: json['topup'],
amount: json['amount'],
remark: json['remark'],
cashier: json['cashier'],
invoice: json['invoice'],
);
}
}
the part for call http is here :
Future<List<PointBallance>> pointBal() async {
var url = 'http://someUrl';
var res = await http.get(url);
if(res.statusCode == 200) {
var dtpoint = json.decode(res.body);
print(dtpoint);
var bel = List<PointBallance>.from(dtpoint.map((i) => PointBallance.fromJson(i)));
return bel;
} else {
throw Exception(
"Request to $url failed with status ${res.statusCode}: ${res.body}"
);
}
}
and for screen to display data ..
class _PointScreenState extends State<PointScreen> {
Future<List<PointBallance>> _point;
AuthService _authService = new AuthService();
#override
void initState() {
_point = _authService.pointBal();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My Point'),
),
body: FutureBuilder<List<PointBallance>>(
future: _point,
builder: (context, snapshot) {
if (snapshot.hasData) {
var dt = snapshot.data[0].id;
return Column(
children: <Widget>[
**Text('in the top $dt'),**
Expanded(
child: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder:(BuildContext context, int index){
var hei = snapshot.data[index];
return **Text(hei.id != null ? hei.id : 'Cant get data')**;
}),
),
],
);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return CircularProgressIndicator();
}),
);
}
}
in console i got result
print(dtpoint);
any guide to correctly display data result? because in console there is result.

Related

FutureBuilder creating infinite loop for fetching records

I have created a demo project for showing orders using FutureBuilder but Its not showing order, instead its giving infinite loop , so where should I correct my code
Why it is infinite?
herewith I am sending code for my provider method to fetch orders and the code where I am using it
or is there any other better option to replace future builder..
Future<void> fetchandsetorders() async {
print('I am fetchandsetorders method of provider');
final url = Uri.parse(
mylink);
final response = await http.get(url);
final List<OrderItem> loadedorders = [];
final Map<String, dynamic> extradeddata = json.decode(response.body) as Map<String, dynamic>;
extradeddata.forEach((orderid, orderdata) {
loadedorders.add(
OrderItem(
id: orderid,
products: (orderdata['products'] as List<dynamic>).map((item) {
return CartItem(
id: item['id'],
title: item['title'],
quantity: item['qty'],
price: item['price']);
}).toList(),
amount: orderdata['amount'],
date: DateTime.parse(orderdata['date']),
),
);
});
_orders=loadedorders.reversed.toList();
notifyListeners();
}
class _OrderScreenState extends State<OrderScreen> {
#override
Widget build(BuildContext context) {
final orderdata = Provider.of<Orders>(context);
print('I am buildmethod');
return Scaffold(
appBar: AppBar(
backgroundColor: Color.fromRGBO(Random().nextInt(255),
Random().nextInt(255), Random().nextInt(255), 1),
title: Text('List of orders: ' + orderdata.ordercount.toString()),
),
drawer: AppDrawer(),
body: FutureBuilder(
future: Provider.of<Orders>(context, listen: false).fetchandsetorders(),
builder: (context,snapshop){
if(snapshop.connectionState==ConnectionState.waiting)
{
return Center(child: CircularProgressIndicator());
}
else
{
if(snapshop.error!=null)
{
return Text(snapshop.error.toString());
}
else
{
return ListView.builder(
itemCount: orderdata.ordercount,
itemBuilder: (context, index) {
return OrderItemWidget(
order: orderdata.orders[index],
);
});
}
}
},
),
);
}
}
create a state variable for Future like
late myFuture = Provider.of<Orders>(context, listen: false).fetchandsetorders(),
And use on
body: FutureBuilder(
future: myFuture,

How to add List Item to FutureBuilder ListView without reloading the data from remote server? [Flutter]

I'm new in flutter, I'd like to know how to add an item list dynamically to ListView without reloading data in FutureBuilder.
When I add an item to the ListView, it duplicate the list and then added the item to that list.
The Following code, include Model clas called Job.
JobListView is a stateful widget that include the dynamic ListView.
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
class Job {
#required
String company;
String description;
String employmentType;
int id;
String location;
String position;
List<String> skillsRequired;
Job(
this.company,
this.description,
this.employmentType,
this.id,
this.location,
this.position,
this.skillsRequired);
Job.fromJson(Map<String, dynamic> json) {
company = json['company'];
description = json['description'];
employmentType = json['employmentType'];
id = json['id'];
location = json['location'];
position = json['position'];
if (json['skillsRequired'] != null) {
skillsRequired = new List<String>();
json['skillsRequired'].forEach((v) {
skillsRequired.add(v);
});
}
}
}
class JobListView extends StatefulWidget {
#override
_JobListViewState createState() => _JobListViewState();
}
class _JobListViewState extends State<JobListView> {
List<Job> data = List<Job>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<Job>>(
future: _getJob(),
builder: (context, snapshot) {
if (snapshot.hasData) {
data = snapshot.data;
return _listViewFormat(data);
} else if (snapshot.hasError) {
return Container();
}
return Center(
child: Container(
width: 50,
height: 50,
child: CircularProgressIndicator(),
),
);
},
) ,
floatingActionButton: (FloatingActionButton(child: Icon(Icons.add),onPressed: (){
setState(() {
var j = Job("CompanyX","Eng.5 position","Full-time",0,"Cairo","Senior",null);
data.add(j);
});
},)),
);
}
}
ListView _listViewFormat(List<Job> data) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return _tile(data[index].position, data[index].description, Icons.work);
});
}
ListTile _tile(String title, String subtitle, IconData iconData) {
return ListTile(
title: Text(title, style: TextStyle(fontSize: 20)),
subtitle: Text(
subtitle,
style: TextStyle(fontSize: 12),
),
leading: Icon(iconData),
trailing: Icon(Icons.arrow_right),
);
}
Future<List<Job>> _getJob() async {
String baseUrl = 'https://mock-json-service.glitch.me';
var response = await get(baseUrl);
if (response.statusCode == 200) {
List jsonResponse = json.decode(response.body);
return jsonResponse.map((job) => new Job.fromJson(job)).toList();
}
}
Check out this more explanation How to deal with unwanted widget build?
if future changes you will see changes
Move _getJob method inside initState like this:
class _JobListViewState extends State<JobListView> {
List<Job> data = List<Job>();
Future<List<Job>> getJobFuture;
#override
void initState() {
super.initState();
getJobFuture = _getJob();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<Job>>(
future: getJobFuture,
builder: (context, snapshot) {
if (snapshot.hasData) {
data = snapshot.data;
return _listViewFormat(data);
} else if (snapshot.hasError) {
return Container();
}
return Center(
child: Container(
width: 50,
height: 50,
child: CircularProgressIndicator(),
),
);
},
) ,
floatingActionButton: (FloatingActionButton(child: Icon(Icons.add),onPressed: (){
setState(() {
var j = Job("CompanyX","Eng.5 position","Full-time",0,"Cairo","Senior",null);
data.add(j);
});
},)),
);
}
}

flutter pull up to refetch data from api

I want to use Refresh indicator so that when you pull up the page you are in right now rebuilds i will share with you my code i have tried many times but really i can't find a straight way around it here is my code
class Companies {
final int id;
final String name;
final String companyLogo;
Companies({this.id, this.name, this.companyLogo});
factory Companies.fromJson(Map<String, dynamic> json) {
return Companies(
id: json['id'],
name: json['name'],
companyLogo: json['company_logo'],
);
}
}
Future<List<Companies>> fetchCompanies() async {
final response = await http.get('$webSiteUrl/company/api/fetch');
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return parseCompanies(response.body);
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load the companies');
}
}
List<Companies> parseCompanies(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<Companies>((json) => Companies.fromJson(json)).toList();
}
class CompaniesPage extends StatefulWidget{
#override
_CompaniesState createState() => _CompaniesState();
}
class _CompaniesState extends State<CompaniesPage> {
var refreshKey = GlobalKey<RefreshIndicatorState>();
Future<List<Companies>> companies;
#override
void initState() {
super.initState();
companies = fetchCompanies();
}
Future<Null> refreshCompanies() async {
refreshKey.currentState?.show(atTop: false);
setState(() {
companies = fetchCompanies();
});
return await companies;
}
Widget build(BuildContext context) {
checkVersion(context);
return Scaffold(
body: Center(
child: FutureBuilder<List<Companies>>(
future: companies,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Companies> companies = snapshot.data;
if(companies.length >= 1){
return MainLayout(
RefreshIndicator(
key: refreshKey,
onRefresh: refreshCompanies,
child: GridView.count(
crossAxisCount: 2 ,
children: List.generate(companies.length, (index) {
return GestureDetector(
onTap: () => {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Categories(companies[index].id, companies[index].name)),
)},
child: CompaniesInterface(companies[index].id , companies[index].name , companies[index].companyLogo),
);
}),
),
),
);
}else{
return EmptyDataBase();
}
} else if (snapshot.hasError) {
return ConnectionError();
}
// By default, show a loading spinner.
return DefaultTabController(
length: 1,
child: TabBar(
indicatorColor: Colors.transparent,
tabs: <Widget>[
Tab(
child: LoadingBouncingGrid.square(
backgroundColor: Colors.cyan,
size: 40,
),
),
],
),
);
},
),
),
);
}
}
as you can see i have tested it but it isn't refreshing the page correctly what i want is how should i rebuild this page on pull up so the missing part from my code i think is refreshCompanies() function
Update :
class _CompaniesState extends State<CompaniesPage> {
StreamController<List<Companies>> companiesStreamController;
var refreshKey = GlobalKey<RefreshIndicatorState>();
Future<List<Companies>> fetchCompanies() async {
final response = await http.get('$webSiteUrl/company/api/fetch');
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return parseCompanies(response.body);
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load the companies');
}
}
loadCompanies() async {
fetchCompanies().then((result) async {
companiesStreamController.add(result);
return result;
});
}
Future<Null> refreshCompanies() async {
refreshKey.currentState.show(atTop: true);
setState(() {
loadCompanies();
});
}
#override
void initState() {
checkVersion(context);
companiesStreamController = new StreamController();
Timer.periodic(Duration(seconds: 1), (_) => loadCompanies());
super.initState();
}
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: StreamBuilder<List<Companies>>(
stream: companiesStreamController.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Companies> companies = snapshot.data;
if(companies.length >= 1){
return MainLayout(
RefreshIndicator(
onRefresh: refreshCompanies,
key: refreshKey,
child: GridView.count(
crossAxisCount: 2 ,
children: List.generate(companies.length, (index) {
return GestureDetector(
onTap: () => {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Categories(companies[index].id, companies[index].name)),
)},
child: CompaniesInterface(companies[index].id , companies[index].name , companies[index].companyLogo),
);
}),
),
),
);
}else{......rest of code
Add a StreamController:
StreamController<List<Companies>> dataController;
Initialize it in your initState:
dataController = StreamController();
Move fetchCompanies inside your widget and before returning the result add it to your stream:
var result = parseCompanies(response.body);
dataController.add(result);
Use a StreamBuilder instead of FutureBuilder:
StreamBuilder<List<Companies>>(
stream: dataController.stream,
builder: (context, snapshot) {
...
}
)

type 'Future<dynamic>' is not a subtype of type 'List<Profile>

class Profile {
final List<String> photos;
final String name;
final int age;
final String education;
final String bio;
final int distance;
Profile({
this.photos,
this.name,
this.age,
this.education,
this.bio,
this.distance
});
}
class _MainControllerState extends State<MainController> {
static List<Profile> demoProfiles = fetchData();
static fetchData() async{
final db = await Firestore.instance;
List<Profile> list = [];
db.collection("users").getDocuments().then((querySnapshot){
querySnapshot.documents.forEach((document) {
list.add(Profile(
photos: document['photoUrl'],
name: document['photoUrl'],
age: document['photoUrl'],
distance: document['photoUrl'],
education: document['photoUrl']
));
});
});
return list;
}
final MatchEngine matchEngine = MatchEngine (
matches:demoProfiles.map((Profile profile) => Match(profile:
profile)).toList()
);
I am new to flutter.
when I run my code , I got the error :type 'Future' is not a subtype of type 'List .and if I change screen I will get the error:NoSuchMethodError: The method 'map' was called on null. How can I solve it ?
Thank you for helping me .
You need to specify the return type of method fetchData
static Future<List<Profile>> fetchData() async{
You need to convert you method to getData
Future<List<Data>> getData() async {
var response =
await http.get(Uri.https('jsonplaceholder.typicode.com', 'users'));
var jsonData = jsonDecode(response.body);
List<Data> dataList = [];
for (var u in jsonData) {
Data data = Data(u["name"], u["phone"], u["email"]);
dataList.add(data);
}
print(dataList.length);
return dataList;
}
And display in a Card
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Data Fetch"),
),
body: Container(
child: Card(
child: FutureBuilder<List<Data>>(
future: getData(),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
}else{
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, i) {
return ListTile(
title: Column(
children: [
Text(snapshot.data![i].name),
Text(snapshot.data![i].phone),
Text(snapshot.data![i].email),
],
),
);
});
}
},
),
),
));
}
Its worked for me :) :) I hope this will help you.

Invalid value: Only valid value is 0: 1 in Flutter

I create an UI with FutureBuilder to show an nested object from my rest api, but i don't know why, but after run my function(in my UI) my console throw me this type of error:
RangeError (index): Invalid value: Only valid value is 0: 1
I try flutter doctor but it not help me,
ps. I can't use itemCount: snapshot.data.length because
Class 'User' has no instance getter 'length'
my code:
#override
void initState(){
super.initState();
userApiService = UserApiService();
_future = getUserData();
}
getUserData() async{
sharedPreferences = await SharedPreferences.getInstance();
int id = sharedPreferences.getInt('id');
return userApiService.getUser(id);
}
#override
Widget build(BuildContext context){
return FutureBuilder(
future: _future,
builder: (context, snapshot){
if(!snapshot.hasData){
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
// User user = snapshot.data;
return Scaffold(
backgroundColor: Colors.white,
body: Container(
child: ListView.builder(
itemBuilder: (context, i){
User user = snapshot.data;
return GestureDetector(
onTap: () {
//
},
child: Container(
width: 300,
height: 80,
color: Colors.blue,
child: Text(user.myFollows[i].firstName + ' ' + user.myFollows[i].lastName),
),
);
}
)
),
);
},
);
}
model User:
class User {
List<Observations> followedBy;
List<Observations> myFollows;
int id;
String firstName;
String lastName;
User(
{
this.followedBy,
this.myFollows,
this.id,
this.firstName,
this.lastName,
});
factory User.fromJson(Map<String, dynamic> json){
return User(
id: json['id'],
firstName: json['firstName'],
lastName: json['lastName'],
followedBy: parseFollowedBy(json),
myFollows: parseMyFollows(json),
);
}
static List<Observations> parseFollowedBy(json){
var lista = json['followedBy'] as List;
List<Observations> followedByList = lista.map((data) => Observations.fromJson(data)).toList();
return followedByList;
}
static List<Observations> parseMyFollows(myFollowsJson){
var list = myFollowsJson['myFollows'] as List;
List<Observations> myFollowsList = list.map((data) => Observations.fromJson(data)).toList();
return myFollowsList;
}
}
List<User> usersFromJson(String jsonData){
final data = json.decode(jsonData);
return List<User>.from(data.map((item) => User.fromJson(item)));
}
User userFromJson(String jsonData){
final data = json.decode(jsonData);
return User.fromJson(data);
}
String userToJson(User data){
final jsonData = data.toJson();
return json.encode(jsonData);
}
model observations.dart:
class Observations {
final int id;
final String firstName;
final String lastName;
Observations({this.id, this.firstName, this.lastName});
factory Observations.fromJson(Map<String, dynamic> parsedJson) {
return Observations(
id: parsedJson['id'],
firstName: parsedJson['firstName'],
lastName: parsedJson['lastName'],
);
}
}
thanks for any help :)
In this case you have to set itemCount to the lenght of the list you are traversing in the ListView.
I see you are using user.myFollows[i]
So maybe you should use:
itemCount: user.myFollows.length,