snapshot.hasData is true but the snapshot.data.length is null, Flutter - json

I'm calling an API from a component that returns some data, but the problem is snapshot.hasData is true but the snapshot.data.length is 0. Am I parsing the data wrong(again)? The code:
API call service component:
Future<List<User>> getUsers() async {
final response = await APIRequest(Method.GET, '/users');
if (response.statusCode == 200) {
var body = jsonDecode(response.body)['data'];
print('this is the response body: ' + response.body); // it returns data completely
List<User> users = [];
body.map((e) {
User user = User.fromJson(e);
users.add(user);
});
return users;
} else {
print('Error occurred! Data is not fetched!');
}
}
The user list component:
Future<List<User>> _getUserList() async {
var _userData = await APIcalls.instance.getUsers();
return _userData;
}
FutureBuilder<List<User>>(
future: _getUserList(),
builder: (context, snapshot) {
if (snapshot.hasData) {
print(snapshot.hasData.toString()); // returns true
print(snapshot.data.length); // returns 0
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
print(snapshot.data.length);
return Text(snapshot.data[index].userId);
},
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return Container();
},
)

Try this:
List<User> users = List.from(body).map((e) => User.fromJson(Map.from(e))).toList();
return users;

Related

Futubuilder snapshot.hasData returning false

I wrote code to fetch data and put them to GridView Buider.
But condition snapshot.hasData not working, its always False and return CircularProgressIndicator().
But If I change condition to !snapshot.hasData(true) my code is working, and fetch data shows on the screen correctly.
Fetch API
List<String> pcBusy = [];
Future fetchDataStandart() async {
final urlAuth =
Uri.parse('http://xxx.xx.xxx.xxx/api/usersessions/activeinfo');
final response = await http
.get(urlAuth, headers: <String, String>{'authorization': basicAuth});
if (response.statusCode == 200) {
List listPc = List.from(json.decode(response.body)['result']);
pcBusy.clear();
for (int i = 0; i < listPc.length; i++) {
pcBusy.add(listPc[i]['hostName']);
}
print(pcBusy);
} else {
throw Exception('Error');
}
Builder code
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
'ЕВРОКО Стандарт',
),
),
body: FutureBuilder(
future: fetchDataStandart(),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ComputerGrid();
} else {
return Center(
child: CircularProgressIndicator(),
);
}
Your fetchDataStandart() function does not have any return statement. Therefore calling it will not give you any data. You need to add a return statement. I do not know if you have just not shared the complete function, because one closing bracket is missing at the end.

Flutter - How to parse JSON data?

I want to parse my JSON data and display all the nodeValues of the rows and not just [7] (which contains the word hello), however my FutureBuilder doesn't display the JSON data (stuck on CircularProgressIndicator) even though i'm following the correct JSON path.
//Updated code
class Feed {
String title;
Feed({this.title});
factory Feed.fromJson(Map<String, dynamic> json) {
return Feed(
title: json["data"]["tables"][0]["rows"][7]["cols"][1]["nodeValue"]);
}
}
//I am making a post method to an API that returns me a JSON output.
Future<List<Feed>> post() async {
final Response<String> result =
await Dio().get('https://example.com');
String _baseUrl = "https://html2json.com/api/v1";
var options = Options(
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
followRedirects: false,
);
final response = json.decode(result.data);
final responseJson = await Dio().post(
_baseUrl,
data: response,
options: options,
);
if (responseJson.statusCode == 200) {
return (response as List).map((json) => Feed.fromJson(json)).toList();
} else {
return null;
}
}
//This is stuck on CircularProgressIndicator();
FutureBuilder(
future: post(),
builder: (context, AsyncSnapshot<List<Feed>> snap) {
if (snap.hasData) {
return ListView.builder(
itemCount: snap.data.length,
itemBuilder: (BuildContext context, int index) {
return Text(snap.data[index].title);
});
} else {
return CircularProgressIndicator();
}
});
I changed a few things to make your code work with the json place holder. You were using response.statusCode == 200, but response has no status code, the status code is on the var link.
class Feed {
String title;
Feed({this.title});
factory Feed.fromJson(Map<String, dynamic> json) {
return Feed(title: json["title"]);
}
}
Future<List> post() async {
final Response<String> result = await Dio().get('https://jsonplaceholder.typicode.com/todos');
final response = json.decode(result.data);
if (result.statusCode == 200) {
return (response as List)
.map((json) => Feed.fromJson(json))
.toList();
} else {
return null;
}
}
return FutureBuilder(
future: post(),
builder: (context, AsyncSnapshot<List> snap) {
if (snap.hasData) {
return ListView.builder(
itemCount: snap.data.length,
itemBuilder: (BuildContext context, int index) {
return Text(snap.data[index].title);
});
} else {
return CircularProgressIndicator();
}
});

Flutter Dart http Type Response is not a subtype of type String error

I'm trying to display pictures I get from a http request but i get this error "Type Response is not a subtype of type String". First i get the recently added albums list then i take the cover art id and put that into the url and send that request to the api. The api sends back an image.
Page:
class RecentlyAddedAlbums extends StatefulWidget {
#override
_RecentlyAddedAlbumsState createState() => _RecentlyAddedAlbumsState();
}
class _RecentlyAddedAlbumsState extends State<RecentlyAddedAlbums> {
Future<List<Album>> albums;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: FutureBuilder(
future: fetchRecentlyAddedAlbums(),
builder: (context, AsyncSnapshot<List<Album>> data) {
switch (data.connectionState) {
case ConnectionState.none:
return Text(
"none",
style: TextStyle(color: Colors.black),
);
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.black),
));
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (data.hasData) {
List<Album> albums = data.data;
return ListView.builder(
itemCount: albums.length,
itemBuilder: (context, index) {
return FutureBuilder(
future: recentAlbumArt(albums[index].coverArt),
builder: (context, AsyncSnapshot data) {
switch (data.connectionState) {
case ConnectionState.none:
return Text(
"none",
style: TextStyle(color: Colors.black),
);
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
Colors.black),
));
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (data.hasData) {
return Image.network(data.data);
/* return GridView.count(
padding: const EdgeInsets.all(20),
crossAxisCount: 2,
children: <Widget>[
ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(
title: Image.network(
(data.data)[index]),
);
})
],
); */
}
}
});
},
);
}
}
}),
),
);
}
}
Recently added function:
Future<List<Album>> fetchRecentlyAddedAlbums() async {
try {
var salt = randomToken(6);
var token = makeToken("$password", "$salt");
var uRL =
"$server/rest/getAlbumList?u=$username&t=$token&s=$salt&v=$tapeOutVerison&c=$client$format&type=newest";
var authresponse = await http.get(uRL);
if (authresponse.statusCode == 200) {
var jsondata = jsonDecode(authresponse.body);
var data = apicallFromJson(jsondata);
var aresponse = data.subsonicResponse.albumList.album;
return aresponse;
} else {
return null;
}
} catch (e) {
return null;
}
}
Cover Art Function
Future recentAlbumArt(String coverArtID) async {
try {
var salt = randomToken(6);
var token = makeToken("$password", "$salt");
var uRL =
"$server/rest/getCoverArt/?u=$username&t=$token&s=$salt&v=$tapeOutVerison&c=$client$format&id=$coverArtID";
return await http.get(uRL);
} catch (e) {
print(e);
}
}
Album class:
class Album {
Album({
this.id,
this.parent,
this.isDir,
this.title,
this.album,
this.artist,
this.genre,
this.coverArt,
this.playCount,
this.created,
this.year,
});
String id;
String parent;
bool isDir;
String title;
String album;
String artist;
String genre;
String coverArt;
int playCount;
DateTime created;
int year;
This function returns a http reponse:
return await http.get(uRL);
If you wish to get the content of the response, you need to get the body like so:
var response = await http.get(uRL);
return response.body;

Flutter Futurebuilder snapshot is null

I try to show the results from JSON in a ListView in Flutter with a FutureBuilder.
But the snapshot is null and the message that no data is available shows.
Here I try to fetch the data:
static Future _getBans() async {
Storage.getLoggedToken().then((token) async {
var body = {
"token": token
};
final response = await http.post('${URLS.BASE_URL}/punishments.php', headers: ApiService.header, body: json.encode(body));
if (response.statusCode == 200) {
List<Ban> bans = [];
var jsonData = json.decode(response.body)["bans"];
for(var b in jsonData){
Ban ban = Ban(b["player"], b["reason"], int.parse(b["end"]), b["by"]);
bans.add(ban);
}
print(response.body);
print(bans.length);
return bans;
} else {
return null;
}
});
}
from this JSON response
{"status":1,"msg":"OK","bans":[{"player":"DDOSAttacke","reason":"Hacking","end":"1579275471304","by":"DDOSAttacke"}],"mutes":[]}
My Futurebuilder. Here is snapshot null but the count of the elements is working.
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Aktive Bans'),
),
body: Container(
child: FutureBuilder(
future: _getBans(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(
child: Text('Keine aktiven Ban vorhanden')
),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(snapshot.data[index].player),
);
},
);
}
},
),
),
);
}
Please try this. I think you'll have to use await keyword for the getLoggedToken mothod, the returnwill wait for the post before returning anything. But now you're returning before the getLoggedTokenfinishes his work. That is why you are always receiving null.
static Future _getBans() async {
var token = await Storage.getLoggedToken();
var body = {
"token": token
};
final response = await http.post('${URLS.BASE_URL}/punishments.php', headers: ApiService.header, body: json.encode(body));
if (response.statusCode == 200) {
List<Ban> bans = [];
var jsonData = json.decode(response.body)["bans"];
for(var b in jsonData){
Ban ban = Ban(b["player"], b["reason"], int.parse(b["end"]), b["by"]);
bans.add(ban);
}
print(response.body);
print(bans.length);
return bans;
} else {
return null;
}
}

Flutter snapshot data is empty

I'm new in flutter, I try parse data from rest api.
Api return:
http://www.json-generator.com/api/json/get/cqwVqdOFrC?indent=2
Eg. Here get data from json api eg. length is 3231
class ApiService {
static Future<dynamic> _get(String url) async {
try {
final response = await http.get(url);
var jsonData = json.decode(response.body);
if (response.statusCode == 200) {
print(response.body.length); //3231
return jsonData;
} else {
return null;
}
}
}
but here is snapshot.hasData = False, Why?
return Scaffold(
appBar: AppBar(title: Text('Posts'),),
body: FutureBuilder(
future: ApiService.getUserList(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
print(snapshot.hasData.toString()); //False no data
static Future<List<dynamic>> getUserList() async {
return await _get('${Urls.BASE_API_URL}');
}
Without items at the beginning of json all work fine. My web server return items at the beginning. Any solutions?
api returns Map<String, dynamic> not <List<dynamic>>
class ListaAbitudini extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new _ListaAbitudiniState();
}
}
class _ListaAbitudiniState extends State<ListaAbitudini> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Posts'),
),
body: FutureBuilder(
future: ApiService.getUserList(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.hasData)
print("True");
return Container();
}));
}
}
class ApiService {
static Future<Map<String, dynamic>> getUserList() async {
return await _get('http://www.json-generator.com/api/json/get/cqwVqdOFrC?indent=2');
}
static Future<dynamic> _get(String url) async {
try {
final response = await http.get(url);
var jsonData = json.decode(response.body);
if (response.statusCode == 200) {
print(response.body.length); //3231
return jsonData;
} else {
return null;
}
} catch (e) {
print(e);
}
}
}
Have to try calling,
future: ApiService.getUserList().then((onValue) {
return onValue;
}
Usually you get hasData = false when hasError = true. Try to look for a snapahot error (snapshot.error)