I'm trying to have 2 data responses for 2 api endpoints. 1 is a single response, and the other is an array of a single response.
When trying to create the List/array version, I get errors. What's the proper way to make the following model class into a List as well?
class SingleDataResponse {
final String id;
final String title;
SingleDataResponse({
this.id,
this.title
});
factory SingleDataResponse.fromJson(Map<String, dynamic> json) {
return SingleDataResponse(
id: json['id'],
title: json['title']
);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['title'] = this.title;
return data;
}
}
Here's what I'm expecting to get in the List Model:
[{_id: "5f210afa8215ff24307c6c53", title: "Cool Title"}]
just check out the example that I have created does this answer your question let me know.
This is the single object json
{
"_id": "5f210afa8215ff24307c6c53",
"title": "Cool Title"
}
This is the list of object:
[
{
"_id": "5f210afa8215ff24307c6c53",
"title": "Cool Title"
}
]
And this is the model class for the it I have taken the json locally.
// To parse this JSON data, do
import 'dart:convert';
// this is for single object
// final dataModel = singledataModelFromJson(jsonString);
DataModel singledataModelFromJson(String str) =>
DataModel.fromJson(json.decode(str));
String singledataModelToJson(DataModel data) => json.encode(data.toJson());
// this is for list of objects.
// final dataModel = dataModelFromJson(jsonString);
List<DataModel> dataModelFromJson(String str) =>
List<DataModel>.from(json.decode(str).map((x) => DataModel.fromJson(x)));
String dataModelToJson(List<DataModel> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class DataModel {
DataModel({
this.id,
this.title,
});
String id;
String title;
factory DataModel.fromJson(Map<String, dynamic> json) => DataModel(
id: json["_id"],
title: json["title"],
);
Map<String, dynamic> toJson() => {
"_id": id,
"title": title,
};
}
This is the logic in main:
import 'package:flutter/material.dart';
import 'package:json_parsing_example/models.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: HomePage());
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
double value;
#override
void initState() {
super.initState();
getdata();
}
getdata() async {
String data =
await DefaultAssetBundle.of(context).loadString("json/parse.json");
final singledataModel = singledataModelFromJson(data);
print('single model');
print(singledataModel.id);
print(singledataModel.title);
String listdata =
await DefaultAssetBundle.of(context).loadString("json/parse2.json");
List<DataModel> dataModel = dataModelFromJson(listdata);
print(dataModel.length);
print(dataModel[0].title);
}
#override
Widget build(BuildContext context) {
return Scaffold(body: Text(''));
}
}
Just check it and let me know if this is what you want.
Related
I got a flutter error A value of type 'Iterable<HospitalListModel>' can't be assigned to a variable of type 'List<HospitalListModel>'. This is my model:
List<HospitalListModel> hospitalListModelFromJson(String str) => List<HospitalListModel>.from(json.decode(str).map((x) => HospitalListModel.fromJson(x)));
String hospitalListModelToJson(List<HospitalListModel> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class HospitalListModel {
HospitalListModel({
this.id,
this.title,
this.content,
this.image,
this.phone,
this.coordinates,
this.website,
this.createdAt,
this.updatedAt,
});
dynamic id;
dynamic title;
dynamic content;
dynamic image;
dynamic phone;
dynamic coordinates;
dynamic website;
dynamic createdAt;
dynamic updatedAt;
factory HospitalListModel.fromJson(Map<String, dynamic> json) => HospitalListModel(
id: json["id"],
title: json["title"],
content: json["content"],
image: json["image"],
phone: json["phone"],
coordinates: json["coordinates"],
website: json["website"],
createdAt: json["created_at"],
updatedAt: json["updated_at"],
);
Map<String, dynamic> toJson() => {
"id": id,
"title": title,
"content": content,
"image": image,
"phone": phone,
"coordinates": coordinates,
"website": website,
"created_at": createdAt.toIso8601String(),
"updated_at": updatedAt.toIso8601String(),
};
}
and this is where the error come from, it's from the API provider and im confused why it throw iterable
class ApiProvider {
final Dio _dio = Dio();
final String _url = 'http://lovemonster.my.id/hospital';
Future<List<HospitalListModel>> fetchHospitalList() async {
try {
List<HospitalListModel> hospitalList = [];
Response response = await _dio.get(_url);
var mData = response.data as List;
hospitalList = mData.
map<HospitalListModel>((e) => hospitalListModelFromJson(e)
.toList();
return hospitalList;//return List not object
} catch (error, stacktrace) {
print("Exception occurred: $error stackTrace: $stacktrace");
return Future.error("");
}
}
}
hospitalList = mData.map<HospitalListModel>((e) =>hospitalListModelFromJson(e).toList();this code throw an error, and if you wondering how the other class or method, i will put event & state that seems related to the error:
state:
abstract class HospitalListState extends Equatable {
const HospitalListState();
#override
List<Object?> get props => [];
}
class HospitalListInitial extends HospitalListState {}
class HospitalListLoading extends HospitalListState {}
class HospitalListLoaded extends HospitalListState {
final List<HospitalListModel> hospitalListModel;
const HospitalListLoaded(this.hospitalListModel);
}
class HospitalListError extends HospitalListState {
final String? message;
const HospitalListError(this.message);
}
event:
abstract class HospitalListEvent extends Equatable {
const HospitalListEvent();
#override
List<Object> get props => [];
}
class GetCovidList extends HospitalListEvent {}
i made this code with flutter_bloc and if you want to know more details just let me know, and if you know what's wrong with my code, just type it on the answer, i appreciate every answers and knowledge that you share with me
You have missed ')' before using toList method you have close the map method.
hospitalList = mData.map<HospitalListModel>((e) => hospitalListModelFromJson(e))
.toList();
I have an array of elements that come from api and I get and error from api =>
The operator '[]' isn't defined for the type of 'Country'
Response from api looks like this:
{"success":true,"list":[{"id":2,"createdAt":"2022-11-11T15:25:31.680Z","updatedAt":"2022-11-11T15:25:31.680Z","name":"Afghanistan"}]}
This is the type of an element inside list:
class Country {
final int id;
final String createdAt;
final String updatedAt;
final String name;
const Country({
required this.id,
required this.createdAt,
required this.updatedAt,
required this.name
});
}
This is my widget:
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
List<Country> countries = [];
Future<void> getCountries() async {
try {
final response = await _apiService.getCountries();
countries = response['list']; // [{"id": 2, "createdAt:""...}]
} catch (e) {
log(e.toString());
rethrow;
}
}
#override
void initState() {
getCountries();
super.initState();
}
#override
Widget build(BuildContext context) {
return Container();
}
}
And if I try to call this, IDE lights me this error in country['name'] =>
final List countriesWithNames = countries.map((country) => country['name']).toList();
Or when I try to get an element from the list, like this => countries[index]['name']
response['list'] returns list of map.You need to convert into model class.
You can use this model class
class Country {
final int id;
final String createdAt;
final String updatedAt;
final String name;
const Country({
required this.id,
required this.createdAt,
required this.updatedAt,
required this.name,
});
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
result.addAll({'id': id});
result.addAll({'createdAt': createdAt});
result.addAll({'updatedAt': updatedAt});
result.addAll({'name': name});
return result;
}
factory Country.fromMap(Map<String, dynamic> map) {
return Country(
id: map['id']?.toInt() ?? 0,
createdAt: map['createdAt'] ?? '',
updatedAt: map['updatedAt'] ?? '',
name: map['name'] ?? '',
);
}
String toJson() => json.encode(toMap());
factory Country.fromJson(String source) =>
Country.fromMap(json.decode(source));
}
And getting from local json string
final data = response["list"] as List?;
List<Country> countries =
data?.map((e) => Country.fromMap(e)).toList() ?? [];
print(countries);
I've been having this problem when trying to connect API's in flutter. I'm not sure if this is a problem of not receiving the data or if there is an error in my code, any hekp would be greatly appreciated.
This is the code I have on the page
import 'package:ctrade/models/newsinfo.dart';
import 'package:ctrade/services/api_manager.dart';
import 'package:flutter/material.dart';
class PostsPage extends StatefulWidget {
const PostsPage({ Key? key }) : super(key: key);
#override
State<PostsPage> createState() => _PostsPageState();
}
class _PostsPageState extends State<PostsPage> {
late Future<Welcome> _Welcome; //error here
#override
void initState() {
_Welcome = API_Manager().getNews();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold (
appBar: AppBar(
title: Text('News App'),
),
body: Container(
child: FutureBuilder<Welcome>(
future: _Welcome,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
itemCount: 52,
itemBuilder:(context, index) {
var ticker = snapshot.data!.ticker[index];
return Container(
height: 100,
child: Row(
children: [
//Text(ticker)
],
),
);
});
}
else
return Center(child: CircularProgressIndicator());
},
),
)
);
}
}
This is the code on my API manager file (I defined the news_url in a different file)
import 'package:ctrade/constants/strings.dart';
import 'package:ctrade/models/newsinfo.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class API_Manager {
Future<Welcome> getNews() async{
var client = http.Client();
var Welcome;
try{
var response = await client.get(Uri.parse(Strings.news_url));
if(response.statusCode == 200) {
var jsonString = response.body;
var jsonMap = json.decode(jsonString);
Welcome = Welcome.fromJson(jsonMap);
}
}
catch(Exception)
{
return Welcome;
}
return Welcome;
}
}
This is the file with the parsed json
// To parse this JSON data, do
//
// final welcome = welcomeFromJson(jsonString);
import 'dart:convert';
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())));
class Welcome {
Welcome({
required this.id,
required this.ticker,
required this.isin,
required this.bestAsk,
required this.bestBid,
required this.currentPrice,
required this.askVolume,
required this.bidVolume,
required this.fullCompanyName,
required this.prevPrice,
required this.prevPer,
required this.prevChange,
});
int id;
String ticker;
String isin;
String bestAsk;
String bestBid;
String currentPrice;
String askVolume;
String bidVolume;
String fullCompanyName;
String prevPrice;
String prevPer;
String prevChange;
factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
id: json["id"],
ticker: json["Ticker"],
isin: json["ISIN"],
bestAsk: json["Best_Ask"],
bestBid: json["Best_bid"],
currentPrice: json["Current_price"],
askVolume: json["Ask_Volume"],
bidVolume: json["Bid_Volume"],
fullCompanyName: json["FullCompanyName"],
prevPrice: json["PrevPrice"],
prevPer: json["PrevPer"],
prevChange: json["PrevChange"],
);
Map<String, dynamic> toJson() => {
"id": id,
"Ticker": ticker,
"ISIN": isin,
"Best_Ask": bestAsk,
"Best_bid": bestBid,
"Current_price": currentPrice,
"Ask_Volume": askVolume,
"Bid_Volume": bidVolume,
"FullCompanyName": fullCompanyName,
"PrevPrice": prevPrice,
"PrevPer": prevPer,
"PrevChange": prevChange,
};
}
class Welcome {
Welcome({
required this.id,
required this.ticker,
required this.isin,
required this.bestAsk,
required this.bestBid,
required this.currentPrice,
required this.askVolume,
required this.bidVolume,
required this.fullCompanyName,
required this.prevPrice,
required this.prevPer,
required this.prevChange,
});
int? id;
String? ticker;
String? isin;
String? bestAsk;
String? bestBid;
String? currentPrice;
String? askVolume;
String? bidVolume;
String? fullCompanyName;
String? prevPrice;
String? prevPer;
String? prevChange;
factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
id: json["id"]??"",
ticker: json["Ticker"]??"",
isin: json["ISIN"]??"",
bestAsk: json["Best_Ask"]??"",
bestBid: json["Best_bid"]??"",
currentPrice: json["Current_price"]??"",
askVolume: json["Ask_Volume"]??"",
bidVolume: json["Bid_Volume"]??"",
fullCompanyName: json["FullCompanyName"]??"",
prevPrice: json["PrevPrice"]??"",
prevPer: json["PrevPer"]??"",
prevChange: json["PrevChange"]??"",
);
Map<String, dynamic> toJson() => {
"id": id,
"Ticker": ticker,
"ISIN": isin,
"Best_Ask": bestAsk,
"Best_bid": bestBid,
"Current_price": currentPrice,
"Ask_Volume": askVolume,
"Bid_Volume": bidVolume,
"FullCompanyName": fullCompanyName,
"PrevPrice": prevPrice,
"PrevPer": prevPer,
"PrevChange": prevChange,
};
}
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Home(),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
Future<List<Products>> getApiData() async {
var url = "https://gorest.co.in/public-api/products";
var response = await http.get(url);
var jsonString = response.body;
List<Products> products = productsFromJson(jsonString);
print(jsonString);
return products;
}
why it doesn't work,
[A value of type 'Products' can't be assigned to a variable of type 'List'.
Try changing the type of the variable, or casting the right-hand type to 'List'.;][1]
[1]: https://i.stack.imgur.com/MQCEP.png
json to dart file
A value of type 'Products' can't be assigned to a variable of type 'List'.
Try changing the type of the variable,dart(invalid_assignment)
Products productsFromJson(String str) =>
Products.fromJson(json.decode(str));
String productsToJson(Products data) => json.encode(data.toJson());
class Products {
Products({
this.code,
this.meta,
this.data,
});
int code;
Meta meta;
List<Datum> data;
factory Products.fromJson(Map<String, dynamic> json) => Products(
code: json["code"],
meta: Meta.fromJson(json["meta"]),
data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"code": code,
"meta": meta.toJson(),
"data": List<dynamic>.from(data.map((x) => x.toJson())),
};
}
class Datum {
Datum({
this.id,
this.name,
this.description,
this.image,
this.price,
this.discountAmount,
this.status,
this.categories,
});
int id;
String name;
String description;
String image;
String price;
String discountAmount;
bool status;
List<Category> categories;
var url = "https://gorest.co.in/public-api/products";
var response = await http.get(url);
var jsonString = jsonDecode(response.body);
List<Products> products = jsonString.map((jsonMap) => Products.fromJson(jsonMap)).toList();
If you need to return all products as list, you can use like this.
You created a Modle class for Products, so productsFromJson(jsonString) return a Products response.
but you try to put the API response to List variable, and then it causes an error.
change your API call by below code it will work fine.
Future<Products> getApiData() async {
var url = "https://gorest.co.in/public-api/products";
var response = await http.get(url);
var jsonString = response.body;
Products products = productsFromJson(jsonString);
print(jsonString);
return products;
}
Hi I need to use polymorphism in flutter to use it in get data from Restfull API
but it doesn't work.
first I have a base class (Model)
class Model
{
Model();
Model.fromJson(Map<String, dynamic> json) ;
Map<String, dynamic> toJson(){}
}
then I have derived class (City)
class City extends Model {
int id;
String name;
List<Region> regions;
City({this.id, this.name, this.regions});
City.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
if (json['regions'] != null) {
regions = new List<Region>();
json['regions'].forEach((v) {
regions.add(new Region.fromJson(v));
});
}
}
}
and this is a function with getAllModel method
class Repository
{
static Future<List<T>> getAllModel<T extends Model>( apis url) async {
try {
bool tk = await Cache.tokenExists();
if (tk) {
String token = await Cache.getString(keys.api_token);
var body = {};
List<dynamic> data = await Request.callAPI(
apiName.name(url),
body,
method: 'GET', apiToken: token);
List<T> objs = new List();
if (data != null) if (data.length > 0) {
data.forEach((v) {
T r = Model.fromJson(v) as T;
objs.add(r);
});
return objs;
}
return objs;
}
return new List();
} catch (e, stacktrace) {
print("getAll() | catch exception");
print(e);
print(stacktrace);
return new List();
}
}
}
finally this is a call method
static Future<List<City>> getCities() async {
return Repository.getAllModel(apis.getCities);
}
this is a problem
type 'Model' is not a subtype of type 'City' in type cast
How can I solve this ?
Model.fromJson(v) will always return a value of the base type, Model.
You can't cast this to T = City here:
T r = Model.fromJson(v) as T;
because Dart can't know how to turn a Model into a City.
You would want to call “T.fromJson(v)”, so to speak, but Dart doesn't allow us to speak polymorphically about constructors.
I think your best bet might be to pass the relevant fromJson function along to getAllModel:
// The type of functions that take a JSON map and return T.
typedef JsonDecoder<T> = T Function(Map<String, dynamic> json);
// Use a provided `fromJson` callback to transform your API results:
Future<List<T>> getAllModel<T extends Model>(String url,
JsonDecoder<T> fromJson) async {
...
T r = fromJson(v);
...
}
// And provide it like so:
void myFunction() {
final cities = await getAllModel<City>("city url", (j) => City.fromJson(j));
}
(Somewhat annoyingly, we can't even write this:)
getAllModel<City>("city url", City.fromJson);
^^^^^^^^^^^^^
By the way, I recommend looking into json_serializable.
Here is an aproach i am thinking of taking to render different components returned from a REST api (strapi)
I want to render the components based on type from a response like this
{
"data": {
"id": 1,
"homepage": [
{
"id": 1,
"__component": "explore.search",
"enabled": true,
"include_articles": true,
"include_menu_entries": true,
"include_contributors": true
},
{
"id": 1,
"__component": "explore.whats-new",
"entry_count": 7
}
]
},
"meta": {}
}
I created a base component model like this to capture the common parameters to be extended by each component model later
class CmsComponent {
CmsComponent({
required this.id,
required this.component,
});
int id;
String component;
factory CmsComponent.fromJson(Map<String, dynamic> json) => CmsComponent(
id: json["id"],
component: json["__component"],
);
Map<String, dynamic> toJson() => {
"id": id,
"__component": component,
};
}
then an example of a single component model is
class CmsComponentSearch extends CmsComponent{
CmsComponentSearch({
required id,
required component,
required this.enabled,
required this.includeArticles,
required this.includeMenuEntries,
required this.includeContributors,
}) : super(id: id, component: component);
bool enabled;
bool includeArticles;
bool includeMenuEntries;
bool includeContributors;
factory CmsComponentSearch.fromJson(Map<String, dynamic> json) => CmsComponentSearch(
id: json["id"],
component: json["__component"],
enabled: json["enabled"],
includeArticles: json["include_articles"],
includeMenuEntries: json["include_menu_entries"],
includeContributors: json["include_contributors"],
);
Map<String, dynamic> toJson() => {
"id": id,
"__component": component,
"enabled": enabled,
"include_articles": includeArticles,
"include_menu_entries": includeMenuEntries,
"include_contributors": includeContributors,
};
}
then at the top level i can create this model with a method to switch out each components model as needed
class CmsExploreHome {
CmsExploreHome({
required this.id,
required this.components,
});
int id;
List<dynamic> components;
factory CmsExploreHome.fromJson(Map<String, dynamic> json) => CmsExploreHome(
id: json["id"],
components: List<dynamic>.from(json["homepage"].map((x) => getCmsComponentModelFromJson(x))),
);
Map<String, dynamic> toJson() => {
"id": id,
"homepage": List<dynamic>.from(components.map((x) => x.toJson())),
};
}
getCmsComponentModelFromJson(Map<String, dynamic> json) {
switch(json['__component']) {
case 'explore.search' : return CmsComponentSearch.fromJson(json);
case 'explore.whats-new' : return CmsComponentWhatsNew.fromJson(json);
default : return CmsComponent.fromJson(json);
}
}
Thats the data modelling done, then in the UI widget i can do something like this
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('explore'),
for (var component in exploreProvider.cmsExploreHome!.components) _RenderComponent(component),
],
),
and add the following widgets
class _RenderComponent extends StatelessWidget {
const _RenderComponent(this.component, {Key? key}) : super(key: key);
final CmsComponent component;
#override
Widget build(BuildContext context) {
if(component is CmsComponentSearch) return CmsSearchComponent(component as CmsComponentSearch);
return Text("${component.component} not implemented");
}
}
and for example
class CmsSearchComponent extends StatelessWidget {
const CmsSearchComponent(this.component, {Key? key}) : super(key: key);
final CmsComponentSearch component;
#override
Widget build(BuildContext context) {
return Text("Search field");
}
}
That gets the job done, the flutter app can receive dynamic types from the REST api in a list and render them