i tried to decode my json and take the values to futurebuilder in flutter when decode my json appear formatexception:unexpectedcharacter,tried to storage in a String and in List, think my error think is how to toke data,how to storage my json decode,
Thanks
my code
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:oauth2_client/spotify_oauth2_client.dart';
import 'package:ui/Models/segundapantalla.dart';
import 'newmodel.dart';
class callttoappi {
Future getatatodapi() async {
String url =
'https://api.spotify.com/v1/playlists/37i9dQZF1DXcBWIGoYBM5M/tracks';
var client = SpotifyOAuth2Client(
redirectUri: 'com.example.ui://callback',
customUriScheme: 'com.example.ui');
var tknResp = await client.getTokenWithAuthCodeFlow(
clientId: 'client id',
scopes: [
'user-read-email',
'user-read-private',
]);
if (tknResp != null) {
var headers = {
'Authorization': 'Bearer ${tknResp.accessToken}',
};
var request = await http.Request(
'GET', Uri.parse('https://api.spotify.com/v1/browse/new-releases'));
request.headers.addAll(headers);
http.StreamedResponse response =
await request.send().timeout(const Duration(seconds: 20));
if (response.statusCode == 200) {
//String reponsedata = await response.stream.bytesToString();
//print(await response.stream.bytesToString());
Map<String, dynamic> userMap = jsonDecode(await response.stream.bytesToString());
var user = Item.fromJson(userMap);
print(userMap);
//Map<String,dynamic> json = jsonDecode(await response.stream.bytesToString());
//print(json);
return Item.fromJson(jsonDecode(json.toString()));
} else {
print(response.reasonPhrase);
}
}
}
}
my model class,quicktype website or another page this like github projects to obtain my json
class Newmodel {
Newmodel({
required this.albums,
});
final Albums? albums;
factory Newmodel.fromJson(Map<String, dynamic> json){
return Newmodel(
albums: json["albums"] == null ? null : Albums.fromJson(json["albums"]),
);
}
Map<String, dynamic> toJson() => {
"albums": albums?.toJson(),
};
#override
String toString(){
return '$albums';
}
}
class Albums {
Albums({
required this.href,
required this.items,
required this.limit,
required this.next,
required this.offset,
required this.previous,
required this.total,
});
final String? href;
final List<Item> items;
final int? limit;
final String? next;
final int? offset;
final dynamic previous;
final int? total;
factory Albums.fromJson(Map<String, dynamic> json){
return Albums(
href: json["href"],
items: json["items"] == null ? [] : List<Item>.from(json["items"]!.map((x) => Item.fromJson(x))),
limit: json["limit"],
next: json["next"],
offset: json["offset"],
previous: json["previous"],
total: json["total"],
);
}
Map<String, dynamic> toJson() => {
"href": href,
"items": List<Item>.from(items.map((x) => x.toJson())),
"limit": limit,
"next": next,
"offset": offset,
"previous": previous,
"total": total,
};
#override
String toString(){
return '$href, $items, $limit, $next, $offset, $previous, $total';
}
}
class Item {
Item({
required this.albumType,
required this.artists,
required this.availableMarkets,
required this.externalUrls,
required this.href,
required this.id,
required this.images,
required this.name,
required this.releaseDate,
required this.releaseDatePrecision,
required this.totalTracks,
required this.type,
required this.uri,
});
final String? albumType;
final List<Artist> artists;
final List<String> availableMarkets;
final ExternalUrls? externalUrls;
final String? href;
final String? id;
final List<Image> images;
final String? name;
final DateTime? releaseDate;
final String? releaseDatePrecision;
final int? totalTracks;
final String? type;
final String? uri;
factory Item.fromJson(Map<String, dynamic> json){
return Item(
albumType: json["album_type"],
artists: json["artists"] == null ? [] : List<Artist>.from(json["artists"]!.map((x) => Artist.fromJson(x))),
availableMarkets: json["available_markets"] == null ? [] : List<String>.from(json["available_markets"]!.map((x) => x)),
externalUrls: json["external_urls"] == null ? null : ExternalUrls.fromJson(json["external_urls"]),
href: json["href"],
id: json["id"],
images: json["images"] == null ? [] : List<Image>.from(json["images"]!.map((x) => Image.fromJson(x))),
name: json["name"],
releaseDate: json["release_date"] == null ? null : DateTime.parse(json["release_date"]),
releaseDatePrecision: json["release_date_precision"],
totalTracks: json["total_tracks"],
type: json["type"],
uri: json["uri"],
);
}
Map<String, dynamic> toJson() => {
"album_type": albumType,
"artists": List<Artist>.from(artists.map((x) => x.toJson())),
"available_markets": List<String>.from(availableMarkets.map((x) => x)),
"external_urls": externalUrls?.toJson(),
"href": href,
"id": id,
"images": List<Image>.from(images.map((x) => x.toJson())),
"name": name,
//"release_date": "${releaseDate.year.toString().padLeft(4'0')}-${releaseDate.month.toString().padLeft(2'0')}-${releaseDate.day.toString().padLeft(2'0')}",
"release_date_precision": releaseDatePrecision,
"total_tracks": totalTracks,
"type": type,
"uri": uri,
};
#override
String toString(){
return '$albumType, $artists, $availableMarkets, $externalUrls, $href, $id, $images, $name, $releaseDate, $releaseDatePrecision, $totalTracks, $type, $uri';
}
}
viewpage class
class lodeo extends StatefulWidget {
#override
State<lodeo> createState() => _WeatherPageState();
}
class _WeatherPageState extends State<lodeo> {
Future getData() async {
return await callttoappi().getatatodapi();
}
Future<dynamic>? _myData;
#override
void initState() {
setState(() {
_myData = getData();
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
builder: (ctx, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// If error occured
if (snapshot.hasError) {
return Center(
child: Text(
'${snapshot.error.toString()} occurred',
style: TextStyle(fontSize: 18),
),
);
// if data has no errors
} else if (snapshot.hasData) {
// Extracting data from snapshot object
final data = snapshot.data as Item;
return Container(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 10),
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment(0.8, 1),
colors: <Color>[
Color.fromARGB(255, 65, 89, 224),
Color.fromARGB(255, 83, 92, 215),
Color.fromARGB(255, 86, 88, 177),
Color(0xfff39060),
Color(0xffffb56b),
],
tileMode: TileMode.mirror,
),
),
width: double.infinity,
height: double.infinity,
child: SafeArea(
child: Column(
children: [
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
data.albumType.toString(),
style: TextStyle(
fontSize: 30,
color: Colors.white,
fontWeight: FontWeight.bold),
),
Text(
data.id.toString(),
style: TextStyle(
fontSize: 20,
color: Colors.white,
fontWeight: FontWeight.bold),
),
Text(
data.name.toString(),
style: TextStyle(
fontSize: 50,
color: Colors.white,
fontWeight: FontWeight.bold),
),
],
),
),
],
),
),
);
}
} else if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return Center(
child: Text("${snapshot.connectionState} occured"),
);
}
return Center(
child: Text("Server timed out!"),
);
},
future: _myData!,
),
);
}
enter code here
Related
hey im building a application which shows some information about certain things and this one certain widget does not show any type of information and just returns a white screen, this was no problem at first since i only really tested in on my emulator (Which worked everytime) but now that i downloaded the APK it only shows a white screen. i have used
<uses-permission android:name="android.permission.INTERNET" />
in my aindroidmanifest file.
my code:
Main.dart
class AllChampionsListedRoute extends StatefulWidget {
String summonerId, summonerName;
AllChampionsListedRoute(this.summonerId, this.summonerName);
#override
State<StatefulWidget> createState() {
return _AllChampionsListedRouteState(this.summonerId, this.summonerName);
}
}
class _AllChampionsListedRouteState extends State<AllChampionsListedRoute> {
TextEditingController editingController = TextEditingController();
var items = <String>[];
List<String> allChampListUncapitalized = [];
String summonerId, summonerName;
_AllChampionsListedRouteState(this.summonerId, this.summonerName);
#override
void initState() {
super.initState();
for (var champ in allChampList) {
allChampListUncapitalized.add(champ.toLowerCase());
items.add(champ.toLowerCase());
}
}
void filterSearchResults(String query) {
List<String> dummySearchList = <String>[];
dummySearchList.addAll(allChampListUncapitalized);
if(query.isNotEmpty) {
List<String> dummyListData = <String>[];
dummySearchList.forEach((item) {
if(item.contains(query)) {
dummyListData.add(item);
}
});
setState(() {
items.clear();
items.addAll(dummyListData);
});
return;
} else {
setState(() {
items.clear();
items.addAll(allChampListUncapitalized);
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: customAppBar(),
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
bgColorFront,
bgColorEnd,
],
),
),
child: Center(
child: Expanded(
child: FutureBuilder<Champions>(
future: getChampions(), // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot<Champions> snapshotChamps) {
if (snapshotChamps.hasData) {
return Column(
children: [
TextField(
onChanged: (value) {
filterSearchResults(value);
},
inputFormatters: [
UpperCaseTextFormatter(),
],
controller: editingController,
style: TextStyle(
color: customColorGray,
fontSize: 20,
),
decoration: new InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: customColorDarkBlue, width: 2.0),
),
labelText: 'Champion',
labelStyle: TextStyle(
color: customColorTextBlue,
fontFamily: 'Spiegel',
fontSize: 20,
),
hintText: 'Fill in your champion here',
hintStyle: TextStyle(
color: customColorTextBlue,
fontFamily: 'Spiegel',
fontSize: 20,
),
),
maxLines: null,
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(
'${capitalize(items[index])}',
style: TextStyle(
fontSize: 25,
),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SummonerMasteryRoute(
snapshotChamps.data!.data["${capitalize(items[index])}"]!.key, capitalize(items[index]),
summonerId, snapshotChamps.data!.data["${capitalize(items[index])}"]!.image.full, summonerName
)),
);
},
);
},
),
)
],
);
} else if (snapshotChamps.hasError) {
return Text('Error: ${snapshotChamps.error}');
} else {
return SizedBox(
width: 60,
height: 60,
child: CircularProgressIndicator(),
);
}
},
),
)
),
),
);
}
}
Remoteservice.dart:
Future<Champions> getChampions() async {
String link = 'http://ddragon.leagueoflegends.com/cdn/12.22.1/data/en_US/champion.json';
final response = await http
.get(Uri.parse(link));
if (response.statusCode == 200) {
return Champions.fromJson(jsonDecode(response.body));
} else {
return throw Exception('Failed to load album');
}
}
champion.dart (class):
import 'dart:convert';
Champions championsFromJson(String str) => Champions.fromJson(json.decode(str));
String championsToJson(Champions data) => json.encode(data.toJson());
class Champions {
Champions({
required this.type,
required this.format,
required this.version,
required this.data,
});
Type? type;
String format;
Version? version;
Map<String, ChampData> data;
factory Champions.fromJson(Map<String, dynamic> json) => Champions(
type: typeValues.map[json["type"]],
format: json["format"],
version: versionValues.map[json["version"]],
data: Map.from(json["data"]).map((k, v) => MapEntry<String, ChampData>(k, ChampData.fromJson(v))),
);
Map<String, dynamic> toJson() => {
"type": typeValues.reverse?[type],
"format": format,
"version": versionValues.reverse?[version],
"data": Map.from(data).map((k, v) => MapEntry<String, dynamic>(k, v.toJson())),
};
}
class ChampData {
ChampData({
required this.version,
required this.id,
required this.key,
required this.name,
required this.title,
required this.blurb,
required this.info,
required this.image,
required this.tags,
required this.partype,
required this.stats,
});
Version? version;
String id;
String key;
String name;
String title;
String blurb;
Info info;
ChampImage image;
List<Tag> tags;
String partype;
Map<String, double> stats;
factory ChampData.fromJson(Map<String, dynamic> json) => ChampData(
version: versionValues.map[json["version"]],
id: json["id"],
key: json["key"],
name: json["name"],
title: json["title"],
blurb: json["blurb"],
info: Info.fromJson(json["info"]),
image: ChampImage.fromJson(json["image"]),
tags: List<Tag>.from(json["tags"].map((x) => tagValues.map[x])),
partype: json["partype"],
stats: Map.from(json["stats"]).map((k, v) => MapEntry<String, double>(k, v.toDouble())),
);
Map<String, dynamic> toJson() => {
"version": versionValues.reverse?[version],
"id": id,
"key": key,
"name": name,
"title": title,
"blurb": blurb,
"info": info.toJson(),
"image": image.toJson(),
"tags": List<dynamic>.from(tags.map((x) => tagValues.reverse?[x])),
"partype": partype,
"stats": Map.from(stats).map((k, v) => MapEntry<String, dynamic>(k, v)),
};
}
class ChampImage {
ChampImage({
required this.full,
required this.sprite,
required this.group,
required this.x,
required this.y,
required this.w,
required this.h,
});
String full;
Sprite? sprite;
Type? group;
int x;
int y;
int w;
int h;
factory ChampImage.fromJson(Map<String, dynamic> json) => ChampImage(
full: json["full"],
sprite: spriteValues.map[json["sprite"]],
group: typeValues.map[json["group"]],
x: json["x"],
y: json["y"],
w: json["w"],
h: json["h"],
);
Map<String, dynamic> toJson() => {
"full": full,
"sprite": spriteValues.reverse?[sprite],
"group": typeValues.reverse?[group],
"x": x,
"y": y,
"w": w,
"h": h,
};
}
enum Type { CHAMPION }
final typeValues = EnumValues({
"champion": Type.CHAMPION
});
enum Sprite { CHAMPION0_PNG, CHAMPION1_PNG, CHAMPION2_PNG, CHAMPION3_PNG, CHAMPION4_PNG, CHAMPION5_PNG }
final spriteValues = EnumValues({
"champion0.png": Sprite.CHAMPION0_PNG,
"champion1.png": Sprite.CHAMPION1_PNG,
"champion2.png": Sprite.CHAMPION2_PNG,
"champion3.png": Sprite.CHAMPION3_PNG,
"champion4.png": Sprite.CHAMPION4_PNG,
"champion5.png": Sprite.CHAMPION5_PNG
});
class Info {
Info({
required this.attack,
required this.defense,
required this.magic,
required this.difficulty,
});
int attack;
int defense;
int magic;
int difficulty;
factory Info.fromJson(Map<String, dynamic> json) => Info(
attack: json["attack"],
defense: json["defense"],
magic: json["magic"],
difficulty: json["difficulty"],
);
Map<String, dynamic> toJson() => {
"attack": attack,
"defense": defense,
"magic": magic,
"difficulty": difficulty,
};
}
enum Tag { FIGHTER, TANK, MAGE, ASSASSIN, MARKSMAN, SUPPORT }
final tagValues = EnumValues({
"Assassin": Tag.ASSASSIN,
"Fighter": Tag.FIGHTER,
"Mage": Tag.MAGE,
"Marksman": Tag.MARKSMAN,
"Support": Tag.SUPPORT,
"Tank": Tag.TANK
});
enum Version { THE_12221 }
final versionValues = EnumValues({
"12.22.1": Version.THE_12221
});
class EnumValues<T> {
Map<String, T> map;
Map<T, String>? reverseMap;
EnumValues(this.map);
Map<T, String>? get reverse {
if (reverseMap == null) {
reverseMap = map.map((k, v) => new MapEntry(v, k));
}
return reverseMap;
}
}
This is how it was supposed to look (and how it looks on my emulator):
I created project to look for sports stadiums in my town. It gets all data from website's Swagger API, data like addresses, price, images and names.
Swagger host: http://admin.sports.com.kg/swagger/
I created ApiRemote to get data from swagger host. It worked perfectly first week, but later it returned exception. Maybe it's because of http.
Terminal returns this error:
E/flutter (26867): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: Failed host lookup: 'admin.sports.com.kg'
It says it has an exception in this line:
var responses = await client.get(uri);
import 'dart:async';
import 'dart:convert';
import 'package:untitled/models/post.dart';
import 'package:http/http.dart' as http;
class RemoteService {
Future<List<Result>?> getPosts() async {
List<Result> list;
var client = http.Client();
var uri = Uri.parse('http://admin.sports.com.kg/api/sports_areas');
var responses = await client.get(uri);
if (responses.statusCode == 200) {
final parsed = json.decode(responses.body) as Map<String, dynamic>;
list = parsed['results'].map<Result>((e) =>Result.fromJson(e)).toList();
print(parsed['results']);
// final p = Post.fromJson(parsed);
// list.add(p);
return list;
}
}
}
Post file that contains all data from Swagger
import 'dart:convert';
Post postFromJson(String str) => Post.fromJson(json.decode(str));
String postToJson(Post data) => json.encode(data.toJson());
class Post {
Post({
required this.next,
this.previous,
required this.count,
required this.pageSize,
required this.numPages,
required this.results,
});
int next;
dynamic previous;
int count;
int pageSize;
int numPages;
List<Result> results;
factory Post.fromJson(Map<String, dynamic> json) => Post(
next: json["next"],
previous: json["previous"],
count: json["count"],
pageSize: json["page_size"],
numPages: json["num_pages"],
results:
List<Result>.from(json["results"].map((x) => Result.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"next": next,
"previous": previous,
"count": count,
"page_size": pageSize,
"num_pages": numPages,
"results": List<dynamic>.from(results.map((x) => x.toJson())),
};
}
class Result {
Result({
required this.id,
required this.title,
required this.price,
required this.address,
required this.image,
});
int id;
String title;
int price;
String address;
String image;
factory Result.fromJson(Map<String, dynamic> json) => Result(
id: json["id"],
title: json["title"],
price: json["price"],
address: json["address"],
image: json["image"],
);
Map<String, dynamic> toJson() => {
"id": id,
"title": title,
"price": price,
"address": address,
"image": image,
};
}
Main Page class
class _HomePageState extends State<HomePage> {
int _selind = 0;
List<Result>? _stadiums;
var isLoaded = false;
#override
void initState() {
super.initState();
getData();
}
void getData() async {
_stadiums = (await RemoteService().getPosts()) as List<Result>?;
if (_stadiums != null) {
setState(() {
isLoaded = true;
});
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.indigo[50],
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 30),
child: Visibility(
visible: isLoaded,
child: ListView.builder(
itemCount: _stadiums?.length,
itemBuilder: (context, index) {
return Column(
// child: _widgetopt.elementAt(_selind),
children: [
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Column(
children: [
Image.network(_stadiums![index].image),
Text('Sportclubs "${_stadiums![index]
.title}"', textDirection: TextDirection.ltr,
style: TextStyle(fontSize: 20,
fontWeight: FontWeight.bold),),
Row(
children: [
Icon(Icons.location_on_outlined,
color: Colors.redAccent, size: 40,),
Text(_stadiums![index].address),
],
)
]
),
),
SizedBox(
height: 10,
),
],
);
}),
replacement: Center(child: CircularProgressIndicator()),
),
),),);
}
}
I'm trying to display a list from api with GET request. But it keeps showing this error:
NoSuchMethodError: The method '[]' was called on null.
Receiver: null
Tried calling: []("depId")
The thing is I don't use depId at all for this request and it's not even in the object that I'm using to make this request so I don't know from where it gets null value because when I use it in my previous request it works totally fine.
Here is the API request
static Future<List<Athlete>> getAthletesByTeamKey(
int depId, int teamId) async {
try {
final response = await http.get(
Uri.parse(
'$uri/get-athletes-by-team-key?depId=$depId&teamId=$teamId&page=0&length=50'),
headers: {
'Authorization': 'Basic ...',
'Content-Type': 'application/json',
'Accept': 'application/json'
});
print('Response status: ${response.statusCode}');
print('Response body: ${response.body}');
if (response.statusCode == 200) {
if (response.body.isNotEmpty) {
print('response.body.isNotEmpty');
List jsonResponse = json.decode(utf8.decode(response.bodyBytes));
return jsonResponse
.map((athlete) => Athlete.fromJson(athlete))
.toList();
} else if (response.body.isEmpty) {
print('response.body.isEmpty');
throw Exception();
}
}
} catch (e) {
print('catch');
logger.e(e.toString());
}
return getAthletesByTeamKey(depId, teamId, context);
}
It prints the print('response.body.isNotEmpty');and then it goes into catch
My Athlete object
List<Athlete> athleteFromJson(String str) =>
List<Athlete>.from(json.decode(str).map((x) => Athlete.fromJson(x)));
String athleteToJson(List<Athlete> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Athlete {
late int id;
late String firstName;
late String lastName;
late String fatherName;
late int currentMonthPresences;
late bool isSelected = false;
late bool hasDebt;
Department? department;
Team? team;
Athlete(
{required this.id,
required this.firstName,
required this.lastName,
required this.fatherName,
required this.currentMonthPresences,
this.isSelected = false,
required this.hasDebt,
this.department,
this.team});
Athlete.newSelectedAthlete(this.id, this.department, this.team); //I use it for another screen
factory Athlete.fromJson(Map<String, dynamic> json) => Athlete(
id: json['id'],
firstName: json['firstName'],
lastName: json['lastName'],
fatherName: json['fatherName'],
currentMonthPresences: json['currentMonthPresences'],
hasDebt: json['hasDebt'],
department: Department.fromJson(json['department']),
team: Team.fromJson(json['team']),
);
Map<String, dynamic> toJson() => {
'id': id,
'firstName': firstName,
'lastName': lastName,
'fatherName': fatherName,
'currentMonthPresences': currentMonthPresences,
'isSelected': isSelected,
'hasDebt': hasDebt,
'department': department,
'team': team,
};
}
Department object
class Department {
int id;
String depName;
Department({required this.id, required this.depName});
factory Department.fromJson(Map<String, dynamic> json) => Department(
id: json['id'],
depName: json['depName'],
);
Map<String, dynamic> toJson() => {
"id": id,
"depName": depName,
};
}
Team object
class Team {
final TeamKey teamKey;
final String teamName;
final int hidden;
final User user;
final String depName;
Team(
{required this.teamKey,
required this.teamName,
required this.hidden,
required this.user,
required this.depName});
factory Team.fromJson(Map<String, dynamic> json) => Team(
teamKey: TeamKey.fromJson(json['teamKey']),
teamName: json['teamName'],
hidden: json['hidden'],
user: User.fromJson(json['user']),
depName: json['depName'],
);
Map<String, dynamic> toJson() => {
'teamKey': teamKey,
'teamName': teamName,
'hidden': hidden,
'user': user,
'depName': depName,
};
}
and the TeamKey object that has the variable depId but I don't use it at all
class TeamKey {
int depId;
int teamId;
TeamKey({required this.depId, required this.teamId});
factory TeamKey.fromJson(Map<String, dynamic> json) => TeamKey(
depId: json['depId'],
teamId: json['teamId'],
);
Map<String, dynamic> toJson() => {
"depId": depId,
"teamId": teamId,
};
}
The screen I'm trying to display my list
class AthleteScreen extends StatefulWidget {
const AthleteScreen(this._team, {Key? key}) : super(key: key);
final Team _team;
#override
State<AthleteScreen> createState() => _AthleteScreenState();
}
class _AthleteScreenState extends State<AthleteScreen> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final myController = TextEditingController();
final controller = TextEditingController();
Future<List<Athlete>>? futureAthletebyTeamKey;
Future<List<Presence>>? futureGetPresences;
final List<Athlete> _athlete = [];
#override
void initState() {
futureAthletebyTeamKey = ApiService.getAthletesByTeamKey();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: Stack(
children: [
SingleChildScrollView(
child: Column(children: [
const SizedBox(
height: 10,
),
FutureBuilder<List<Athlete>>(
future: futureAthletebyTeamKey,
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
List<Athlete> _athlete = snapshot.data;
return ListView.builder(
shrinkWrap: true,
cacheExtent: 34,
primary: true,
physics: const ClampingScrollPhysics(),
padding: const EdgeInsets.only(
top: 10,
bottom: 56,
),
itemCount: _athlete.length,
itemBuilder: (BuildContext context, int i) {
return CheckboxListTile(
title: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'ID: ${_athlete[i].id}',
style: const TextStyle(
color: Colors.blue, fontSize: 14),
),
const SizedBox(
width: 5,
),
],
),
Row(
children: [
Flexible(
child: Text(
'${_athlete[i].lastName} ${_athlete[i].firstName}',
style: const TextStyle(
color: Colors.black,
fontFamily: 'Cera',
fontWeight: FontWeight.bold,
fontSize: 18),
),
),
],
),
const SizedBox(
height: 5,
),
});
} else if (snapshot.hasError) {
logger.e('${snapshot.error}');
}
return const Center(
heightFactor: 20,
child: CircularProgressIndicator.adaptive(),
);
},
),
]),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
width: double.infinity,
height: 60,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
disabledBackgroundColor: Colors.grey),
onPressed: () async {
Navigator.of(context).pushNamed(
SelectedAthletes.routeName,
arguments: selectedAthlete.toList());
}),
child: Column(
children: [
const Text(
'ΝΕΧΤ',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 18),
),
],
),
),
),
),
],
),
);
}
}
I'll be very thankful if someone took time to help me! Thanks in advance!
You actually use depId.
So let's follow along with your JSON.
When you decode the athlete you do:
factory Athlete.fromJson(Map<String, dynamic> json) => Athlete(
...
department: Department.fromJson(json['department']),
team: Team.fromJson(json['team']),
);
So the Athlete.fromJson() is calling Team.fromJson(). Let's look at it
factory Team.fromJson(Map<String, dynamic> json) => Team(
teamKey: TeamKey.fromJson(json['teamKey']),
...
);
Team.fromJson() iscalling TeamKey.fromJson(). Let's look at that.
factory TeamKey.fromJson(Map<String, dynamic> json) => TeamKey(
depId: json['depId'],
teamId: json['teamId'],
);
TeamKey.fromJson() wants the 'depId'.
Your JSON should look like:
team: {
teamKey: {
depId: ...
}
}
Double check your JSON to make sure your structure is good. Your code will actually decode along with Athlete his Team and TeamKey where you access 'depId'.
You should either remove the teamKey, or resolve it by following along the path of the original JSON you are trying to parse and see if your structure is in align with it.
Hi need help to show my API data into Text.
I already get the response but I don't know how to turn it into text which it will show at the screen.. now the data are shows at the terminal.
This is my codes:
class carList extends StatefulWidget {
const carList({Key? key}) : super(key: key);
#override
State<carList> createState() => _carListState();
}
class _carListState extends State<carList> {
var userController = TextEditingController();
var apiController = TextEditingController();
final pref = Pref();
#override
void initState() {
MySharedPreferences().getUserId().then((value) {
setState(() {
userController.text = value.toString();
});
});
MySharedPreferences().getUserToken().then((value) {
setState(() {
apiController.text = value.toString();
});
});
//TODO: IMPLEMENT INITSTATE
}
this is where I want to show my API data
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: <Widget>[
Container(
padding: const EdgeInsets.all(10),
child: TextField(
controller: userController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
suffixIcon: Icon(Icons.email),
labelText: 'User ID',
),
),
),
Container(
padding: const EdgeInsets.all(10),
child: TextField(
controller: apiController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
suffixIcon: Icon(Icons.email),
labelText: 'Token',
),
),
),
Container(
margin: EdgeInsets.all(25),
child: TextButton(
child: Text('Show Car List',
style: TextStyle(fontSize: 20.0,
color: Colors.blueAccent,
backgroundColor: Colors.white),
),
onPressed: () {
list();
},
),
)
]
)
);
}
this is my API response
void list() async {
{
var response = await http.post(
Uri.parse("http://servisjer.me-tech.com.my/api/Car/GetUserCar"),
body: ({
'user_id': userController.text,
'token': apiController.text,
'device': "Android",
}));
if (response.statusCode == 200) {
final body = jsonDecode(response.body);
print(apiController.text);
print(body.toString());
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Successfully Login")));
}
}
}
}
This page that I want to show my data.
this is my log response
{
"Status": "OK",
"Message": "Senarai maklumat kereta.",
"Details": [
{
"car_id": 184,
"user_id": 141,
"manufacturer_id": 21,
"name": "Akma",
"registration_no": "ws 3345",
"model_name": "Bezza",
"production_year": 2022,
"notes": null,
"date_purchased": "2022-08-10",
"image":
" http://servisjer.me-tech.com.my/admin/storage/app/media/userplugin/7PyVIp8iwb.png"
}
]
}
Best way to use API response data is to create model from https://app.quicktype.io/ (copy your response and paste on this link and select language dart) and use as per your requirement.
I create model with name "GetUserCarModel" from your API response and use like this way.
Future<void> list() async {
{
var response = await http.post(
Uri.parse("http://servisjer.me-tech.com.my/api/Car/GetUserCar"),
body: ({
'user_id': userController.text,
'token': apiController.text,
'device': "Android",
})
);
if (response.statusCode == 200) {
final body = jsonDecode(response.body);
GetUserCarModel getUserCarModel = GetUserCarModel.fromJson(body);
print("getUserCarModel ===> ${getUserCarModel.toString()}");
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Successfully Login")));
}
}
}
First of all you have to crate a model class of your response.
import 'dart:convert';
CarDetailResponse carDetailResponseFromJson(String str) => CarDetailResponse.fromJson(json.decode(str));
String carDetailResponseToJson(CarDetailResponse data) => json.encode(data.toJson());
class CarDetailResponse {
CarDetailResponse({
this.status,
this.message,
this.details,
});
String? status;
String? message;
List<Detail>? details;
factory CarDetailResponse.fromJson(Map<String, dynamic> json) => CarDetailResponse(
status: json["Status"],
message: json["Message"],
details: List<Detail>.from(json["Details"].map((x) => Detail.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"Status": status,
"Message": message,
"Details": List<dynamic>.from(details!.map((x) => x.toJson())),
};
}
class Detail {
Detail({
this.carId,
this.userId,
this.manufacturerId,
this.name,
this.registrationNo,
this.modelName,
this.productionYear,
this.notes,
this.datePurchased,
this.image,
});
int? carId;
int? userId;
int? manufacturerId;
String? name;
String? registrationNo;
String? modelName;
int? productionYear;
dynamic notes;
DateTime? datePurchased;
String? image;
factory Detail.fromJson(Map<String, dynamic> json) => Detail(
carId: json["car_id"],
userId: json["user_id"],
manufacturerId: json["manufacturer_id"],
name: json["name"],
registrationNo: json["registration_no"],
modelName: json["model_name"],
productionYear: json["production_year"],
notes: json["notes"],
datePurchased: DateTime.parse(json["date_purchased"]),
image: json["image"],
);
Map<String, dynamic> toJson() => {
"car_id": carId,
"user_id": userId,
"manufacturer_id": manufacturerId,
"name": name,
"registration_no": registrationNo,
"model_name": modelName,
"production_year": productionYear,
"notes": notes,
"date_purchased": "${datePurchased!.year.toString().padLeft(4, '0')}-${datePurchased!.month.toString().padLeft(2, '0')}-${datePurchased!.day.toString().padLeft(2, '0')}",
"image": image,
};
}
you can make this model class with the help of app.quicktype.io
then after getting response, assign the response.body to this model class object
void list() async {
{
var response = await http.post(
Uri.parse("http://servisjer.me-tech.com.my/api/Car/GetUserCar"),
body: ({
'user_id': userController.text,
'token': apiController.text,
'device': "Android",
}));
if (response.statusCode == 200) {
final body = jsonDecode(response.body);
setState(() {
carDetailResponse =
carDetailResponseFromJson(body);
});
print(apiController.text);
print(body.toString());
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Successfully Login")));
}
}
}
}
then at UI use this model class to show data. Like -
class CarDetailScreen extends StatefulWidget {
const CarDetailScreen({Key? key}) : super(key: key);
#override
State<CarDetailScreen> createState() => _CarDetailScreenState();
}
class _CarDetailScreenState extends State<CarDetailScreen> {
CarDetailResponse? carDetailResponse;
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(children: <Widget>[
Container(
padding: const EdgeInsets.all(10),
child: TextField(
controller: userController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
suffixIcon: Icon(Icons.email),
labelText: 'User ID',
),
),
),
Container(
padding: const EdgeInsets.all(10),
child: TextField(
controller: apiController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
suffixIcon: Icon(Icons.email),
labelText: 'Token',
),
),
),
Container(
margin: EdgeInsets.all(25),
child: TextButton(
child: Text(
'Show Car List',
style: TextStyle(fontSize: 20.0, color: Colors.blueAccent, backgroundColor: Colors.white),
),
onPressed: () {
list();
},
),
),
carDetailResponse != null
? Expanded(
child: ListView.builder(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
itemCount: carDetailResponse!.details!.length,
itemBuilder: (context, index) {
var car = carDetailResponse!.details![index];
return Text(car.name ?? '');
},
),
)
: const SizedBox()
]));
}
}
assuming this is valid response :
{
"Status":"OK",
"Message":"Sena.",
"Details":[
{
"car_id":184,
"user_id":141,
"manufacturer_id":21,
"name":"Akma",
"registration_no":"ws 3345",
"model_name":"Bezza",
"production_year":2022,
"notes":null,
"date_purchased":"2022-08-10",
"image":"http://servisjer.me-tech.com.my/admin/storage/app/media/userplugin/7PyVIp8iwb.png"
}
]
}
then to get save the details is a list so you have to loop through the list i.e
if(body["Status"]=="OK")
{
List<Detail> allRecord;
final parsed = json.decode(body).cast<Map<String, dynamic>>();
allRecord = parsed .map<Detail>((json) => Detail.fromJson(json)).toList();
}
here is your model :
// To parse this JSON data, do
//
// final responseModel = responseModelFromJson(jsonString);
import 'dart:convert';
ResponseModel responseModelFromJson(String str) => ResponseModel.fromJson(json.decode(str));
String responseModelToJson(ResponseModel data) => json.encode(data.toJson());
class ResponseModel {
ResponseModel({
this.status,
this.message,
this.details,
});
String status;
String message;
List<Detail> details;
factory ResponseModel.fromJson(Map<String, dynamic> json) => ResponseModel(
status: json["Status"],
message: json["Message"],
details: List<Detail>.from(json["Details"].map((x) => Detail.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"Status": status,
"Message": message,
"Details": List<dynamic>.from(details.map((x) => x.toJson())),
};
}
class Detail {
Detail({
this.carId,
this.userId,
this.manufacturerId,
this.name,
this.registrationNo,
this.modelName,
this.productionYear,
this.notes,
this.datePurchased,
this.image,
});
int carId;
int userId;
int manufacturerId;
String name;
String registrationNo;
String modelName;
int productionYear;
dynamic notes;
DateTime datePurchased;
String image;
factory Detail.fromJson(Map<String, dynamic> json) => Detail(
carId: json["car_id"],
userId: json["user_id"],
manufacturerId: json["manufacturer_id"],
name: json["name"],
registrationNo: json["registration_no"],
modelName: json["model_name"],
productionYear: json["production_year"],
notes: json["notes"],
datePurchased: DateTime.parse(json["date_purchased"]),
image: json["image"],
);
Map<String, dynamic> toJson() => {
"car_id": carId,
"user_id": userId,
"manufacturer_id": manufacturerId,
"name": name,
"registration_no": registrationNo,
"model_name": modelName,
"production_year": productionYear,
"notes": notes,
"date_purchased": "${datePurchased.year.toString().padLeft(4, '0')}-${datePurchased.month.toString().padLeft(2, '0')}-${datePurchased.day.toString().padLeft(2, '0')}",
"image": image,
};
}
Worst Approach : use a for each to loop through if you are sure the Details array has only one object i.e
for (var data in details)
{
debugPrint(data.model_name);
debugPrint(data.registration_no);
//and many more
}
This is my model;
/*
// To parse this JSON data, do
//
// final hisselist = hisselistFromJson(jsonString);
import 'dart:convert';
Hisselist hisselistFromJson(String str) => Hisselist.fromJson(json.decode(str));
String hisselistToJson(Hisselist data) => json.encode(data.toJson());
class Hisselist {
Hisselist({
required this.success,
required this.result,
});
bool success;
List<ResultClass> result;
factory Hisselist.fromJson(Map<String, dynamic> json) => Hisselist(
success: json["success"], result: json["result"].map<ResultClass>((x) => ResultClass.fromJson(x)).toList(),
);
Map<String, dynamic> toJson() => {
"success": success,
"result": result.map((x) => x.toJson()),
};
}
class ResultClass {
ResultClass({
required this.rate,
required this.lastprice,
required this.lastpricestr,
required this.hacim,
required this.hacimstr,
required this.text,
required this.code,
});
double rate;
double lastprice;
String lastpricestr;
double hacim;
String hacimstr;
String text;
String code;
factory ResultClass.fromJson(Map<String, dynamic> json) => ResultClass(
rate: double.tryParse(json["rate"].toString()) ?? 0.0,
lastprice: double.tryParse(json["lastprice"].toString()) ?? 0.0,
lastpricestr: json["lastpricestr"],
hacim: double.tryParse(json["hacim"].toString()) ?? 0.0,
hacimstr: json["hacimstr"],
text: json["text"],
code: json["code"],
);
Map<String, dynamic> toJson() => {
"rate": rate,
"lastprice": lastprice,
"lastpricestr": lastpricestr,
"hacim": hacim,
"hacimstr": hacimstr,
"text": text,
"code": code,
};
}
*/
// To parse this JSON data, do
//
// final hisselist = hisselistFromJson(jsonString);
import 'dart:convert';
Hisselist hisselistFromJson(String str) => Hisselist.fromJson(json.decode(str));
String hisselistToJson(Hisselist data) => json.encode(data.toJson());
class Hisselist {
Hisselist({
required this.success,
required this.result,
});
bool success;
List<Result> result;
factory Hisselist.fromJson(Map<String, dynamic> json) => Hisselist(
success: json["success"],
result: List<Result>.from(json["result"].map((x) => Result.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"success": success,
"result": List<dynamic>.from(result.map((x) => x.toJson())),
};
}
class Result {
Result({
this.rate,
this.lastprice,
this.lastpricestr,
this.hacim,
this.hacimstr,
this.min,
this.minstr,
this.max,
this.maxstr,
this.time,
this.text,
this.code,
});
double? rate;
double? lastprice;
String? lastpricestr;
String? hacim;
String? hacimstr;
dynamic min;
String? minstr;
dynamic max;
String? maxstr;
Time? time;
String? text;
String? code;
factory Result.fromJson(Map<String, dynamic> json) => Result(
rate: json["rate"].toDouble(),
lastprice: json["lastprice"].toDouble(),
lastpricestr: json["lastpricestr"],
hacim: json["hacim"],
hacimstr: json["hacimstr"],
min: json["min"],
minstr: json["minstr"],
max: json["max"],
maxstr: json["maxstr"],
time: timeValues.map[json["time"]],
text: json["text"],
code: json["code"],
);
Map<String, dynamic> toJson() => {
"rate": rate,
"lastprice": lastprice,
"lastpricestr": lastpricestr,
"hacim": hacim,
"hacimstr": hacimstr,
"min": min,
"minstr": minstr,
"max": max,
"maxstr": maxstr,
"time": timeValues.reverse[time],
"text": text,
"code": code,
};
}
enum Time { THE_1809, THE_1808, THE_1805, THE_1810, THE_1759, THE_1755 }
final timeValues = EnumValues({
"17:55": Time.THE_1755,
"17:59": Time.THE_1759,
"18:05": Time.THE_1805,
"18:08": Time.THE_1808,
"18:09": Time.THE_1809,
"18:10": Time.THE_1810
});
class EnumValues<T> {
Map<String, T> map;
Map<T, String>? reverseMap;
EnumValues(this.map);
Map<T, String> get reverse {
if (reverseMap == null) {
reverseMap = map.map((k, v) => new MapEntry(v, k));
}
return reverseMap!;
}
}
This is where i call api:
class Hisseler extends StatefulWidget {
const Hisseler({Key? key}) : super(key: key);
#override
State<Hisseler> createState() => _HisselerState();
}
class _HisselerState extends State<Hisseler> {
final controller = TextEditingController();
final scaffoldKey = GlobalKey<ScaffoldState>();
final url = Uri.parse('https://api.collectapi.com/economy/hisseSenedi');
var counter;
Hisselist? hisseResult;
Future callHisse() async {
try{
Map<String, String> requestHeaders = {
'Content-Type': 'application/json',
'Authorization': 'apikey xxx:xxx'
};
final response = await http.get(url,headers:requestHeaders);
if(response.statusCode == 200){
var result = hisselistFromJson(response.body);
if(mounted);
setState(() {
counter = result.result.length;
result.result.sort((a, b) => (a.text ?? "").compareTo(b.text ?? ""));
hisseResult = result;
});
return result;
} else {
print(response.statusCode);
}
} catch(e) {
print(e.toString());
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
callHisse();
}
#override
Widget build(BuildContext context) {
final style = controller.text.isEmpty
? const TextStyle(color: Colors.black54)
: const TextStyle(color: Colors.black);
return Scaffold(
appBar: AppBar(
centerTitle: false,
automaticallyImplyLeading: false,
title: Text(
'Hisseler'
),
),
body: Column(
children: [
Container(
margin: const EdgeInsets.fromLTRB(16, 16, 16, 16),
child: TextField(
controller: controller,
decoration: InputDecoration(
prefixIcon: const Icon(Icons.search),
suffixIcon: controller.text.isNotEmpty
? GestureDetector(
child: Icon(Icons.close, color: style.color),
onTap: () {
controller.clear();
FocusScope.of(context).requestFocus(FocusNode());
searchHisse('');
},
)
: null,
hintText: 'Hisse Ara',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(color: Colors.black26),
),
),
onChanged: searchHisse,
),
),
Expanded(
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: counter != null ?
ReorderableListView.builder(
itemCount: counter,
itemBuilder: (context, index){
return Card(
key: ValueKey(hisseResult?.result[index]),
child: ListTile(
contentPadding: EdgeInsets.all(10),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text((hisseResult?.result[index].code ?? "")
.replaceAll("https:", ""),
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w500)),
Text(hisseResult?.result[index].text??"",style: TextStyle(color: Colors.grey[500], fontSize: 14))
],
),
trailing: Column(
children: <Widget>[
Text(hisseResult?.result[index].lastpricestr??"", style: TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w500)),
Container(
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: (hisseResult?.result[index].rate ?? 0) > 0
? Colors.green
: Colors.red),
width: 75,
height: 25,
child: Text(hisseResult?.result[index].rate.toString() ?? "",
style: TextStyle(color: Colors.white)))
],
),
onTap: () => Navigator.push(
context, MaterialPageRoute(builder: (context) => StocksDetailScreen(
degisimoran: hisseResult?.result[index].rate!.toDouble(),
sondeger: hisseResult?.result[index].lastpricestr??"",
hacim: hisseResult?.result[index].hacimstr ?? "",
mindeger : hisseResult?.result[index].minstr?? "",
maxdeger : hisseResult?.result[index].maxstr?? "",
hisseismi : hisseResult?.result[index].text?? "",
hissekodu : hisseResult?.result[index].code?? "",
min : hisseResult?.result[index].min!.toDouble(),
max : hisseResult?.result[index].max!.toDouble(),
son : hisseResult?.result[index].lastprice!.toDouble(),
)),),
),
);
},
onReorder: (oldIndex, newIndex) {
setState(() {
if (newIndex > oldIndex) {
newIndex = newIndex - 1;
}
final element = hisseResult?.result.removeAt(oldIndex);
hisseResult?.result.insert(newIndex, element!);
});
},) : Center(child: CircularProgressIndicator(
)),
),
),
),
],
),
);
}
void searchHisse(String query) {
final suggestions = hisseResult?.result.where((code) {
final hisseTitle = hisseResult?.result;
final input = query.toLowerCase();
return hisseTitle!.contains(input);
}).toList();
setState(() => hisseResult = suggestions as Hisselist?);
}
}
But nothing happens on search result :
I think the problem is on searchHisse() but i am not sure. How can i make this work? Thanks for your help
Based on your code , you only call api once and you get the full list only once too.
i think you need to separated in to 2 list object.
eg case:
initstate you fetch api callHisse(); and get the data.
then you can show all the data from hisseResult.
after 1 onchanged on Textfield you call searchHisse(String query) , which is updated your hisseResult. now you only have data with first letters from onchanged
then you tapped on textfield and clear the controller. there is no data on the list left that match to query
this is what i suggest
Hisselist? hisseResult; // data you get from API
Hisselist? hisseShow; // list that you show
and on your search function you need to add this condition
void searchHisse(String query) {
if (query == '') {
setState((){hisseShow =hisseResult;});
return;
}
final suggestions = hisseResult?.result.where((code) {
final hisseTitle = hisseResult?.result;
final input = query.toLowerCase();
return hisseTitle!.contains(input);
}).toList();
// based on your model data
setState(() => hisseShow = Hisselist(result: suggestions, success:true );
}
}
and you show your list
return Card(
key: ValueKey(hisseShow?.result[index]),
child: ListTile(
.....