HTTP request doesn't get complete data in flutter - json

I have this class :
class Weeks {
final int index;
final int udigree;
final int d_id;
final String activity_a;
final String activity_k;
final String title_a;
final String title_k;
Weeks(this.index, this.udigree, this.d_id, this.activity_a, this.activity_k,
this.title_a, this.title_k);
}
I used future function to get data from server :
import 'package:flutter/material.dart';
import 'package:jiyanUquraan/classes/weekly.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class Weekly extends StatefulWidget {
#override
_WeeklyState createState() => _WeeklyState();
}
class _WeeklyState extends State<Weekly> {
#override
Widget build(BuildContext context) {
var widthView = MediaQuery.of(context).size.width;
var heightView = MediaQuery.of(context).size.height;
List weekly = [];
Map rData = ModalRoute.of(context).settings.arguments;
var cm_id = rData['current_m_id'];
var u_id = rData['u_id'];
var d_id = rData['d_id'];
var w_id = rData['w_id'];
// Futher Function for Get Data
Future<List> getWeeks() async {
print(cm_id);
print(u_id);
print(w_id);
var url =
'http://10.0.2.2/jiyan/test/api/digrees/weekly_report.php?m_id=$cm_id&u_id=$u_id&w_id=$w_id';
var response = await http.get(url);
var data = jsonDecode(response.body);
print(data);
print(data.length);
for (var x in data) {
Weeks _weeklyReport = Weeks(x['index'], x['udigree'], x['activity_a'],
x['activity_k'], x['title_a'], x['title_k'], x['d_id']);
weekly.add(_weeklyReport);
}
return weekly;
}
// End of Get Data
// Create Future Builder
return FutureBuilder(
future: getWeeks(),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Center(
child: Text('Loading'),
);
} else {
return Center(child: Text('data'));
}
});
// End of Futur Builder
}
}
As I print the data and its length, the length is correct but the data is not complete as shown:
As it doesn't get the data correctly the snapshot.data gets null, How can I fix this?
Does the error occur because the data is Kurdish?

the Mistake was in the class .
the variables d_id and udigree must be String
class Weeks {
final int index;
final String udigree;
final Stringd_id;
final String activity_a;
final String activity_k;
final String title_a;
final String title_k;
Weeks(this.index, this.udigree, this.d_id, this.activity_a, this.activity_k,
this.title_a, this.title_k);
}

Related

Can anyone explain the function of .map()

I was trying to make a Covid Tracking application using flutter, and I came across this function getCountrySummary( ),
import 'package:covid_tracker/models/country_summary.dart';
import 'package:covid_tracker/models/global_summary.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class CovidService {
Future<GlobalSummaryModel> getGlobalSummary() async {
final data =
await http.get(Uri.parse('https://api.covid19api.com/summary'));
if (data.statusCode != 200) {
throw Exception();
}
GlobalSummaryModel summary =
GlobalSummaryModel.fromJson(json.decode(data.body));
return summary;
}
Future<List<CountrySummaryModel>> getCountrySummary(String slug) async {
String url = "https://api.covid19api.com/total/dayone/country/$slug";
final data = await http.get(Uri.parse(url));
if (data.statusCode != 200) {
throw Exception();
}
List<CountrySummaryModel> summaryList = (json.decode(data.body) as List)
.map((item) => CountrySummaryModel.fromJson(item))
.toList();
return summaryList;
}
}
So I know what the function getCountrySummary() is trying to do, but I don't understand what statement
List<CountrySummaryModel> summaryList = (json.decode(data.body) as List).map((item) => CountrySummaryModel.fromJson(item)).toList();
is trying to do, and CountrySummaryModel is an object.
class CountrySummaryModel {
final String country;
final int confirmed;
final int death;
final int recovered;
final int active;
final DateTime date;
CountrySummaryModel(this.country, this.active, this.confirmed, this.date,
this.death, this.recovered);
factory CountrySummaryModel.fromJson(Map<String, dynamic> json) {
return CountrySummaryModel(
json["country"],
json["active"],
json["confirmed"],
DateTime.parse(json["date"]),
json["death"],
json["recovered"],
);
}
}
When you call Map on a list, it means you want to reach each item in it, in your case you call map on your list to parse each item in it and at then call toList() to make a list of this items.
If I understand your code correctly:
First, you convert data to List.
Then, use CountrySummaryModel.fromJson() and .toList() to convert it to List<CountrySummaryModel>.

sqflite + Flutter : map((e) => .... returns [Instance of Class]

I am currently using Sqflite with Flutter for a small app being developed.
My model Class for User is as follows:
class User {
static const tblUser = 'users';
static const colUserId = 'id';
static const colUserName = 'name';
static const colUserMail = 'mail';
static const colUserPhone = 'phone';
User({this.id, this.name, this.mail, this.phone});
int id;
String name;
String mail;
String phone;
User.fromMap(Map<String, dynamic> map) {
this.id = map[colUserId];
this.name = map[colUserName];
this.mail = map[colUserMail];
this.phone = map[colUserPhone];
}
Map<String, dynamic> toMap() {
var map = <String, dynamic>{
colUserName: name,
colUserMail: mail,
colUserPhone: phone
};
if (id != null) {
map[colUserId] = id;
}
return map;
}
}
In the database_helper class, I create the database and the tables, which work correctly:
class DatabaseHelper {
static const _databaseName = 'FinmanDatabase.db';
static const _databaseVersion = 1;
DatabaseHelper._();
static final DatabaseHelper instance = DatabaseHelper._();
Database _database;
Future<Database> get database async {
if (_database != null) return _database;
_database = await _initDatabase();
return _database;
}
_initDatabase() async {
Directory dbDirectory = await getApplicationDocumentsDirectory();
String dbpath = join(dbDirectory.path, _databaseName);
return await openDatabase(dbpath,
version: _databaseVersion, onCreate: _onCreateDB);
}
Future _onCreateDB(Database db, int version) async {
await db.execute('''
CREATE TABLE ${User.tblUser} (
${User.colUserId} INTEGER PRIMARY KEY AUTOINCREMENT,
${User.colUserName} TEXT NOT NULL,
${User.colUserMail} TEXT NOT NULL,
${User.colUserPhone} TEXT NOT NULL
)
''');
}}
However, when I try to fetch the Users to flutter, the program returns 'Instance of User' instead of the contents. The function to fetch the Users is as follows:
Future<List<User>> fetchAllUser() async {
Database db = await database;
List<Map> userslist = await db.query(User.tblUser);
int count = userslist.length;
print('Printing $userslist from DBHelper + Length: $count');
return userslist.length == 0 ? [] : userslist.map((e) => User.fromMap(e)).toList();
}
And here is how I am calling this in Flutter:
class _HomeState extends State<Home> {
User user = User();
List<User> _users;
String _dbExists;
DatabaseHelper _dbhelper;
int count = 0;
#override
void initState() {
super.initState();
setState(() {
_dbhelper = DatabaseHelper.instance;
});
_refreshUserList();
}
_refreshUserList() async {
List<User> x = await _dbhelper.fetchAllUser();
setState(() {
_users = x;
print(_users);
count = _users.length;
print(count);
if (count > 0) {
_dbExists = 'Database exists';
} else {
_dbExists = 'Create a new Database';
}
});
}}
While the print(count) returns 1 (which is the number of records in the User Table), print(_users) returns [Instance of User]??
Any help is appreciated.
when I try to fetch the Users to flutter, the program returns
'Instance of User' instead of the contents
Because x is List<User>.
To get the content, you can use for-loop
for(var i in x){
print(i.name); // it will print out the name
}

Flutter/Dart - How to pass variables between classes?

I am very new to programming and I am trying to pass a variable (jsonData) from a future to another future in a different class, so the data from the variable can be stored in a database. Dont be confused, I am using an API for getting the neccessary data, this works perfectly fine. Any tips how I can access the variable jsonData to insert the data?
//first class gets the json data
class getJSONData {
Future<void> makeRequest() async {
var url = "some url";
Map inputData = {
"Password": example,
"SQL": sql query,
"db_server": "server",
"db_table": "table",
};
var body = json.encode(inputData);
var putRequest = await http.put(
Uri.encodeFull(url), headers: {"Content-Type": "application/json"},
body: body);
//this variable has to be stored
var jsonData = json.decode(putRequest.body);
}
}
//data needs to be inserted here
class Database {
Future<void> insertJSON() async {
db = await openDatabase(
join(await getDatabasesPath(), tableName),
onCreate: (db, version) {
return db.execute('''
INSERT INTO $tableName(column1, column2, etc) VALUES (${jsonData["Records].data1}, ${jsonData["Records].data2}, etc)
''');
}
);
}
}
below i am showing you how to pass data between two screens :
Screen 1 :
class HomeScreenTopContainer extends StatefulWidget {
#override
_HomeScreenTopContainerState createState() => _HomeScreenTopContainerState();
}
class _HomeScreenTopContainerState extends State<HomeScreenTopContainer> {
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Inkwell(onTap:(){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ParentLanding(parameter:"pass your value here")),
);
},child:Text("Tap Here and pass data")),
],
);
}
}
Screen 2 :
class ParentLanding extends StatefulWidget {
String parameter;
ParentLanding({Key key,String parameter}) : super(key: key,parameter:parameter);
#override
_ParentLandingState createState() => _ParentLandingState();
}
class _ParentLandingState extends State<ParentLanding> {
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Inkwell(onTap:(){
// you can use this parameter like this.
},child:Text(**Widget.parameter**)),
],
);
}
}
You have many options.
I'll suggest you one.
Change the signatures of both methods.
Example
Your HttpClient class
Future<Map<String, dynamic>> makeRequest() async {
// ... your code
var jsonData = json.decode(putRequest.body);
return jsonData;
}
Your DB Class
Future<void> insertJSON(Map<String, dynamic> jsonData) async {
db = await openDatabase(
join(await getDatabasesPath(), tableName),
onCreate: (db, version) {
return db.execute('''
INSERT INTO $tableName(column1, column2, etc) VALUES
(${jsonData["Records].data1}, ${jsonData["Records].data2}, etc)
''');
}
);
}
Use a third Class/object/method that make the call to the api, take the result and pass it to the db class:
main() async {
HttClient http = HttpClient();
Database db = Database();
final json = await http.makeRequest();
await db.insertJSON(json);
}
Easiest way to pass any value is using an argument.
Value can be send as:
Keys.navKey.currentState.pushNamed(
Routes.gameViewScreen, arguments: jsonData );
In another class it can be retrieved as :
var jsonData = ModalRoute.of(context).settings.arguments;

Flutter : Showing nested data received from serve : Edited #3

I have an app receive nested data from server in the page i print the data's and it is printed successfully :
class page :
final DateTime mDate;
final List<Games> games;
class DatedMatchs {
DatedMatchs(
this.mDate,
this.games,
);
}
class Games {
Games(
this.id,this.sId,this.wId,this.leagueName,this.homeTeam,this.awayTeam,this.homeGoals,this.awayGoals,this.mHour,this.homeEx,this.awayEx,
);
final String id;
final String sId;
final String wId;
final String leagueName;
final String homeTeam;
final String awayTeam;
final String homeGoals;
final String awayGoals;
final String mHour;
final String homeEx;
final String awayEx;
}
page i want to show data:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
import '../models/dated_matchs.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
List matchs = [];
Future<List> getmatchs() async {
var url =
'xxx/api/controller/matchs/dated_matchs.php?s_id=1';
var response = await http.get(url);
var data = jsonDecode(response.body);
print(data);
}
return FutureBuilder(
future: getmatchs(),
builder: (ctx, snapshot) {
return Container();
});
}
}
Now i don't know how to add received data to a list then show it on list-view
I used this way inside future function but there is something wrong :
Future<List> getmatchs() async {
var url =
'xxx/api/controller/matchs/dated_matchs.php?s_id=1';
var response = await http.get(url);
var data = jsonDecode(response.body);
for (var x in data) {
for (var y in x['games']) {
cont1.add(TextEditingController());
cont2.add(TextEditingController());
Games newmatch = Games(
y['id'],
y['s_id'],
y['w_id'],
y['league_name'],
y['home_team'],
y['away_team'],
y['home_goals'],
y['away_goals'],
y['m_hour'],
y['home_ex'],
y['away_ex']);
matchs.add(newmatch);
}
DatedMatchs newdated = DatedMatchs(x['m_date'], x['matchs']);
datedmatchs.add(newdated);
}
return datedmatchs;
}
no thing print
Some of your data is coming back as a Map, rather than a List. You'll need to debug and see which data is a Map, then you can print it from the Map.
Also, I wouldn't call an api in your UI. It's best to use a state management library, such as Bloc, Provider, or RxDart.
I solved it and below the future method which get me list of data correctly :
List<Games> games = []; // I added type of List
List<DatedMatchs> datedmatchs = []; // I added type of List
Future<List> getmatchs() async {
var url =
'xxx/api/controller/matchs/dated_matchs.php?s_id=1';
var response = await http.get(url);
var data = await jsonDecode(response.body);
for (var x in data) {
for (var y in x['games']) {
cont1.add(TextEditingController());
cont2.add(TextEditingController());
Games newmatch = Games(
y['id'],
y['s_id'],
y['w_id'],
y['league_name'],
y['home_team'],
y['away_team'],
y['home_goals'],
y['away_goals'],
y['m_hour'],
y['home_ex'],
x['away_ex']);
games.add(newmatch);
}
DatedMatchs newdated = DatedMatchs(x['m_date'], games); // add name of list
datedmatchs.add(newdated);
}
return datedmatchs;
}

What's the best way to serialize data from Firebase into Dart object for Flutter?

What is the best way to serialize a list of data from Firebase? Firebase provides an object with a list of properties for the list which makes it more challenging to come up with a good conversion technique.
How would you serialize this data from Firebase:
{
"-KiRg_F-qC59xxlfZ6ej": {
"first":"Brandon",
"last":"Donnelson"
},
"-KiRgmsISBsJSWfXhrdD": {
"first":"Danny",
"last":"Kirk"
}
}
What I came up with — see _loadData()) —:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Text(
'click',
),
),
floatingActionButton: new FloatingActionButton(
onPressed: _test,
tooltip: 'Increment',
child: new Icon(Icons.add),
),);
}
void _test() {
_loadData();
}
_loadData() async {
String url = 'https://dev-xxxxxxx.firebaseio.com/names.json';
var httpClient = createHttpClient();
var response = await httpClient.read(url);
print('response=' + response);
// response = {
// "-KiRg_F-qC59xxlfZ6ej":{"first":"Brandon","last":"Donnelson"},
// "-KiRgmsISBsJSWfXhrdD":{"first":"Danny","last":"Kirk"}
// }
NamesData namesData = new NamesData(JSON.decode(response));
print("names.len=" + namesData.names.length.toString());
}
}
class NamesData {
final List<NameData> names = new List();
NamesData(Map data) {
data.values.forEach((Map map) => names.add(new NameData.fromJson(map)));
}
}
class NameData {
String first;
String last;
NameData.fromJson(Map map) {
first = map['first'];
last = map['last'];
}
}
I found the JSON decoder has a better method for instantiating classes with the reviver function. This feels much better, but I think I can do better.
_loadData() async {
String url = 'https://dev-xxxxxxx.firebaseio.com/names.json';
var httpClient = createHttpClient();
var response = await httpClient.read(url);
print('response=' + response);
// response = {
// "-KiRg_F-qC59xxlfZ6ej":{"first":"Brandon","last":"Donnelson"},
// "-KiRgmsISBsJSWfXhrdD":{"first":"Danny","last":"Kirk"}
// }
var extendedJson = new JsonCodec(reviver: _reviver);
var o = extendedJson.decode(response);
print('end');
}
// https://github.com/dart-lang/sdk/blob/master/tests/lib/convert
// /json_toEncodable_reviver_test.dart
_reviver(key, value) {
if (value != null && value is Map && key.toString().contains("-")) {
return new NameData2(value);
}
return value;
}
}
class NameData2 {
String first;
String last;
NameData2(Map map) {
first = map['first'];
last = map['last'];
}
}
I personally like writing a tiny Codec sometimes:
DartPad example
import 'dart:convert';
void main() {
final decoder = const FirebaseNamesDecoder();
print(decoder.convert(exampleFirebaseData));
}
class NamedData {
final String id;
final String firstName;
final String lastName;
const NamedData(this.id, this.firstName, this.lastName);
#override
String toString() => '$NamedData {$id: $firstName $lastName}';
}
class FirebaseNamesDecoder extends Converter<Map, Iterable<NamedData>> {
const FirebaseNamesDecoder();
#override
Iterable<NamedData> convert(Map<String, Map> raw) {
return raw.keys.map((id) => new NamedData(id, raw[id]['first'], raw[id]['last']));
}
}
final exampleFirebaseData = {
"-KiRg_F-qC59xxlfZ6ej": {
"first":"Brandon",
"last":"Donnelson"
},
"-KiRgmsISBsJSWfXhrdD": {
"first":"Danny",
"last":"Kirk"
}
};
Results in:
(
NamedData {-KiRg_F-qC59xxlfZ6ej: Brandon Donnelson},
NamedData {-KiRgmsISBsJSWfXhrdD: Danny Kirk}
)
Dart 2 needs modification to the overridden method:
Iterable<NamedData> convert(Map<dynamic,dynamic> raw) {
return raw.keys
.map((id) => new NamedData(id, raw[id]['first'], raw[id]['last']));
}
Serializing JSON manually using dart:convert
Basic JSON serialization in Flutter is very simple. Flutter has a built-in dart:convert library which includes a straightforward JSON encoder and decoder.
The following sample JSON implements a simple user model.
{"name":"John Smith","email":"john#example.com"}
With dart:convert, you can serialize this JSON model in two ways.
1) Serializing JSON inline
   
Map<String, dynamic> user = jsonDecode(jsonString);
print('Howdy, ${user['name']}!');
print('We sent the verification link to ${user['email']}.');
2) Serializing JSON inside model classes
class User
{
final Stringname;
final Stringemail;
User(this.name,this.email);
User.fromJson(Map<String,dynamic>json):name=json['name'],email=json['email'];
Map<String,dynamic>toJson()=>
{
'name':name,
'email':email,
};
}
The responsibility of the decoding logic is now moved inside the model itself. With this new approach, you can decode a user easily.
Map userMap = jsonDecode(jsonString);
var user = User.fromJson(userMap);
print('Howdy, ${user.name}!');
print('We sent the verification link to ${user.email}.');
I would recommend using json_serializable it is developed by google developers and it can handle the boilerplate code easily.