I am trying to understand how to work with Json in Flutter/Dart.
I want to read a local Json from the assets folder and display it on the screen.
I have in the assets folder the following Json
{
"title": [
{
"number": 8,
"firstarray": [
26.6, 27, 26.6, 22.9, 27.1, 26.8,
],
"secondarray": [
26.6, 27, 26.6, 22.9, 27.1, 26.8,
]
},
{
"number": 9,
"firstarray": [
26.6, 27, 26.6, 22.9, 27.1, 26.8,
],
"secondarray": [
26.6, 27, 26.6, 22.9, 27.1, 26.8,
]
}
]
}
I tried to created a Class "DataModel" to be able to read from JSON file.
class DataModel {
DataModel({this.measure});
List<DataTitle>? measure;
factory DataModel.fromJson(Map<String, dynamic> json) {
return DataModel(
measure: List<DataTitle>.from(
json['title'].map((c) => DataTitle.fromJson(c)).toList()),
);
}
}
class DataTitle {
DataTitle(
{required this.number,
required this.firstarray,
required this.secondarray});
int? number;
List<double>? firstarray;
List<double>? secondarray;
DataTitle.fromJson(Map<String, dynamic> json) {
number = json['number'];
firstarray = json['firstarray'] == null
? []
: List<double>.from(json['firstarray'].map((x) => x.toDouble()));
secondarray = json['secondarray'] == null
? []
: List<double>.from(json['secondarray'].map((x) => x.toDouble()));
}
}
and I am trying to read and print to the console as follows.
Future loadData() async {
String jsonString = await _loadData();
final jsonResponse = json.decode(jsonString);
DataTitle measure = DataTitle.fromJson(jsonResponse);
print('${measure.number} - ${measure.firstarray} - ${measure.secondarray}');
}
I get at the console printed out,
flutter: null - [] - []
but i was expecting
flutter: 8 - 26.6, 27, 26.6, 22.9, 27.1, 26.8 - 26.6, 27, 26.6, 22.9, 27.1, 26.8,
Updated part:
You tried to convert the whole json structure to an object of your DataModel class. However, in your json, only the list which is under the title node contains DataModelobjects.
Please check the loadData function below, where I first extract the list out of the title node and then make one DataModel object for each element in the list.
class DataModel {
DataModel({this.measure});
List<DataTitle>? measure;
factory DataModel.fromJson(Map<String, dynamic> json) {
return DataModel(
measure: List<DataTitle>.from(
json['title'].map((c) => DataTitle.fromJson(c)).toList()),
);
}
}
class DataTitle {
DataTitle(
{required this.number,
required this.firstarray,
required this.secondarray});
int? number;
List<double>? firstarray;
List<double>? secondarray;
DataTitle.fromJson(Map<String, dynamic> json) {
number = json['number'];
firstarray = json['firstarray'] == null
? []
: List<double>.from(json['firstarray'].map((x) => x.toDouble()));
secondarray = json['secondarray'] == null
? []
: List<double>.from(json['secondarray'].map((x) => x.toDouble()));
}
#override
String toString() {
return 'DataTitle{number: $number, firstarray: $firstarray, secondarray: $secondarray}';
}
}
Future loadData() async {
final jsonString = await rootBundle.loadString('assets/data.json');
final decodedJson = json.decode(jsonString);
List<DataTitle> dataTileList= (decodedJson ['title'] as List)
.map((jsonElement) => DataTitle.fromJson(jsonElement))
.toList();
print(dataTileList.first);
print(dataTileList.last);
}
Original Answer
In your code your json data example does not match the way you try to read it. You provide a single element but you try to read a list of elements.
If the json data contains a single element
Your json structure is of type Map<String, dynamic> so this is the data type which json.decode returns (or you also use the method jsonDecode from import 'dart:convert';).
You then try to cast this Map to List<dynamic>which obviously fails.
Instead, the first part should look like this:
final jsonString =
await rootBundle.rootBundle.loadString('assets/measurelist.json');
final json = json.decode(jsonString) as Map<String, dynamic>;
Afterwards you need to call the fromJsonmethod of your data model class.
In your example you try to use map to create one object for each element in the json array. However, in your example json you only have one object which is not part of an array. So that map doesn't make sense.
What should work is directly calling the fromJson method on the single data element you provide, like:
return DataModel.fromJson(json);
Putting all together, your method should look like this:
Future<DataModel> readJsonData() async {
final jsonString =
await rootBundle.rootBundle.loadString('assets/measurelist.json');
final json = json.decode(jsonString) as Map<String, dynamic>;
return DataModel.fromJson(json);
}
If the json data contains a list of elements
If your datamodel actually contains a list of elements, the json data would look something like this:
[
{
"title": [
{
"number": 8,
"firstarray": [
26.6, 27, 26.6, 2, 27.1, 26.8, 26.6, 26.8, 26.8, 27.2, 26.9, 0, 26.8,
26.8, 26.9, 0, 27.1, 26.8, 27.2, 26.7
],
"secondarray": [
0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 6.4, 6.4, 2.1, 2, 0, 0, 2, 0, 0, 6.3
]
}
]
},
{
"title": [
{
"number": 9,
"firstarray": [
26.6, 27, 26.6, 2, 27.1, 26.8, 26.6, 26.8, 26.8, 27.2, 26.9, 0, 26.8,
26.8, 26.9, 0, 27.1, 26.8, 27.2, 26.7
],
"secondarray": [
0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 6.4, 6.4, 2.1, 2, 0, 0, 2, 0, 0, 6.3
]
}
]
},
...
]
Then your method for parsing it should look something like this:
Future<List<DataModel>> readJsonData() async {
final jsonString =
await rootBundle.rootBundle.loadString('assets/measurelist.json');
final listOfJsonElements = json.decode(jsonString) as List;
return listOfJsonElements.map((jsonElement) => DataModel.fromJson(jsonElement)).toList();
}
Fix your model and future void:
DataModel
class DataModel {
List<Title>? title;
DataModel({this.title});
DataModel.fromJson(Map<String, dynamic> json) {
if (json['title'] != null) {
title = <Title>[];
json['title'].forEach((v) {
title!.add(new Title.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.title != null) {
data['title'] = this.title!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Title {
int? number;
List<double>? firstarray;
List<int>? secondarray;
Title({this.number, this.firstarray, this.secondarray});
Title.fromJson(Map<String, dynamic> json) {
number = json['number'];
firstarray = json['firstarray'].cast<double>();
secondarray = json['secondarray'].cast<int>();
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['number'] = this.number;
data['firstarray'] = this.firstarray;
data['secondarray'] = this.secondarray;
return data;
}
}
Function
Future<DataModel> readJsonData() async {
final jsondata = await rootBundle.loadString('assets/measurelist.json');
final list = json.decode(jsondata) as Map<String, dynamic> ;
DataModel res = DataModel.fromJson(list);
return res;
}
Related
I have 2 things I want to compare and return a list of Strings for each of the matching Ids with the corresponding names. Example: I have a list of "genre_ids": [16, 878, 28] from a movie, and from another API I get a list of objects with id and name of the genres, { "id": 878, "name": "Science Fiction" }. Now I want to compare the list of genre_ids with the list of objects with ids and names and return a List of names with all the matching Ids. How do I do that? I tried using the .where() option but failed miserably.
JSON from genre list:
{
"genres": [
{
"id": 28,
"name": "Action"
},
{
"id": 12,
"name": "Adventure"
},
{
"id": 16,
"name": "Animation"
},
{
"id": 35,
"name": "Comedy"
},
{
"id": 10749,
"name": "Romance"
},
{
"id": 878,
"name": "Science Fiction"
},
]
}
JSON from movie list:
"results": [
{
"adult": false,
"genre_ids": [
16,
878,
28
],
"id": 610150,
"release_date": "2022-06-11",
"title": "Dragon Ball Super: Super Hero",
"vote_average": 7.5,
"vote_count": 126
},
]
Both models from the APIs:
class Movies {
int? id;
String? title;
String? overview;
List<dynamic>? genreIds;
dynamic voteAverage;
String? posterPath;
Movies({
this.id,
this.title,
this.overview,
this.genreIds,
this.voteAverage,
this.posterPath,
});
Movies.fromJson(Map<String, dynamic> json) {
id = json['id'];
title = json['title'];
overview = json['overview'];
genreIds = json['genre_ids'].toList();
voteAverage = json['vote_average'];
posterPath = json['poster_path'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = Map<String, dynamic>();
data['id'] = id;
data['title'] = title;
data['overview'] = overview;
data['vote_average'] = voteAverage;
data['genre_ids'] = genreIds;
data['poster_path'] = posterPath;
return data;
}
}
class Genres {
int? id;
String? name;
Genres({
this.id,
this.name,
});
Genres.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'] as String;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = Map<String, dynamic>();
data['id'] = id;
data['name'] = name;
return data;
}
}
API calls:
Future<List<Movies?>> getAllMovies() async {
Response response = await Dio().get(Contants().moviesUrl);
return (response.data['results'] as List).map((movies) {
return Movies.fromJson(genres);
}).toList();
}
Future<List<Genres?>> getAllGenres() async {
Response response = await Dio().get(Contants().genresUrl);
return (response.data['genres'] as List).map((genres) {
return Genres.fromJson(genres);
}).toList();
}
Future builder:
FutureBuilder(
future: Future.wait([
RepositoryFromAPItoDB().gettAllMovies(),
RepositoryFromAPItoDB().getAllGenres()
]),
builder:
(BuildContext context, AsyncSnapshot<List<dynamic>?> snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
return ListView.builder(
itemCount: snapshot.data?[0].length,
itemBuilder: (BuildContext context, int index) {
return MoviesListTile(
title: snapshot.data?[0][index].title,
voteAverage: snapshot.data?[0][index].voteAverage,
description: snapshot.data?[0][index].overview,
posterPath: snapshot.data?[0][index].posterPath,
genreIds: snapshot.data?[0][index].genreIds,
genres: ['drama', 'somehting'],
);
},
);
}
},
),
Requested output of names from the list:
Widget getTextWidgets(List<String?> strings) {
return Row(
children: strings
.map((item) => Container(
child: Text(
item!,
),
),
),
)
.toList());
}
Any form of help is appreciated.
Is this what you wanted?
void main() {
Map<String, dynamic> genres = {
"genres": [
{"id": 28, "name": "Action"},
{"id": 12, "name": "Adventure"},
{"id": 16, "name": "Animation"},
{"id": 35, "name": "Comedy"},
{"id": 10749, "name": "Romance"},
{"id": 878, "name": "Science Fiction"},
]
};
Map<String, dynamic> movie = {
"adult": false,
"genre_ids": [16, 878, 28],
"id": 610150,
"release_date": "2022-06-11",
"title": "Dragon Ball Super: Super Hero",
"vote_average": 7.5,
"vote_count": 126
};
print(getGenres(movie, genres["genres"]));
}
List getGenres(Map movie, List genres) {
final Set movieGenreIds = Set.from(movie["genre_ids"]);
return genres
.where((g) => movieGenreIds.contains(g["id"]))
.map((g) => g["name"])
.toList();
}
The output:
[Action, Animation, Science Fiction]
Edit, using the models you provided.
List getGenres(Movie movie, List<Genre> genres) {
final Set movieGenreIds = Set.from(movie.genreIds);
return genres
.where((g) => movieGenreIds.contains(g.id))
.map((g) => g.name)
.toList();
}
I am trying to map a json list in my application using JSON Serializable. But I am not able to map it.
Following is the response from the API:
{
"code": 200,
"message": "Countries Lists",
"count": 250,
"data": [
{
"id": 1,
"name": "Afghanistan"
},
{
"id": 2,
"name": "Aland Islands"
},
{
"id": 3,
"name": "Albania"
},
{
"id": 4,
"name": "Algeria"
},
{
"id": 5,
"name": "American Samoa"
},
{
"id": 6,
"name": "Andorra"
},
{
"id": 7,
"name": "Angola"
},
{
"id": 8,
"name": "Anguilla"
},
{
"id": 9,
"name": "Antarctica"
},
{
"id": 10,
"name": "Antigua And Barbuda"
},
{
"id": 11,
"name": "Argentina"
},
{
"id": 12,
"name": "Armenia"
},
{
"id": 13,
"name": "Aruba"
},
{
"id": 14,
"name": "Australia"
},
{
"id": 15,
"name": "Austria"
},
{
"id": 16,
"name": "Azerbaijan"
},
{
"id": 17,
"name": "Bahamas The"
},
{
"id": 18,
"name": "Bahrain"
},
{
"id": 19,
"name": "Bangladesh"
},
{
"id": 20,
"name": "Barbados"
}
]
}
Following is my response file:
#JsonSerializable()
class BaseResponse {
#JsonKey(name: "code")
int? status;
#JsonKey(name: "message")
String? message;
}
#JsonSerializable(explicitToJson: true)
class AllCountryResponse extends BaseResponse {
#JsonKey(name: "data")
List<CountryResponse> data;
AllCountryResponse(this.data);
//from JSON
factory AllCountryResponse.fromJson(Map<String, dynamic> json) =>
_$AllCountryResponseFromJson(json);
//to JSON
Map<String, dynamic> toJson() => _$AllCountryResponseToJson(this);
}
#JsonSerializable()
class CountryResponse {
#JsonKey(name: "id")
String? id;
#JsonKey(name: "name")
String? name;
CountryResponse(this.id, this.name);
//from JSON
factory CountryResponse.fromJson(Map<String, dynamic> json) =>
_$CountryResponseFromJson(json);
//to JSON
Map<String, dynamic> toJson() => _$CountryResponseToJson(this);
}
I am able to generate the responses.g dart file.
Following is my mapper class file:
class Countries {
String id,name;
Countries(this.id,this.name);
}
class AllCountries{
List<Countries> countries;
AllCountries(this.countries);
}
extension CountryResponseMapper on CountryResponse? {
Countries toDomain() {
return Countries(
this?.id.orEmpty() ?? EMPTY, this?.name.orEmpty() ?? EMPTY);
}
}
extension AllCountriesResponseMapper on AllCountryResponse? {
AllCountries toDomain() {
return AllCountries(this?.data.map((e) => e.toDomain()).toList() ?? []);
}
}
Once I run my api I do get 200 status while using my bio, but after that it shows me the default error I have set, i.e. "Something went wrong". Which means there is an issue in mapping the response.
Can someone help me with mapping this list please?
This code should work.
This code is generated by a very small and simple script (which was written in a few minutes).
class Response {
Response(
{required this.code,
required this.message,
required this.count,
required this.data});
factory Response.fromJson(Map json) {
return Response(
code: json['code'] as int?,
message: json['message'] as String?,
count: json['count'] as int?,
data: json['data'] == null
? []
: (json['data'] as List).map((e) => Data.fromJson(e as Map)).toList(),
);
}
final int? code;
final String? message;
final int? count;
final List<Data> data;
static List<Response> fromJsonList(List json) {
return json.map((e) => Response.fromJson(e as Map)).toList();
}
Map<String, dynamic> toJson() {
return {
'code': code,
'message': message,
'count': count,
'data': data.map((e) => e.toJson()).toList(),
};
}
static List<Map<String, dynamic>> toJsonList(List<Response> list) {
return list.map((e) => e.toJson()).toList();
}
}
class Data {
Data({required this.id, required this.name});
factory Data.fromJson(Map json) {
return Data(
id: json['id'] == null ? 0 : json['id'] as int,
name: json['name'] == null ? '' : json['name'] as String,
);
}
final int id;
final String name;
static List<Data> fromJsonList(List json) {
return json.map((e) => Data.fromJson(e as Map)).toList();
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
};
}
static List<Map<String, dynamic>> toJsonList(List<Data> list) {
return list.map((e) => e.toJson()).toList();
}
}
Code generation script:
import 'dart:io';
import 'package:object_serializer/json_serializer_generator.dart';
import 'package:yaml/yaml.dart';
void main() {
final classes = loadYaml(_classes) as Map;
final g = JsonSerializerGenerator();
final classesCode = g.generateClasses(classes);
final values = {
'classes': classesCode,
};
var source = g.render(_template, values);
source = g.format(source);
File('bin/stackoverflow.dart').writeAsStringSync(source);
}
const _classes = r'''
Response:
fields:
code: int?
message: String?
count: int?
data: List<Data>
Data:
fields:
id: int
name: String
''';
const _template = r'''
{{classes}}
''';
So... I got this One Call Api which also includes forecast for 7 days. I managed to get display the current weather (temp, and icon) but how do I get the forecast for the next 4 days?
My API: https://api.openweathermap.org/data/2.5/onecall?lat=lat&lon=lon&exclude=minutely,hourly,alerts&cnt=4&appid={MyKey}&units=metric
My model:
class CurrentWeatherModel {
final WeatherInfo weatherInfo;
final double temp;
const CurrentWeatherModel({
required this.weatherInfo, required this.temp
});
factory CurrentWeatherModel.fromJson(json){
return CurrentWeatherModel(
weatherInfo: WeatherInfo.fromJson(json['weather'][0]),
temp: json['temp'],
);
}
}
class HourlyWeatherModel {
final double temp;
final WeatherInfo weatherInfo;
const HourlyWeatherModel(
{
required this.temp,
required this.weatherInfo
}
);
factory HourlyWeatherModel.fromJson(json){
return HourlyWeatherModel(
temp: json['temp'],
weatherInfo: WeatherInfo.fromJson(json['weather'][0])
);
}
}
class DailyWeatherInfoModel {
final TempModel dailyTemp;
final WeatherInfo weatherInfo;
final DateTime date;
final int dt;
const DailyWeatherInfoModel(
{
required this.dailyTemp,
required this.weatherInfo,
required this.date,
required this.dt,
}
);
factory DailyWeatherInfoModel.fromJson(json){
return DailyWeatherInfoModel(
dailyTemp: TempModel.fromJson(json['temp']),
dt: json['dt'],
date: DateTime.fromMillisecondsSinceEpoch(json['dt'] * 1000,
isUtc: true),
weatherInfo: WeatherInfo.fromJson(json['weather'][0]),
);
}
}
class TempModel {
final double day;
final double min;
final double max;
const TempModel(
{
required this.day,
required this.min,
required this.max
}
);
factory TempModel.fromJson(json){
return TempModel(
day: json['day'],
min: json['min'],
max: json['max']
);
}
}
class WeatherInfo {
final String? description;
final String? icon;
WeatherInfo({this.description, this.icon});
factory WeatherInfo.fromJson(Map<String, dynamic> json) {
final description = json['description'];
final icon = json['icon'];
return WeatherInfo(description: description, icon: icon);
}
}
class WeatherForecastResponse {
final CurrentWeatherModel current;
final HourlyWeatherModel hourly;
final DailyWeatherInfoModel daily;
String get iconCurrentWeatherUrl{
return 'https://merakiapp.be/wp-content/uploads/2022/04/${current.weatherInfo.icon}.png';
}
String get iconDailyWeatherUrl{
return 'https://merakiapp.be/wp-content/uploads/2022/04/${daily.weatherInfo.icon}.png';
}
const WeatherForecastResponse(
{
required this.current,
required this.daily,
required this.hourly
}
);
factory WeatherForecastResponse.fromJson(json){
return WeatherForecastResponse(
current: CurrentWeatherModel.fromJson(json['current']),
hourly: HourlyWeatherModel.fromJson(json['hourly'][0]),
daily: DailyWeatherInfoModel.fromJson(json['daily'][0])
);
}
}
My Response:
Future<WeatherForecastResponse> getForecast(double lat, double lon) async {
try {
String api = 'https://api.openweathermap.org/data/2.5/onecall';
String appId = 'MyAPIKey';
String units = 'metric';
String cnt = '4';
String url = '$api?lat=$lat&lon=$lon&cnt=$cnt&appid=$appId&units=$units';
final response = await http.get(Uri.parse(url));
final json = jsonDecode(response.body);
return WeatherForecastResponse.fromJson(json);
} catch (e) {
rethrow;
}
}
Respons object:
void _currentWeather() async {
await FirebaseFirestore.instance.collection('Users').doc(currentUser).get().then((value) => _userLocation = value.data()!['Location']);
setState(() {
lat = _userLocation.latitude;
lon = _userLocation.longitude;
});
final response = await _dataWeatherService.getForecast(lat!, lon!);
setState(() {
temp = response.current.temp.round();
weather = response.current.weatherInfo.description;
icon = response.iconCurrentWeatherUrl;
});
}
void _dailyForecast() async {
final response = await _dataWeatherService.getForecast(lat!, lon!);
setState(() {
tempDaily = response.daily.dailyTemp.day.round();
weatherDaily = response.daily.weatherInfo.description;
iconDaily = response.iconDailyWeatherUrl;
date = response.daily.date;
});
}
JSON from OneCall API:
{
"lat": 33.44,
"lon": -94.04,
"timezone": "America/Chicago",
"timezone_offset": -21600,
"current": {
"dt": 1618317040,
"sunrise": 1618282134,
"sunset": 1618333901,
"temp": 284.07,
"feels_like": 282.84,
"pressure": 1019,
"humidity": 62,
"dew_point": 277.08,
"uvi": 0.89,
"clouds": 0,
"visibility": 10000,
"wind_speed": 6,
"wind_deg": 300,
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10d"
}
],
"rain": {
"1h": 0.21
}
},
"minutely": [
{
"dt": 1618317060,
"precipitation": 0.205
},
...
},
"hourly": [
{
"dt": 1618315200,
"temp": 282.58,
"feels_like": 280.4,
"pressure": 1019,
"humidity": 68,
"dew_point": 276.98,
"uvi": 1.4,
"clouds": 19,
"visibility": 306,
"wind_speed": 4.12,
"wind_deg": 296,
"wind_gust": 7.33,
"weather": [
{
"id": 801,
"main": "Clouds",
"description": "few clouds",
"icon": "02d"
}
],
"pop": 0
},
...
}
"daily": [
{
"dt": 1618308000,
"sunrise": 1618282134,
"sunset": 1618333901,
"moonrise": 1618284960,
"moonset": 1618339740,
"moon_phase": 0.04,
"temp": {
"day": 279.79,
"min": 275.09,
"max": 284.07,
"night": 275.09,
"eve": 279.21,
"morn": 278.49
},
"feels_like": {
"day": 277.59,
"night": 276.27,
"eve": 276.49,
"morn": 276.27
},
"pressure": 1020,
"humidity": 81,
"dew_point": 276.77,
"wind_speed": 3.06,
"wind_deg": 294,
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10d"
}
],
"clouds": 56,
"pop": 0.2,
"rain": 0.62,
"uvi": 1.93
},
...
},
"alerts": [
{
"sender_name": "NWS Tulsa",
"event": "Heat Advisory",
"start": 1597341600,
"end": 1597366800,
"description": "...HEAT ADVISORY REMAINS IN EFFECT FROM 1 PM THIS AFTERNOON TO\n8 PM CDT THIS EVENING...\n* WHAT...Heat index values of 105 to 109 degrees expected.\n* WHERE...Creek, Okfuskee, Okmulgee, McIntosh, Pittsburg,\nLatimer, Pushmataha, and Choctaw Counties.\n* WHEN...From 1 PM to 8 PM CDT Thursday.\n* IMPACTS...The combination of hot temperatures and high\nhumidity will combine to create a dangerous situation in which\nheat illnesses are possible.",
"tags": [
"Extreme temperature value"
]
},
...
]
I would change your WeatherForecastResponse to have a list of DailyWeatherInfoModel vs a single model.
class WeatherForecastResponse {
final CurrentWeatherModel current;
final HourlyWeatherModel hourly;
final List<DailyWeatherInfoModel> daily;
...
}
Then you parse a full list in the fromJson constructor
factory WeatherForecastResponse.fromJson(json) {
final dailyResponse = json['daily'] as List;
final dailyForecastList = <DailyWeatherInfoModel>[];
for (final day in dailyResponse) {
dailyForecastList.add(DailyWeatherInfoModel.fromJson(day));
}
return WeatherForecastResponse(
current: CurrentWeatherModel.fromJson(json['current']),
hourly: HourlyWeatherModel.fromJson(json['hourly'][0]),
daily: dailyForecastList);
}
I would also just put the icon url in each daily/hourly model. This way you have a fully self contained list of DailyWeatherInfoModel with everything you need.
class DailyWeatherInfoModel {
final TempModel dailyTemp;
final WeatherInfo weatherInfo;
final DateTime date;
final int dt;
final String iconUrl; // adding this
const DailyWeatherInfoModel({
required this.dailyTemp,
required this.weatherInfo,
required this.date,
required this.dt,
required this.iconUrl,
});
factory DailyWeatherInfoModel.fromJson(json) {
final weatherInfo = WeatherInfo.fromJson(json['weather'][0]);
final iconUrl =
'https://merakiapp.be/wp-content/uploads/2022/04/${weatherInfo.icon}.png'; // init iconUrl here
return DailyWeatherInfoModel(
dailyTemp: TempModel.fromJson(json['temp']),
dt: json['dt'],
date: DateTime.fromMillisecondsSinceEpoch(json['dt'] * 1000, isUtc: true),
weatherInfo: weatherInfo,
iconUrl: iconUrl,
);
}
}
You can apply the same concept to the hourly forecast as well.
I want to get data from API, my API data as DoctorModel inside it daysModel, inside daysModel is workTimeModel, each doctor has many days and has worktime.
I tried a lot of ways but still can't fix it.
note: I made my API from this website https://app.quicktype.io/
my code to get API data:
Response res = await get(
doctorsUrl ,
);
if (res.statusCode == 200) {
var body = jsonDecode(res.body);
List<dynamic> data = body['data'];
List<DoctorInfoModel> doctors = data.map((dynamic item) => DoctorInfoModel.fromJson(item)).toList();
return doctors;
}
my API:
{
"id": 15,
"name": "Prof. Elton Quigley",
"about": "uHiKeKA1gq",
"stars": 5,
"location": "R59lmj1eud",
"latitude": 5,
"longitude": 5,
"notes": "yCl95VqUAz",
"days": [
{
"name": "سبت",
"pivot": {
"doctor_id": 15,
"day_id": 1,
"morning": "1",
"evening": "1"
}
},
{
"name": "أحد",
"pivot": {
"doctor_id": 15,
"day_id": 2,
"morning": "3",
"evening": "3"
}
},
{
"name": "إثنين",
"pivot": {
"doctor_id": 15,
"day_id": 3,
"morning": "5",
"evening": "5"
}
},
{
"name": "ثلاثاء",
"pivot": {
"doctor_id": 15,
"day_id": 4,
"morning": "4",
"evening": "4"
}
},
{
"name": "أربعاء",
"pivot": {
"doctor_id": 15,
"day_id": 5,
"morning": "5",
"evening": "5"
}
},
{
"name": "خميس",
"pivot": {
"doctor_id": 15,
"day_id": 6,
"morning": "4",
"evening": "4"
}
}
]
}
my DoctorModel:
// To parse this JSON data, do
//
// final doctorInfoModel = doctorInfoModelFromJson(jsonString);
import 'dart:convert';
DoctorInfoModel doctorInfoModelFromJson(String str) => DoctorInfoModel.fromJson(json.decode(str));
String doctorInfoModelToJson(DoctorInfoModel data) => json.encode(data.toJson());
class DoctorInfoModel {
DoctorInfoModel({
this.id,
this.name,
this.about,
this.stars,
this.location,
this.latitude,
this.longitude,
this.notes,
this.days,
});
int id;
String name;
String about;
int stars;
String location;
int latitude;
int longitude;
String notes;
List<Day> days;
factory DoctorInfoModel.fromJson(Map<String, dynamic> json) => DoctorInfoModel(
id: json["id"],
name: json["name"],
about: json["about"],
stars: json["stars"],
location: json["location"],
latitude: json["latitude"],
longitude: json["longitude"],
notes: json["notes"],
days: List<Day>.from(json["days"].map((x) => Day.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"about": about,
"stars": stars,
"location": location,
"latitude": latitude,
"longitude": longitude,
"notes": notes,
"days": List<dynamic>.from(days.map((x) => x.toJson())),
};
}
class Day {
Day({
this.name,
this.pivot,
});
String name;
Pivot pivot;
factory Day.fromJson(Map<String, dynamic> json) => Day(
name: json["name"],
pivot: Pivot.fromJson(json["pivot"]),
);
Map<String, dynamic> toJson() => {
"name": name,
"pivot": pivot.toJson(),
};
}
class Pivot {
Pivot({
this.doctorId,
this.dayId,
this.morning,
this.evening,
});
int doctorId;
int dayId;
String morning;
String evening;
factory Pivot.fromJson(Map<String, dynamic> json) => Pivot(
doctorId: json["doctor_id"],
dayId: json["day_id"],
morning: json["morning"],
evening: json["evening"],
);
Map<String, dynamic> toJson() => {
"doctor_id": doctorId,
"day_id": dayId,
"morning": morning,
"evening": evening,
};
}
How can I get data correctly?
I figured out how to get data.
I replaced these two lines:
List<dynamic> data = body['data'];
List<DoctorInfoModel> doctors = data.map((dynamic item) => DoctorInfoModel.fromJson(item)).toList();
by these:
var data = body['data'];
DoctorInfoModel doctorInfo = DoctorInfoModel.fromJson(data);
when my DoctorInfoModel is not a List, so I delete it.
Correct code to get API data:
if (res.statusCode == 200) {
var body = jsonDecode(res.body);
var data = body['data'];
DoctorInfoModel doctorInfo = DoctorInfoModel.fromJson(data);
print(doctorInfo.name);
print(doctorInfo.about);
print(doctorInfo.days[0].name);
print(doctorInfo.days[0].pivot.morning);
return doctorInfo;
}
I am getting a response as key as numeric. How to map data for the following response
{
"1": [
{
"id": 6,
"name": "test 1"
},
{
"id": 8,
"name": "test 2"
},
{
"id": 7,
"name": "test 3"
}
],
"2": [
{
"id": 9,
"name": "ttt1"
},
{
"id": 5,
"name": "ttt3"
}
],
"3": [
{
"id": 4,
"name": "ttg",
"status_id": 1
}
]
}
Here is my model
import 'dart:convert';
Map<String, List<HomeBannerModel>> homeBannerModelFromJson(String str) => Map.from(json.decode(str)).map((k, v) => MapEntry<String, List<HomeBannerModel>>(k, List<HomeBannerModel>.from(v.map((x) => HomeBannerModel.fromJson(x)))));
String homeBannerModelToJson(Map<String, List<HomeBannerModel>> data) => json.encode(Map.from(data).map((k, v) => MapEntry<String, dynamic>(k, List<dynamic>.from(v.map((x) => x.toJson())))));
class HomeBannerModel {
int id;
String name;
HomeBannerModel({this.id, this.name});
HomeBannerModel.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;
}
}
I need to take the value in UI as
var data1 = data['1'];
var data2= data['2'];
var data3= data['3'];
but I am getting errors. help how to get the data of each key in each of the variable
but while mapping I am getting errors I have added part of my code in UI
_message:"type 'Map<String, dynamic>' is not a subtype of type 'List'"
The following method will convert your json string to a valid map object so that you can get your data the way you wanted.
Map<String, List<HomeBannerModel>> homeBannerModelFromJson(String str) => Map.from(json.decode(str)).map((k, v) => MapEntry<String, List<HomeBannerModel>>(k, List<HomeBannerModel>.from(v.map((x) => HomeBannerModel.fromJson(x)))));
to access data
final data = homeBannerModelFromJson(your_json_string);
print(data['1'][0].name); // test 1
You current json structure is Map<String, List<Map<String, dynamic>>>
You can try something like
var json = {...};
json.forEach((key, list) {
list.forEach((homeBannerModelMap) {
HomeBannerModel hBM = HomeBannerModel.fromJson(homeBannerModelMap);
});
});
You getting the error because your data is the type of Map, not the List.
So you can do something like this:
// [data] is result banners
List data = [];
// [result] is your object variable {"1": [{"id": 1, "name": "Welcome!"}]} etc
// So .forEach method is used for iterating through your json object
result.forEach((k, v){
// in which iteration I will map every instance to List of [HomeBannerModel]
var value = v.map((banner) => HomeBannerModel.fromJson(banner)).toList();
//in result I will add the result to our [banners] List
data.add(value);
});
But in this case, you should do:
data1 = data[1] // use int as the key, result will be List of BannerModels [Instance of 'HomeBannerModel', Instance of 'HomeBannerModel']
instead of:
var data1 = data['1']; //use string as the key
Please try the following code with just one model 'HomeBannerModel'.
main() {
final Map<String, dynamic> json = {
"1": [
{"id": 6, "name": "test 1"},
{"id": 8, "name": "test 2"},
{"id": 7, "name": "test 3"}
],
"2": [
{"id": 9, "name": "ttt1"},
{"id": 5, "name": "ttt3"}
],
"3": [
{"id": 4, "name": "ttg", "status_id": 1}
]
};
final Map datas = {};
json.forEach((key, value) {
datas.addAll(
{"$key": value.map((ele) => HomeBannerModel.fromMap(ele)).toList()});
});
print(datas["1"]);
print(datas["2"]);
print(datas["3"]);
}
class HomeBannerModel {
final int id;
final String name;
final int status_id;
HomeBannerModel({
this.id,
this.name,
this.status_id,
});
Map<String, dynamic> toMap() {
return {
'id': id,
'name': name,
'status_id': status_id,
};
}
factory HomeBannerModel.fromMap(map) {
if (map == null) return null;
return HomeBannerModel(
id: map['id'],
name: map['name'],
status_id: map['status_id'],
);
}
#override
String toString() => 'Details(id: $id, name: $name, status_id: $status_id)';
}
You may also try with two models (1) Data and (2) HomeBannerModel. Please see the following code :
main() {
final Map<String, dynamic> json = {
"1": [
{"id": 6, "name": "test 1"},
{"id": 8, "name": "test 2"},
{"id": 7, "name": "test 3"}
],
"2": [
{"id": 9, "name": "ttt1"},
{"id": 5, "name": "ttt3"}
],
"3": [
{"id": 4, "name": "ttg", "status_id": 1}
]
};
final List<Data> data = [];
json.forEach((key, value) {
data.add(Data.fromMap({"id": key, "details": value}));
});
print(data.firstWhere((e) => e.dataID == '1').homeBannerModel);
print(data.firstWhere((e) => e.dataID == '2').homeBannerModel);
print(data.firstWhere((e) => e.dataID == '3').homeBannerModel);
}
class Data {
final String dataID;
final List<HomeBannerModel> homeBannerModel;
Data({
this.dataID,
this.homeBannerModel,
});
factory Data.fromMap(Map<String, dynamic> map) {
if (map == null) return null;
return Data(
dataID: map["id"],
homeBannerModel: (map["details"]
.map<HomeBannerModel>((ele) => HomeBannerModel.fromMap(ele))
.toList() as List<HomeBannerModel>));
}
#override
String toString() => 'Data(id: $dataID, details: $homeBannerModel)';
}
class HomeBannerModel {
final int id;
final String name;
final int status_id;
HomeBannerModel({
this.id,
this.name,
this.status_id,
});
Map<String, dynamic> toMap() {
return {
'id': id,
'name': name,
'status_id': status_id,
};
}
factory HomeBannerModel.fromMap(map) {
if (map == null) return null;
return HomeBannerModel(
id: map['id'],
name: map['name'],
status_id: map['status_id'],
);
}
#override
String toString() => 'Details(id: $id, name: $name, status_id: $status_id)';
}
From what I’m seeing in the sample response you shared , the kets are all string as should be... "1" is also String FYI.
Coming to the error you're getting its because you are probably using the var data1,data2,data3 as a map which it isn't.
var data1 = data['1'];
if you print this var you will get :
[
{
"id": 6,
"name": "test 1"
},
{
"id": 8,
"name": "test 2"
},
{
"id": 7,
"name": "test 3"
}
]
If you want to access the submap with id of 6 and name Test 1 do the following:
print(data1[0]);
to display name:
print(data1[0]["name"]);