I am a newbie in the world of flutter and GetX package and I am trying to create a simple app using my API and I have only JSON API and a model how to create my controller and response data??
Here is my JSON response data from the API
{
"isSuccess": true,
"datacount": 77,
"data": [
{
"provinceID": 1,
"provinceNameEN": "Bangkok",
"geoID": 2
},
{
"provinceID": 2,
"provinceNameEN": "Samut Prakan",
"geoID": 2
}
],
"error": {
"code": null,
"messageToDeveloper": null,
"messageToUser": null
}
}
And this is my model
// To parse this JSON data, do
//
// final provicesModel = provicesModelFromJson(jsonString);
import 'dart:convert';
ProvicesModel provicesModelFromJson(String str) => ProvicesModel.fromJson(json.decode(str));
String provicesModelToJson(ProvicesModel data) => json.encode(data.toJson());
class ProvicesModel {
ProvicesModel({
this.isSuccess,
this.datacount,
this.data,
this.error,
});
bool isSuccess;
int datacount;
List<Datum> data;
Error error;
factory ProvicesModel.fromJson(Map<String, dynamic> json) => ProvicesModel(
isSuccess: json["isSuccess"],
datacount: json["datacount"],
data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
error: Error.fromJson(json["error"]),
);
Map<String, dynamic> toJson() => {
"isSuccess": isSuccess,
"datacount": datacount,
"data": List<dynamic>.from(data.map((x) => x.toJson())),
"error": error.toJson(),
};
}
class Datum {
Datum({
this.provinceId,
this.provinceNameEn,
this.geoId,
});
int provinceId;
String provinceNameEn;
int geoId;
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
provinceId: json["provinceID"],
provinceNameEn: json["provinceNameEN"],
geoId: json["geoID"],
);
Map<String, dynamic> toJson() => {
"provinceID": provinceId,
"provinceNameEN": provinceNameEn,
"geoID": geoId,
};
}
class Error {
Error({
this.code,
this.messageToDeveloper,
this.messageToUser,
});
dynamic code;
dynamic messageToDeveloper;
dynamic messageToUser;
factory Error.fromJson(Map<String, dynamic> json) => Error(
code: json["code"],
messageToDeveloper: json["messageToDeveloper"],
messageToUser: json["messageToUser"],
);
Map<String, dynamic> toJson() => {
"code": code,
"messageToDeveloper": messageToDeveloper,
"messageToUser": messageToUser,
};
}
This is my services
import 'package:dio/dio.dart';
class ProvinceService {
var dio = Dio();
Future<dynamic> provinceService() async {
return await dio.get(
'URL');
}
}
This is my Controller
class RegisterController extends GetxController {
var provicesList = <ProvicesModel>[].obs;
void fetchprovices() async {
ProvinceService request = ProvinceService();
request.provinceService().then((value) {
if (value.statusCode == 200) {
for (var item in value.data) {
<<< Have Error _TypeError (type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Iterable')>>>
provicesList.add(ProvicesModel.fromJson(item));
}
} else {
print('Backend error');
}
}).catchError((onError) {
printError();
});
}
}
This is my page response
class Register extends StatefulWidget {
const Register({Key? key}) : super(key: key);
#override
State<Register> createState() => _RegisterState();
}
class _RegisterState extends State<Register> {
#override
void initState() {
registerController.fetchprovices();
super.initState();
}
final registerController = Get.put(RegisterController());
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(child: GetX<RegisterController>(
builder: (controller) {
return ListView.builder(
itemCount: controller.provicesList.length,
itemBuilder: (context, index) {
return ListTile(
title: Text('${controller.provicesList[index].datacount}'),
subtitle: Text(
'${controller.provicesList[index].data[index].provinceNameEn}'),
);
},
);
},
))
],
),
);
}
}
Refer this for more info :-> getx_dio_example
/////
var provicesList = ProvicesModel().obs;
void fetchprovices() async {
ProvinceService request = ProvinceService();
request.provinceService().then((value) {
if (value.statusCode == 200) {
final response = ProvicesModel.fromJson(value.data);
provicesList.value = response;
} else {
print('Backend error');
}
}).catchError((onError) {
printError();
});
}
///
return ListView.builder(
itemCount: controller.provicesList.data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text('${controller.provicesList.datacount}'),
subtitle: Text(
'${controller.provicesList.data[index].provinceNameEn}'),
);
},
);
Related
I'm trying to make a simple ListView with GetX but it gives me this error when starting the app "Unhandled Exception: NoSuchMethodError: The method 'map' was called on null.", I'm new to flutter and dart, that's why I'm starting with the "easiest" and for work reasons they ask me to add GetX
Home
class HomePage extends GetView<HomeController> {
const HomePage({super.key});
#override
Widget build(BuildContext context) {
// final homeController = Get.put(HomeController());
var title = "HomePage";
return Scaffold(
body: Obx(() {
HomeController controller = Get.find<HomeController>();
return controller.regionList.isEmpty
? const Center(
child: Text('No hay regiones'),
)
: ListView.builder(
itemCount: controller.regionList.length,
itemBuilder: (context, index) => ListTile(
title: Text(
controller.regionList[index].name,
)));
}),
);
}
}
Controller
class HomeController extends GetxController {
//late Regiones model;
var regionList = <Regiones>[].obs;
Future<List<Regiones>> getRegiones() async {
var response = await rootBundle.loadString('assets/response.json');
var results = (jsonDecode(response)['regions'] ?? []) as List;
return results.map((x) => Regiones.fromJson(x)).toList();
//return Regiones.fromJson(jsonDecode(response));
}
//Json['regions'] == null ? Null :
#override
Future<void> onInit() async {
// TODO: implement onInit
super.onInit();
regionList.assignAll(await getRegiones());
}
}
Json
{
"name": "Chile",
"regions": [
{
"name": "Arica y Parinacota",
"romanNumber": "XV",
"number": "15",
"abbreviation": "AP",
"communes": [
{ "name": "Arica", "identifier": "XV-1" },
{ "name": "Camarones", "identifier": "XV-2" },
{ "name": "General Lagos", "identifier": "XV-3" },
{ "name": "Putre", "identifier": "XV-4" }
]
},
{
...
Model
Regiones regionesFromJson(String str) => Regiones.fromJson(json.decode(str));
String regionesToJson(Regiones data) => json.encode(data.toJson());
class Regiones {
Regiones({
required this.name,
required this.regions,
});
String name;
List<Region> regions;
factory Regiones.fromJson(Map<String, dynamic> json) => Regiones(
name: json["name"],
regions:
List<Region>.from(json["regions"].map((x) => Region.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"name": name,
"regions": List<dynamic>.from(regions.map((x) => x.toJson())),
};
}
class Region {
Region({
required this.name,
required this.romanNumber,
required this.number,
required this.abbreviation,
required this.communes,
});
String? name;
String? romanNumber;
String? number;
String? abbreviation;
List<Commune> communes;
factory Region.fromJson(Map<String, dynamic> json) => Region(
name: json["name"],
romanNumber: json["romanNumber"],
number: json["number"],
abbreviation: json["abbreviation"],
communes: List<Commune>.from(
json["communes"].map((x) => Commune.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"name": name,
"romanNumber": romanNumber,
"number": number,
"abbreviation": abbreviation,
"communes": List<dynamic>.from(communes.map((x) => x.toJson())),
};
}
class Commune {
Commune({
required this.name,
required this.identifier,
});
String name;
String identifier;
factory Commune.fromJson(Map<String, dynamic> json) => Commune(
name: json["name"],
identifier: json["identifier"] ?? '',
);
Map<String, dynamic> toJson() => {
"name": name,
"identifier": identifier,
};
}
You call ['regions'] in two place:
1:
var results = (jsonDecode(response)['regions'] ?? []) as List;
2: inside Regiones.fromJson
so in your HomeController instead of this:
return results.map((x) => Regiones.fromJson(x)).toList();
try this:
return results.map((x) => Region.fromJson(x)).toList();
and then make your getRegiones return Future<List> like this:
Future<List<Regione>> getRegiones() async {
...
}
Im having problems receiving data from the api, i a class and a function and a class to use the data but im getting null, i used the function from a class to the other in a FutureBuilder. When i get to the screen where the data is trying to be fetched im just getting the circular progress indicator and in the debug is saying Null is not a subtype of String, i tried looking for the problem but i couldn't fix it, the problem might be when im trying to use the function to the other class in the other file, any help would be much appreciated, if someone could implement his answer on the code i send it would be even more helpful.
class LoginData {
final String loginPhoneNumber;
final String loginPassword;
LoginData({
required this.loginPhoneNumber,
required this.loginPassword,
});
factory LoginData.fromJson(Map<String, dynamic> json) {
return LoginData(
loginPhoneNumber: json['phoneNumber'],
loginPassword: json['lastName']
);
}
}
// function
buildSwipeButton() {
return MenuPage(
sendData: fetchLoginData(),
);
}
Future<List<LoginData>> fetchLoginData() async {
var url = 'https://dev.api.wurk.skyver.co/api/employees';
String basicAuth = 'Basic ' +
base64Encode(
utf8.encode('${emailController.text}:${passwordController.text}'),
);
var response = await http.get(
Uri.parse(url),
headers: <String, String>{'authorization': basicAuth},
);
print(response.body);
if (response.statusCode == 200) {
print(response.statusCode);
List data1 = json.decode(utf8.decode(response.bodyBytes));
return data1.map((data) => LoginData.fromJson(data)).toList();
} else {
throw Exception('Failed to load LoginData');
}
}
// the other class that im trying to use the data from
class MenuPage extends StatefulWidget {
const MenuPage({Key? key, Future<List<LoginData>>? sendData, Future<List<LoginData>>? sendData2}) : super(key: key);
#override _MenuPageState createState() => _MenuPageState();
}
class _MenuPageState extends State<MenuPage> {
final _advancedDrawerController = AdvancedDrawerController();
void _handleMenuButtonPressed() {
_advancedDrawerController.showDrawer();
}
late LoginData data;
Future<LoginData>? sendData;
body: FutureBuilder<LoginData>(
future: sendData,
builder: (context, snapshot) {
if (snapshot.hasData) {
LoginData? data1 = snapshot.data;
data = data1!;
//print(data.loginPhoneNumber);
return afterLoginBody();
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return Center(child: const CircularProgressIndicator());
},
),
afterLoginBody() {
return ListView.builder(
itemCount: data.loginPhoneNumber.length,
itemBuilder: (context, index){
return ListTile(
title: Text(''),
);
});
}
}
Though your question was not completely clear as what data type you are expecting from the api. I've tried to make the future builder running on your code and now you can intrepret the response you receive from the server as your needs.
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class LoginData {
final String loginPhoneNumber;
final String loginPassword;
LoginData({
required this.loginPhoneNumber,
required this.loginPassword,
});
factory LoginData.fromJson(Map<String, dynamic> json) {
return LoginData(
loginPhoneNumber: json['phoneNumber'], loginPassword: json['lastName']);
}
}
// function
buildSwipeButton() {
return MenuPage(
sendData: fetchLoginData(),
);
}
Future<List<LoginData>> fetchLoginData() async {
var url = 'https://dev.api.wurk.skyver.co/api/employees';
String basicAuth = 'Basic ' +
base64Encode(
utf8.encode('${emailController.text}:${passwordController.text}'),
);
var response = await http.get(
Uri.parse(url),
headers: <String, String>{'authorization': basicAuth},
);
// List<Map<String,dynamic>> _dummyResponse = [
// {
// "id": "0e9ca1b9-6ef3-4e16-93e0-3b4c6c1506c3",
// "firstName": "Dibran",
// "lastName": "Krasniqi",
// "phoneNumber": "049000000",
// "idNumber": 1564654
// },
// {
// "id": "0e9ca1b9-6ef3-4e16-93e0-3b4c6c1506c5",
// "firstName": "John",
// "lastName": "Doe",
// "phoneNumber": "049123456",
// "idNumber": 65412984
// },
// {
// "id": "0e9ca1b9-6ef3-4e16-93e0-3b4c6c1506e4",
// "firstName": "Ajan",
// "lastName": "Bikliqi",
// "phoneNumber": "049105221",
// "idNumber": 456123
// }
// ];
print(response.body);
if (response.statusCode == 200) {
print(response.statusCode);
List data1 = json.decode(utf8.decode(response.bodyBytes));
return data1.map((data) => LoginData.fromJson(data)).toList();
} else {
throw Exception('Failed to load LoginData');
}
}
// the other class that im trying to use the data from
class MenuPage extends StatefulWidget {
MenuPage({
Key? key,
this.sendData,
this.sendData2,
}) : super(key: key);
Future<List<LoginData>>? sendData;
Future<List<LoginData>>? sendData2;
#override
_MenuPageState createState() => _MenuPageState();
}
class _MenuPageState extends State<MenuPage> {
// final _advancedDrawerController = AdvancedDrawerController();
// void _handleMenuButtonPressed() {
// _advancedDrawerController.showDrawer();
// }
late List<LoginData> data;
Future<LoginData>? sendData;
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<LoginData>>(
future: widget.sendData!,
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data != null) {
data = snapshot.data!;
} else {
data = [];
}
//print(data.loginPhoneNumber);
return afterLoginBody();
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return Center(child: const CircularProgressIndicator());
},
),
);
}
afterLoginBody() {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(data[index].loginPhoneNumber),
);
});
}
}
Occurs exception when I get the chapter list.
So how can I solve this problem?
Please help.
Here is my API response.
{
"success": 1,
"chapter": [
{
"chapter_id": "609cb13f497e3",
"chapter_name": "test",
"subject_id": "5e32874c714fa",
"medium_id": "5d15938aa1344",
"standard_id": "5d1594e283e1a",
"material": null,
"textbook": null,
"test_paper": null,
"test_paper_solution": null,
"subject_memory_map": null,
"active": "1"
}
]
}
The model class which I created in chapter_model.dart file.
// To parse this JSON data, do
//
// final chapterBySubjectModel = chapterBySubjectModelFromJson(jsonString);
import 'dart:convert';
ChapterBySubjectModel chapterBySubjectModelFromJson(String str) => ChapterBySubjectModel.fromJson(json.decode(str));
String chapterBySubjectModelToJson(ChapterBySubjectModel data) => json.encode(data.toJson());
class ChapterBySubjectModel {
ChapterBySubjectModel({
required this.success,
required this.chapter,
});
int success;
List<Chapter> chapter;
factory ChapterBySubjectModel.fromJson(Map<String, dynamic> json) => ChapterBySubjectModel(
success: json["success"],
chapter: List<Chapter>.from(json["chapter"].map((x) => Chapter.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"success": success,
"chapter": List<dynamic>.from(chapter.map((x) => x.toJson())),
};
}
class Chapter {
Chapter({
required this.chapterId,
required this.chapterName,
required this.subjectId,
required this.mediumId,
required this.standardId,
this.material,
this.textbook,
this.testPaper,
this.testPaperSolution,
this.subjectMemoryMap,
required this.active,
});
String chapterId;
String chapterName;
String subjectId;
String mediumId;
String standardId;
dynamic material;
dynamic textbook;
dynamic testPaper;
dynamic testPaperSolution;
dynamic subjectMemoryMap;
String active;
factory Chapter.fromJson(Map<String, dynamic> json) => Chapter(
chapterId: json["chapter_id"],
chapterName: json["chapter_name"],
subjectId: json["subject_id"],
mediumId: json["medium_id"],
standardId: json["standard_id"],
material: json["material"],
textbook: json["textbook"],
testPaper: json["test_paper"],
testPaperSolution: json["test_paper_solution"],
subjectMemoryMap: json["subject_memory_map"],
active: json["active"],
);
Map<String, dynamic> toJson() => {
"chapter_id": chapterId,
"chapter_name": chapterName,
"subject_id": subjectId,
"medium_id": mediumId,
"standard_id": standardId,
"material": material,
"textbook": textbook,
"test_paper": testPaper,
"test_paper_solution": testPaperSolution,
"subject_memory_map": subjectMemoryMap,
"active": active,
};
}
Method which i Created in api_manager.dart file.
Future<List<Chapter>> getChapterBySubject() async {
final chapterUrl =
'$baseUrl/subject/get_by_user_plan?user_id=609cab2cd5b6c&order_id=1620889722609cd07a601af469889697609cab2cd5b6c&standard_id=5d1594e283e1a&medium_id=5d15938aa1344';
final response = await http.get(Uri.parse(chapterUrl));
if (response.statusCode == 200) {
final chapterData = chapterBySubjectModelFromJson(response.body);
final List<Chapter> chapters = chapterData.chapter;
print(chapters);
return chapters;
} else {
return <Chapter>[];
}
}
And view as below in chapter_widget.dart file.
class _ChapterWidgetState extends State<ChapterWidget> {
late bool _loading;
var _chapters = <Chapter>[];
#override
void initState() {
super.initState();
_loading = true;
ApiManager().getChapterBySubject().then((chapters) {
setState(() {
_chapters = chapters;
_loading = false;
});
});
}
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: null == _chapters ? 0 : _chapters.length,
//itemCount: _chapters.length,
itemBuilder: (context, index) {
Chapter chapter = _chapters[index];
return Container(
padding: EdgeInsets.all(8),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: InkWell(
//child: Image.asset("assets/logos/listbackground.png"),
child: Text(chapter.chapterName),
),
),
),
);
});
}
}
It throws an Exception in Model Class in below line.
List<Chapter>.from(json["chapter"].map((x) => Chapter.fromJson(x))),
You set chapter as required but it seems API says it can be null. So, you should convert your parameters from required to nullable like this:
import 'dart:convert';
ChapterBySubjectModel chapterBySubjectModelFromJson(String str) => ChapterBySubjectModel.fromJson(json.decode(str));
String chapterBySubjectModelToJson(ChapterBySubjectModel data) => json.encode(data.toJson());
class ChapterBySubjectModel {
ChapterBySubjectModel({
this.success,
this.chapter,
});
int success;
List<Chapter> chapter;
factory ChapterBySubjectModel.fromJson(Map<String, dynamic> json) => ChapterBySubjectModel(
success: json["success"] == null ? null : json["success"],
chapter: json["chapter"] == null ? null : List<Chapter>.from(json["chapter"].map((x) => Chapter.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"success": success == null ? null : success,
"chapter": chapter == null ? null : List<Chapter>.from(chapter.map((x) => x)),
};
}
I want to get data of each element inside "invoices" to show but I don't know why it has a problem when I try to call "DataAllInvoice" class.
Please help me fix this problem.
Data API
{
"invoices": [
{
"id": 3,
"customer_id": 6,
"customer_name": "Nguyễn Công Phượng",
"creater_id": 2,
"creater_name": "Lê Minh Tuấn",
"create_time": "2021-05-16T10:05:43",
"total": 411107.0,
"description": "ABC",
"manager_confirm_id": 0,
"manager_confirm_name": null,
"manager_confirm_date": null,
"customer_confirm_date": null,
"status_id": 4
},
{
"id": 2,
"customer_id": 3,
"customer_name": "Nguyễn Văn A",
"creater_id": 2,
"creater_name": "Lê Minh Tuấn",
"create_time": "2021-05-14T10:05:43",
"total": 411107.0,
"description": "ABC",
"manager_confirm_id": 0,
"manager_confirm_name": null,
"manager_confirm_date": null,
"customer_confirm_date": null,
"status_id": 1
},
{
"id": 1,
"customer_id": 3,
"customer_name": "Nguyễn Văn A",
"creater_id": 2,
"creater_name": "Lê Minh Tuấn",
"create_time": "2021-05-14T09:28:43",
"total": 222220.0,
"description": "ABC",
"manager_confirm_id": 0,
"manager_confirm_name": null,
"manager_confirm_date": null,
"customer_confirm_date": null,
"status_id": 5
}
],
"total": 3
}
Class to call API
class GetInvoice{
static int statusInvoice;
createInvoice() async {
final response = await http.get(
Uri.parse("http://3.137.137.156:5000/api/rtm/v1/invoice/get-invoice?customer_id=0&pageNum=10&pageNo=1&from=%20&to=2021-05-14%2012%3A00%3A00"),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
'Accept': 'application/json',
'Authorization': 'Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIwMTIzNDU2Nzg4IiwiaWF0IjoxNjIyNjI0MjAyLCJleHAiOjE2MjMyMjkwMDJ9.zkf23Da4-TR5sVZgtXjXvczERhaNT1teeX5k-mQaKK6lbE0l28j5TwY5ZqPL252AEAaT8W1jyEUijG-rQiSu5Q',
},
);
print("Status getApi Invoice:${response.statusCode}");
statusInvoice = response.statusCode;
if (response.statusCode == 200) {
Invoice invoice = Invoice.fromJson(jsonDecode(response.body));
List<DataAllInvoice> _invoice;
for(int i=0;i < invoice.invoices.length;i++){
if(invoice.invoices[i]!=null){
Map<String,dynamic> map=invoice.invoices[i];
_invoice.add(DataAllInvoice.fromJson(map)); ****Not working here****
}
}
return _invoice;
} else {
// throw an exception.
throw Exception('Failed to load data');
}
}
Class have a problem when I try to call - DataAllInvoice class
class DataAllInvoice {
final int id, customer_id, creater_id, total, manager_confirm_id, status_id;
final String customer_name, manager_confirm_name;
final String creater_name, description;
final DateTime create_time, manager_confirm_date, customer_confirm_date;
DataAllInvoice(
{this.id,
this.customer_id,
this.creater_id,
this.total,
this.manager_confirm_id,
this.status_id,
this.customer_name,
this.manager_confirm_name,
this.creater_name,
this.description,
this.create_time,
this.manager_confirm_date,
this.customer_confirm_date
});
factory DataAllInvoice.fromJson(Map<String, dynamic> json) {
return DataAllInvoice(
id: json[" id"],
customer_id: json[" customer_id"],
creater_id: json[" creater_id"],
total: json[" total"],
manager_confirm_id: json[" manager_confirm_id"],
status_id: json[" status_id"],
customer_name: json[" customer_name"],
manager_confirm_name: json[" manager_confirm_name"],
creater_name: json[" creater_name"],
description: json[" description"],
create_time: DateTime.parse(json[" create_time"]),
manager_confirm_date: DateTime.parse(json[" manager_confirm_date"]),
customer_confirm_date: DateTime.parse(json[" customer_confirm_date"]),
);
}
}
Invoice Class
class Invoice {
final List invoices;
final int total;
Invoice({this.invoices, this.total});
factory Invoice.fromJson(Map<String, dynamic> json) {
return Invoice(
invoices: json["invoices"],
total: json["total"],
);
}
}
Try That :
So here Fetch Api Class
Sometime you gotta need to use Uri.parse() to put the URL inside it.
and you have to check the statusCode is equal 200 Otherwise there is problem.
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'DataCardFromApi.dart';
class FetchApi {
static Future<List<Articles>> fetchStory() async {
var url = Uri.parse("https://newsapi.org/v2/top-headlines?sources=techcrunch&apiKey=c5609b49c9274e89bacde5dcab5c52a2");
http.Response response = await http.get(url);
if (response.statusCode == 200) {
Map<String, dynamic> resMap = jsonDecode(response.body);
List listNews = resMap['articles'];
return listNews.map((e) => Articles.fromJson(e)).toList();
}
return null;
}
}
So the second Step :
you have to copy All Code Of Json and convert to Dart Code via This Link
You will get a code like this :
class NewsModel {
String status;
int totalResults;
List<Articles> articles;
NewsModel({this.status, this.totalResults, this.articles});
NewsModel.fromJson(Map<String, dynamic> json) {
status = json['status'];
totalResults = json['totalResults'];
if (json['articles'] != null) {
articles = new List<Articles>();
json['articles'].forEach((v) {
articles.add(new Articles.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
data['totalResults'] = this.totalResults;
if (this.articles != null) {
data['articles'] = this.articles.map((v) => v.toJson()).toList();
}
return data;
}
}
class Articles {
Source source;
String author;
String title;
String description;
String url;
String urlToImage;
String publishedAt;
String content;
Articles(
{this.source,
this.author,
this.title,
this.description,
this.url,
this.urlToImage,
this.publishedAt,
this.content});
Articles.fromJson(Map<String, dynamic> json) {
source =
json['source'] != null ? new Source.fromJson(json['source']) : null;
author = json['author'];
title = json['title'];
description = json['description'];
url = json['url'];
urlToImage = json['urlToImage'];
publishedAt = json['publishedAt'];
content = json['content'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.source != null) {
data['source'] = this.source.toJson();
}
data['author'] = this.author;
data['title'] = this.title;
data['description'] = this.description;
data['url'] = this.url;
data['urlToImage'] = this.urlToImage;
data['publishedAt'] = this.publishedAt;
data['content'] = this.content;
return data;
}
}
class Source {
String id;
String name;
Source({this.id, this.name});
Source.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
return data;
}
}
The Third step :
you have to create a Function loadData like this and after that you will put it inside initState to get data
watch this code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/StoryModel.dart';
import 'Fetch_Api.dart';
import 'New_Page.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<Articles> listModel;
#override
void initState() {
// TODO: implement initState
super.initState();
loadData() ;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(""),
actions: [
Padding(padding: EdgeInsets.only(right: 20.0),child: Icon(Icons.search_rounded))],
backgroundColor: Colors.indigo,
),
body: SafeArea(child: listModel != null ? ListView.builder(
shrinkWrap: true,
itemCount: listModel.length,
itemBuilder: (_ , index){
Articles model = listModel[index] ;
if(model.urlToImage != null)
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
InkWell(
onTap:()=> onPressCallback(model),
child: ClipRRect(
borderRadius: BorderRadius.circular(30.0),
child: Image.network(model.urlToImage,)),),
Text(model.title,style: TextStyle(fontSize: 27.0,fontWeight:FontWeight.bold),),
SizedBox(height: 20,),],
),
) ;
return SizedBox();
}) : Center(child: Text('Loading data ... ')),)
);
}
void loadData() async{
listModel = await FetchApi.fetchStory() ;
setState(() {});
}
void onPressCallback(Articles model) {
Navigator.push(context, MaterialPageRoute(builder: (_) => NewPage(model: model)));
}
}
I am trying to parse a nested JSON document in my app. The JSON structure looks like this:
[
{
"id": 1,
"content": [
{
"type": "text",
"value": "This is a Text1"
},
{
"type": "latex",
"value": "\frac00"
},
{
"type": "text",
"value": "This is a Text2"
},
{
"type": "latex",
"value": "\frac00"
},
{
"type": "text",
"value": "This is a Text3"
}
]
},
{
"id": 2,
"content": [
{
"type": "text",
"value": "This is a Text"
}
]
}
]
And here are my model classes:
class Tutorial {
String id;
List<Content> content;
Tutorial({this.id, this.content});
Tutorial.fromJson(Map<String, dynamic> json) {
id = json['id'];
if (json['content'] != null) {
content = new List<Content>();
json['content'].forEach((v) {
content.add(new Content.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
if (this.content != null) {
data['content'] = this.content.map((v) => v.toJson()).toList();
}
return data;
}
}
class Content {
String type;
String value;
Content({this.type, this.value});
Content.fromJson(Map<String, dynamic> json) {
type = json['type'];
value = json['value'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['type'] = this.type;
data['value'] = this.value;
return data;
}
}
This is how I retrieve that Json and make the response object:
import 'package:Mathzi/pages/courses/models/tutorialModel.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'dart:async' show Future;
import 'dart:convert' as convert;
class TutorialService {
Future<List> fetchTutorial() async {
var response = await rootBundle.loadString('assets/tutorial.json');
final jsonResponse = convert.jsonDecode(response) as List;
return jsonResponse.map((tutorial) => Tutorial.fromJson(tutorial)).toList();
}
}
And here are my Screen Widget tree:
final TutorialService tutorialService = TutorialService();
#override
Widget build(BuildContext context) {
return FutureProvider(
create: (context) => tutorialService.fetchTutorial(),
catchError: (context, error) => print(error.toString()),
child: SizeTransition(
axis: Axis.vertical,
sizeFactor: animation,
child: GestureDetector(
//behavior: HitTestBehavior.opaque,
onTap: onTap,
child: SizedBox(
height: 50.0,
width: MediaQuery.of(context).size.width,
child: TutParagraph()
),
),
),
);
}
And my TutParagraph.dart:
import 'package:Mathzi/pages/courses/models/tutorialModel.dart';
import 'package:catex/catex.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'models/tutorialModel.dart';
class TutParagraph extends StatelessWidget {
const TutParagraph({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
List<Content> parag = Provider.of<List<Content>>(context);
return (parag == null)
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: parag.length,
itemBuilder: (context, index) {
if (parag[index].type.toString() == "text")
return Text(parag[index].value.toString());
else if (parag[index].type.toString() == "latex")
return CaTeX(parag[index].value.toString());
else
return null;
},
);
}
}
if the type is equal to text I use a Text() widget to display it and if it is latex I use CaTex()
When I run my code it gives me this error message:
Error:
Could not find the correct Provider<List> above this
TutParagraph Widget
To fix, please:
Ensure the Provider<List> is an ancestor to this
TutParagraph Widget * Provide types to Provider<List> *
Provide types to Consumer<List> * Provide types to
Provider.of<List>() * Ensure the correct context is being
used.
The best solution is to try to cast and explicitly tell the type of object the List uses to avoid this sort of problems instead of let it infere it
class TutorialService {
Future<List<Tutorial>> fetchTutorial() async { //Tell the trturn type of the List
var response = await rootBundle.loadString('assets/tutorial.json');
final jsonResponse = convert.jsonDecode(response) as List;
return jsonResponse.map<Tutorial>((tutorial) => Tutorial.fromJson(tutorial)).toList();
//Cast the type in the map method <Tutorial>
}
}
Again in the FutureProvider
FutureProvider<List<Tutorial>>( //perhaps it can infere it correctly now that the return type explicitly says is a List<Tutorial>, but lets add it anyway just in case
create: (context) => tutorialService.fetchTutorial(),
catchError: (context, error) => print(error.toString()),
child: ...
)
And in TutParagraph
class TutParagraph extends StatelessWidget {
const TutParagraph({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
List<Tutorial> tutorial = Provider.of<List<Tutorial>>(context); //it should find the FutureProvider
List<Content> parag = (tutorial?.isEmpty ?? true) ? null : tutorial[0].content; //but this will only give you the list of the first element of the tutorial List
return (parag == null)
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: parag.length,
itemBuilder: (context, index) {
if (parag[index].type.toString() == "text")
return Text(parag[index].value.toString());
else if (parag[index].type.toString() == "latex")
return CaTeX(parag[index].value.toString());
else
return null;
},
);
}
}
Now if you want to retrieve only a List<Content> you should try to change the logic of tutorialService.fetchTutorial() to return only that type of list, because the Provider doesn't know what types are inside of Tutorial and obviously if you have a List<Tutorial> it doesn't know the List<Content> of what index of the list of Tutorial you really want