Flutter app using pagewise package and JSON - json

I am building an APP using pagewise package and would like to get the totalCount var from an external JSON request.
I have a function that returns an INT value that will be the totalCount but when added to the totalCount parameter it returns an error:
type 'Future<int>' is not a subtype of type 'int'
How can I solve this matter?
UPDATE:
return PagewiseGridView(
pageSize: 6,
totalCount: getTotals(),
crossAxisCount: 2,
mainAxisSpacing: 8.0,
crossAxisSpacing: 8.0,
childAspectRatio: 0.555,
padding: EdgeInsets.all(15.0),
itemBuilder: this._itemBuilder,
pageFuture: BackendService.getPage,
);
this is the class that creates the grid.

The problem is that you can't pass a future to a variable that expects an int.
You need to await for the future to complete and while you are awaiting you could, for instance, display a centered circular indicator.
This is something that you could use in your State class:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
State createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _totalCounter = -1;
#override
void initState() {
super.initState();
getTotalCounter();
}
void getTotalCounter() async {
_totalCounter = await getTotals();
setState(() {});
}
// Simulate your future
Future<int> getTotals() {
return Future.delayed(Duration(seconds: 3), () => 100);
}
#override
Widget build(BuildContext context) {
return _totalCounter == -1
? Center(child: CircularProgressIndicator())
: PagewiseGridView(
pageSize: 6,
totalCount: _totalCounter,
crossAxisCount: 2,
mainAxisSpacing: 8.0,
crossAxisSpacing: 8.0,
childAspectRatio: 0.555,
padding: EdgeInsets.all(15.0),
itemBuilder: this._itemBuilder,
pageFuture: BackendService.getPage,
);
}
}

From the dart documentation:
A future is a Future object, which represents an asynchronous operation that produces a result of type T.
In your case it is something you need access the info after it was retrieved async.
// Performing a request
// ... some widget
// ... child/Center is here just to exemplify how to use this Future inside a widget
// child: Center(child:
FutureBuilder<CustomList>(
future: fetchPost(),
builder: (context, snapshot) {
if (snapshot.hasData) {
// USE HERE THE DATA:
// snapshot.data.allCustoms
// snapshot.data.allCustoms.length
// for example you can create a ListView here
enter code here
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
})
// Making a request example (called above)
Future<CustomList> fetchPost() async {
final response = await http
.get('https://some_api_example');
if (response.statusCode == 200) {
// was successful, parse
return CustomList.fromJson(json.decode(response.body));
} else {
// not successful, throw.
throw Exception('Failed to load post');
}
}
// Some custom object we need to parse
class Custom {
final String id;
final String info;
Custom({this.id, this.info});
factory Custom.fromJson(Map<String, dynamic> json) {
return Custom(
id: json['id'].replaceAll(" ", ""),
info: json['info'].replaceAll(" ", "")
);
}
}
// A list of custom objects we parse from the reqeust
class CustomList {
final List<Custom> allCustoms;
CustomsList({
this.allCustoms,
});
factory CustomList.fromJson(List<dynamic> parsedJson) {
allCustoms = new List<Custom>();
allCustoms = parsedJson.map((i) => Custom.fromJson(i)).toList();
return new CustomList(
allCustoms: allCustoms,
);
}
}

Could you please try the following code and let me know what error are you getting.
return FutureBuilder<CustomList>(
future: fetchPost(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return PagewiseGridView(
pageSize: 6,
totalCount: snapshot.data,
crossAxisCount: 2,
mainAxisSpacing: 8.0,
crossAxisSpacing: 8.0,
childAspectRatio: 0.555,
padding: EdgeInsets.all(15.0),
itemBuilder: this._itemBuilder,
pageFuture: BackendService.getPage,
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
})

Related

Flutter - Pass variable to another screen for URL GET JSON

I'm new to Flutter. On my HOME screen I have a ListView with fetched Json. I want to pass JSON variable ex:id on Tap to the next screen/class 'contantPage' to show another Json loaded from URL with id added.
ex.https:/example.com/myjson.php?id=1
Please! Show me the way.
main.dart
onTap: () {
Navigator.push(context,MaterialPageRoute(
builder(context)=>ContentPage(
photo: photos[index]
)),);},
And in my ContentPage.dart should add id value to URL as GET ex:?id=1
Future<Album> fetchAlbum() async {
// final query1 = Text(photo.publishDate);
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums.php?id=I WANT ID HERE'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
class Album {
final int userId;
final int id;
final String title;
Album({
required this.userId,
required this.id,
required this.title,
});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}
//void main() => runApp(MyApp());
class ContentPage extends StatefulWidget {
// ContentPage({Key? key, Photo photo}) : super(key: key);
ContentPage({Key? key, required Photo photo}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<ContentPage> {
late Future<Album> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
),
),
);
}
}
Like the photo pass your photosid as follows:
onTap: () {
Navigator.push(context,MaterialPageRoute(
builder(context)=>ContentPage(
photo: photos[index],
id:photos[index].id,
)),);},
And then in ContentPage create constructor as follows:
class ContentPage extends StatefulWidget {
Photo photo;
String id;
ContentPage({Key? key, required this.photo,required this.id,}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
In initstate pass your id as follows:
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum(widget.id);
}
And finally your fetchAlbum as follows:
Future<Album> fetchAlbum(var id) async {
// final query1 = Text(photo.publishDate);
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums.php?id=id'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
I can't understand how to display more than 1 field with my code. I have title field and contentIntro field from Json and want to show all together.
body: Center(
child: FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Center(
child: Text(snapshot.data!.contentIntro),
//child: Text(snapshot.data!.Title),
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
),

Im getting a - type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>' error

I have a list of map in json and Im trying to render 'title' on a list.
Im reading data through through an api (http.get) then parse it.
I want to show the title in a list.
Here's my code...
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Getting the data
Future<Welcome> fetchAlbum() async {
final response = await http.get('https://jsonplaceholder.typicode.com/posts');
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Welcome.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
Convert to json
List<Welcome> welcomeFromJson(String str) =>
List<Welcome>.from(json.decode(str).map((x) => Welcome.fromJson(x)));
String welcomeToJson(List<Welcome> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
Model class Welcome
class Welcome {
Welcome({
this.userId,
this.id,
this.title,
this.body,
});
int userId;
int id;
String title;
String body;
factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
userId: json["userId"],
id: json["id"],
title: json["title"],
body: json["body"],
);
Map<String, dynamic> toJson() => {
"userId": userId,
"id": id,
"title": title,
"body": body,
};
}
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Future<Welcome> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<Welcome>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return new Text(snapshot.data.title);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
),
),
);
}
}
Im getting an error saying " type 'List' is not a subtype of type 'Map<String, dynamic>' "
Change your fetchAlbum function to this
Future<List<Welcome>> fetchAlbum() async {
final response =
await http.get('https://jsonplaceholder.typicode.com/posts');
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
// return Welcome.fromJson(jsonDecode(response.body));
var jsonData = jsonDecode(response.body);
List<Welcome> welcome = [];
for (var v in jsonData) {
Welcome w1 = Welcome(
userId: v['userId'],
id: v['id'],
title: v['title'],
body: v['body']);
welcome.add(w1);
}
return welcome;
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
The FutureBuider widget will be this
child: FutureBuilder(
future: fetchAlbum(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.all(8),
child: Column(
children: [
Text("User Id = ${snapshot.data[index].userId}"),
Text("Id = ${snapshot.data[index].id}"),
Text("Title = ${snapshot.data[index].title}"),
Text("Body = ${snapshot.data[index].body}"),
],
),
);
});
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),

Store List of Objects or Map in SharedPreference using dart

I am returning data from MySQL in JSON using this piece of code
while($row = mysqli_fetch_assoc($queryResult)) {
$resultArray[]=$row;
}
echo json_encode($resultArray);
The result is in this format
[{
"reg_number": "FA16-BCS-106",
"teacher_id": "1",
"qr_code": "jamshaid",
"course_name": "COURSE 1"
}, {
"reg_number": "FA16-BCS-106",
"teacher_id": "EMP_FA10_10",
"qr_code": "jamoo",
"course_name": "COURSE 2"
}]
I am decoding the response and storing it in a list using this method which is working fine.
class Student {
final String reg_number;
final String teacher_id;
final String qr_code;
final String course_name;
Student({this.reg_number, this.teacher_id, this.qr_code, this.course_name});
factory Student.fromJson(Map<String, dynamic> json) {
return Student(
reg_number: json['reg_number'],
teacher_id: json['teacher_id'],
qr_code: json['qr_code'],
course_name: json['course_name'],
);
}
}
final parsed =
json.decode(jsonResponse.body).cast<Map<String, dynamic>>();
List<Student> st =
parsed.map<Student>((json) => Student.fromJson(json)).toList();
I am trying to store this List of objects of Student class in SharedPreference using version ^0.5.6. There is no direct method available for this. I've tried using this method but having the following error.
Unhandled Exception: type 'List' is not a subtype of type 'Map'
jsonResponse.body is supposed to be a string but it is reading it as List<dynamic>. Why is that happening? Am I doing anything wrong while parsing the result? Thanks
Here is a simple example created for you to understand how to do this. This is ok for small list but if you have a large list, I dont recommend this because of we are doing too much stuff here.
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Todo {
final String title;
final String description;
Todo(this.title, this.description);
Todo.fromJson(Map<String, dynamic> map) :
title = map["title"],
description = map["description"];
Map<String, dynamic> toMap() => {
"title": title,
"description": description
};
}
void main() {
runApp(MaterialApp(
title: 'Passing Data',
home: HomePage(
todos: List.generate(
20, (i) => Todo(
'Todo $i',
'A description of what needs to be done for Todo $i',
),
),
),
));
}
class HomePage extends StatelessWidget {
final List<Todo> todos;
HomePage({this.todos}) {
saveTodos();
}
void saveTodos() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> values = todos.map((item) => json.encode(item.toMap())).toList();
prefs.setStringList("todos", values);
}
#override
Widget build(BuildContext context) {
return TodosScreen();
}
}
class TodosScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _StateTodosScreen();
}
}
class _StateTodosScreen extends State<TodosScreen> {
Future<List<Todo>> getTodos() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> values = prefs.getStringList("todos");
return values.map((item) => Todo.fromJson(json.decode(item))).toList();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Todos'),
),
body: FutureBuilder(
future: getTodos(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(snapshot.data[index].title),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen(todo: snapshot.data[index]),
),
);
},
);
},
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
);
}
}
class DetailScreen extends StatelessWidget {
final Todo todo;
DetailScreen({Key key, #required this.todo}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(todo.title),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Text(todo.description),
),
);
}
}
But you can simply encode your complete json and store, there will not be much work then, but if it is a complex json you have to handle that also.

JSON Array to JSON Object

I'm using a HTTP request that gets a JSON array and pushes this into a JSON object which is read by a list view. I'm having difficulty forcing the JSON array into a JSON object so I'm currently calling each object once via json.decode(response.body)[0]. How can I cast the JSON Array to a JSON Object and have the list view read this entire JSON object?
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Post> fetchPost() async {
final url = <my_url>;
final response =
await http.get(url);
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON.
print(json.decode(response.body));
// TODO: Identify a way to convert JSON Array to JSON Object
return Post.fromJson(json.decode(response.body)[0]);
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
class Post {
final String title;
Post({this.title});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
title: json['title']
);
}
}
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Future<Post> post;
#override
void initState() {
super.initState();
post = fetchPost();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<Post>(
future: post,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data.title);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
),
),
);
}
}
try this,
Future<List<Post>> fetchPost() async {
final url = <my_url>;
final response =
await http.get(url);
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON.
print(json.decode(response.body));
List<dynamic> responseList = json.decode(response.body);
// TODO: Identify a way to convert JSON Array to JSON Object
List<Post> tempList = [];
responseList.forEach((f) {
tempList.add(Post.fromJson(f));
});
return tempList;
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
class Post {
final int id;
final String title;
Post({this.id, this.title});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(id: json['id'], title: json['title']);
}
}
class _Frag_CommitteeState extends State<Frag_Committee> {
Future<List<Post>> post;
#override
void initState() {
super.initState();
post = fetchPost();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<List<Post>>(
future: post,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return Text(snapshot.data[index].title);
});
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
),
);
}
}

How to solve this "The getter 'length' was called on null"

I have a php file hosted on my college server and when i run this file on the server it works very well. I can get the json data after running my php file which is in the link http://www.alkadhum-col.edu.iq/Teachers%20Activities/get.php but when i was unable to got them when i had tried that in flutter on the app screen got "the getter 'length'was called on null".
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() {
runApp(Workshops());
}
class Workshops extends StatelessWidget {
#override
Widget build(BuildContext mycontext) {
return MaterialApp(
home:Scaffold(
appBar: AppBar(
backgroundColor: Color.fromRGBO( 52, 73, 94, 1.0),
automaticallyImplyLeading: false, // Don't show the leading button
title: new Text("PHP with Flutter"),
),
body: PostScreen(),
)
);
}
}
class PostScreen extends StatefulWidget {
#override
_PostScreenState createState() => _PostScreenState();
}
class _PostScreenState extends State<PostScreen> {
List<Post> _postList = new List<Post>();
Future<List<Post>> fetchPost() async {
final response =
await http.get('http://www.alkadhum-col.edu.iq/Teachers%20Activities/get.php');
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON
List<dynamic> values = new List<dynamic>();
values = json.decode(response.body);
if (values.length > 0) {
for (int i = 0; i < values.length; i++) {
if (values[i] != null) {
Map<String, dynamic> map = values[i];
_postList.add(Post.fromJson(map));
}
}
}
return _postList;
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
#override
Widget build(BuildContext context) {
return FutureBuilder<List<Post>>(
future: fetchPost(),
builder: (_, AsyncSnapshot<List<Post>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
//dynamic post = snapshot.data[index];
return (Container(
margin: EdgeInsets.symmetric(vertical: 2.0, horizontal: 8.0),
child: new Card(
elevation: 10.0,
child: new Container(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Text(snapshot.data[index].name, style: TextStyle(fontSize: 18.0),),
new Text(snapshot.data[index].msg, style: TextStyle(fontSize: 18.0),),
new Text(snapshot.data[index].day, style: TextStyle(fontSize: 18.0),),
new Text(snapshot.data[index].date, style: TextStyle(fontSize: 18.0),),
],
),
),
),
));
},
);
},
);
}
#override
void initState() {
super.initState();
fetchPost();
}
}
class Post {
String name;
String msg;
String day;
String date;
Post({this.name, this.msg, this.day, this.date});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
name: json['name'],
msg: json['msg'],
day: json['day'],
date:json['date']
);
}
}
How to fix this issue?.
Thanks in advance.
I've looked at your link and tried running the code and I think the issue is in the data returned from your link.
[{"name":"م.م علي ستار باراني","msg":"امتحان مادة قواعد البيانات اول جابترين ","day":"السبت","date":"2019-06-20"}][{"name":"م. امجد عباس التميمي","msg":"امتحان مادة هندسة البرامجيات اول فصلين","day":"الاحد","date":"2019-06-21"},{"name":"م.م علي ستار باراني","msg":"امتحان مادة قواعد البيانات اول جابترين ","day":"السبت","date":"2019-06-20"}]
Right after the first object, you have a closing square bracket and no comma separating it from the opening square bracket beside it. Calling json.decode() on the link body throws the following error
FormatException (FormatException: Unexpected character (at character 115)
...,"day":"السبت","date":"2019-06-20"}][{"name":"م. امجد عباس التميمي","msg...
^
)
After fixing that, it runs fine for me. I tested by taking the body of the link manually and removing the offending characters, leaving me with the json below.
[{"name":"م.م علي ستار باراني","msg":"امتحان مادة قواعد البيانات اول جابترين ","day":"السبت","date":"2019-06-20"},{"name":"م. امجد عباس التميمي","msg":"امتحان مادة هندسة البرامجيات اول فصلين","day":"الاحد","date":"2019-06-21"},{"name":"م.م علي ستار باراني","msg":"امتحان مادة قواعد البيانات اول جابترين ","day":"السبت","date":"2019-06-20"}]
Running the app now displays the following:
make sure to always check for nulls in itemCount like this
ListView.builder(
itemCount: snapshot.data.length == null ? 0 :snapshot.data.length,
itemBuilder: (_, index){}
),
With this if your list is null, the itemCount will return a 0.
Just do this to the list List<Post> _postList = [] that happens its that everything it a object in Dart so when you do this List<Post> _postList = new List<Post>(); your variable _postList is equal to null because has been declared but not initialize so by default it null and you will not be able to use any property for the list until it initialize.
in resume just initialize your list like this: an empty list
List<Post> _postList = [];
So you don't have that issue.