How to put json-data into a list in flutter? - api

When I try to get data from this API https://api.met.no/weatherapi/locationforecast/2.0/complete?lat=10&lon=10 it gets me a long array of some sort with all the timeseries. In the end, I would like to display some data from each time which has its own place in the downloaded array. I want to covert all data to a list so I can manipulate the data but i get errors like these type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String.
This is my code
List<dynamic> timeseriesglobal = [];
void loadForecast() async{
//Getting the data from API
Response response = await get("https://api.met.no/weatherapi/locationforecast/2.0/complete?lat=57.047218&lon=9.920100");
var results = jsonDecode(response.body);
timeseriesglobal = results["properties"]["timeseries"] as List;
}
And in the end i have this code for displaying the data
child: ListView.builder(
itemCount: timeseriesglobal.length,
itemBuilder: (context,index){
return Card(
child: ListTile(
title: Text(
timeseriesglobal[index]
),
),
);
},
What am I doing wrong? Please help me

Provide the property name that you want to show Ex time
ListView.builder(
itemCount: timeseriesglobal.length,
itemBuilder: (context,index){
return Card(
child: ListTile(
title: Text(
timeseriesglobal[index]['time']
),
),
);
},

Create Your BaseModel from the json you are getting from the link.
Then Parse like below
var data= BaseModel.fromJson(response.body);
Now this will contain everything and you can extract whatever u want from the model
To convert the json use this link

Related

How to dynamically populate AudioSource with multiple audio data from firestore in just_audio?

I have been trying to dynamically populate AudioSource.uri() with data from firestore.
I uploaded some songs into firestore database and I wanted to use the data for a just_audio playlist in my app. I have done everything possible, and I really am not sure why its not working.
I don't want to add the song urls and other data statically as shown in the plugin example.
Here are my attempts:
First I fetched the song data using a StreamBuilder and passed it as a DocumentSnapshot List to the JustAudioPlaylist() page;
List<DocumentSnapshot> _list;
_list = snapshot.data.docs;
Flexible(
child: ListView.builder(
itemCount: 1,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => JustAudioPlaylist(
songs: [_list[index]],
),
));
},
child:
Container(child: Center(child: Text('My Playlists'))),
);
}),
)
Then, here's the JustAudioPlaylist page where I expected to retrieve and populate the AudioSource.uri().
class JustAudioPlaylist extends StatefulWidget {
final List songs;
JustAudioPlaylist({this.songs});
#override
_JustAudioPlaylistState createState() => _JustAudioPlaylistState();
}
class _JustAudioPlaylistState extends State<JustAudioPlaylist> {
AudioPlayer _player;
int _addedCount = 0;
var _playlist;
#override
void initState() {
_playlist
.addAll(widget.songs.map((song) => ConcatenatingAudioSource(children: [
AudioSource.uri(
Uri.parse(song['song']),
tag: AudioMetadata(
album: "Science Friday",
title: song['songTitle'],
artwork: song['songImage'],
),
),
])));
I am not sure why its not working, but it produces an error "addAll was called on null". Please can anyone help?
Your relevant code is:
_playlist.addAll(...);
The error means _playlist is null. That is, _playlist is an uninitialised variable and doesn't actually contain any playlist object. I can see you declare the variable so it starts off empty:
var _playlist;
But you never actually store anything into this variable, like _playlist = ...something.... So your _playlist variable starts off null and continues to remain null.
You could do this instead:
_playlist = ConcatenatingAudioSource(children: []);
// and then later...
_playlist.addAll(widget.songs.map(...etc...));
Although addAll is intended for dynamically modifying the playlist after it's already created. But in your case, you know which songs you want to play at initialisation time, so you may as well just initialise the playlist right at the beginning and you won't have to add to it later:
_playlist = ConcatenatingAudioSource(
children: widget.songs.map(...etc...)
);

API data display - flutter card widget

Get API connection is successful. but I have no idea how to map data.. how is connect snapshot.data,
I want to display data in a Stack widget.
https://flutter.dev/docs/cookbook/networking/fetch-data
I learned this from the association with this source
Future<News> fetchNews() async {
final response =
await http.get('#url');
print(response.body);
if (response.statusCode == 200) {
return News.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load news');
}
}
class News {
final String title;
final String description;
final String image;
News({this.title, this.description, this.image});
factory News.fromJson(Map<String, dynamic> json) {
return News(
title: json['title'],
description: json['description'],
image: json['image'],
);
}
}
Widget _buildPage(BuildContext context, int direction) {
Size size = MediaQuery.of(context).size;
return SafeArea(
child: FutureBuilder<News>(
future: futureNews,
builder: (context, snapshot) {
if (snapshot.hasData) {
return newsCard(snapshot.data);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
);
}
Widget newsCard(size){
return Stack(
children: <Widget>[
Container(
child: Image.network(
image,
fit: BoxFit.cover
),
height: size.height/2.0,
),
),
],
);
}
Your code is a bit messy and it doesn't make much sense. It seems obvious that the data is not getting displayed because you're passing your News object to your newsCard function, but the parameter seems to be expecting Size. I also don't know where are you getting the image property from since it doesn't seem to be declared anywhere in the code.
Doing some changes to your code, a minimal working function that returns your widget would look like this:
Widget _buildPage(BuildContext context, int direction) {
Size size = MediaQuery.of(context).size;
return SafeArea(
child: FutureBuilder<News>(
future: futureNews,
builder: (context, snapshot) {
if (snapshot.hasData) {
return newsCard(snapshot.data, size);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
);
}
Widget newsCard(News news, Size size){
return Stack(
children: <Widget>[
Container(
child: Image.network(
news.image,
fit: BoxFit.cover
),
height: size.height/2.0,
),
),
],
);
}
UPDATE
If you're getting the error you mentioned bellow, is likely that your response from the get request is a list of News and not just one News object, therefore you'll have to change this:
return News.fromJson(jsonDecode(response.body));
To this:
return jsonDecode(response.body).map<News>((object) => News.fromJson(object)).toList();
The return type of fetchNews() should be Future<List<News>> instead of Future<News>

Flutter app error "NoSuchMethodError: The getter 'length' was called on null"

Am getting this error and can't find the why, the app shows a google map calling hospital from google map places api, api call returns fine when used in chrome, but the app fail to build showing the "NoSuchMethodError: The getter 'length' was called on null" error. Thanks for your help.
class Search extends StatelessWidget {
#override
Widget build(BuildContext context) {
final currentPosition = Provider.of<Position>(context);
final placesProvider = Provider.of<Future<List<Place>>>(context);
return FutureProvider(
create: (context) => placesProvider,
child: Scaffold(
body: (currentPosition != null)
? Consumer<List<Place>>(
builder: (_, places, __) {
return Column(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height / 3,
width: MediaQuery.of(context).size.width,
child: GoogleMap(
initialCameraPosition: CameraPosition(
target: LatLng(currentPosition.latitude,
currentPosition.longitude),
zoom: 16.0),
zoomGesturesEnabled: true,
mapToolbarEnabled: true,
myLocationEnabled: true,
scrollGesturesEnabled: true,
),
),
SizedBox(
height: 10.0,
),
Expanded(
child: ListView.builder(
itemCount: places.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(places[index]?.name),
),
);
}),
)
],
);
},
)
: Center(
child: CircularProgressIndicator(),
),
),
);
}
}
The api request works fine when called in chrome, problem is when building the app. This is my places_service.dart file:
class PlacesService {
final key = 'xxxxxxxxxxxxxxxxxxxxx-ttttttttttttttttt';
Future<List<Place>> getPlaces(double lat, double lng) async {
var response = await http.get('https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=$lat,$lng&type=hospital&rankby=distance&key=$key');
var json = convert.jsonDecode(response.body);
var jsonResults = json['results'] as List;
return jsonResults.map((place) => Place.fromJson(place)).toList();
}
}
Problem is this line:
itemCount: places.length,
If you use constructions like places.length the programming code can fail on two places:
when places = null
when places.length = null (your situation)
You cannot call methods and properties on null-objects; that is why you get this error. So before you call places.length you must be sure that both situations cannot occur. How this is done and if the check is really necessary depends on the rest of your program. One way to check is:
itemCount: places.length != null ? places.length : 0;

Why doesn't my FutureBuilder return any data?

I have a api that returns a list of data.
When I retrieve that data I use a FutureBuilder to show the list of data.
But for some reason it won't show my data even though when I print the response I can see that I got a correct response.
This is the error that i got:
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (11846): The following assertion was thrown building FutureBuilder<List<BasicDiskInfo>>(dirty, state:
I/flutter (11846): _FutureBuilderState<List<BasicDiskInfo>>#a0948):
I/flutter (11846): A build function returned null.
I/flutter (11846): The offending widget is: FutureBuilder<List<BasicDiskInfo>>
I/flutter (11846): Build functions must never return null. To return an empty space that causes the building widget to
I/flutter (11846): fill available room, return "new Container()". To return an empty space that takes as little room as
I/flutter (11846): possible, return "new Container(width: 0.0, height: 0.0)".
I don't know what to do. Help me?
API
static Future<List<BasicDiskInfo>> fetchAllDisks() async {
final response = await http.get('link');
if (response.statusCode == 200) {
Iterable list = json.decode(response.body);
var disks = new List<BasicDiskInfo>();
disks = list.map((model) => BasicDiskInfo.fromJson(model)).toList();
print(disks[0]);
return disks;
} else {
throw Exception('Failed to load disks');
}
}
Page
class Disks extends StatelessWidget {
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: API.fetchAllDisks(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return new CircularProgressIndicator();
default:
if (snapshot.hasError) {
return new Text('Error: ${snapshot.error}');
} else {
print(snapshot.data);
createListView(context, snapshot);
}
}
},
);
}
Widget createListView(BuildContext context, AsyncSnapshot snapshot) {
List<BasicDiskInfo> disks = snapshot.data;
return new ListView.builder(
itemCount: disks.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SpecificDiskPage(
diskId: disks[index].id,
),
));
},
child: Card(
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text(disks[index].name),
Spacer(),
Text(disks[index].driveType),
Spacer(),
Text(disks[index].driveFormat),
],
),
Row(
children: <Widget>[
Text(disks[index].totalSize.toString()),
Spacer(),
Text(disks[index].totalFreeSpace.toString()),
],
),
],
),
),
);
},
);
}
}
BasicDiskInfo
class BasicDiskInfo {
int id;
String name;
String driveType;
String driveFormat;
int totalSize;
int totalFreeSpace;
BasicDiskInfo(
{this.id,
this.name,
this.driveType,
this.driveFormat,
this.totalSize,
this.totalFreeSpace});
factory BasicDiskInfo.fromJson(Map<String, dynamic> json) {
return BasicDiskInfo(
id: json['id'],
name: json['name'],
driveType: json['driveType'],
driveFormat: json['driveFormat'],
totalSize: json['totalSize'],
totalFreeSpace: json['totalFreeSpace']);
}
}
The FutureBuilder should return a list with the data from the api
There is an error in your build method. You didn't return createListView(context, snapshot); in your default case.

Flutter - Creating tables dynamically

I'm trying to dynamically create tables using Dart and Flutter. Something like this The number of table rows will change depending on the the JSON file passed in.
I've read through and done all of the Flutter tutorials I can get my hands on and read through the Documentation on the Table and ListBuilder classes, but none of them quite accomplish what I'm trying to do, because the examples either only dynamically create single ListItems or all the data and/or Widgets are hard-coded.
I've also tried doing this by doing:
Table dynamicTable = new Table(); then dynamically adding children Widgets with
dynamicTable.add(TableRow(
children: [
Text("test1"),
Text("test2"),
Text("test3"),
]
));
But I get an error saying "Cannot add to an unmodifiable list".
Any tips on how to accomplish this would be greatly appreciated.
This function creates a table dynamically:
Widget createTable() {
List<TableRow> rows = [];
for (int i = 0; i < 100; ++i) {
rows.add(TableRow(children: [
Text("number " + i.toString()),
Text("squared " + (i * i).toString()),
]));
}
return Table(children: rows);
}
First fetch List of Records
List<PriceDetailsView> priceDetailsList = MockDataSource.getPriceDetailsDataList();
Now create an empty list of table rows :
List<TableRow> priceTableRows = [];
Add details from the fetched list to this row list:
for(PriceDetailsView priceDetalis in priceDetailsList){
priceTableRows.add(TableRow(children: [Text(priceDetalis.priceType), Text(priceDetalis.priceValue)]));
}
Now create your table with this list of row :
Table priceTable = Table(children: priceTableRows);
Suppose you have this model class:
class Person {
final int id;
final String name;
final String email;
final String phone;
const Person({
this.id = 0,
this.name = '',
this.email = '',
this.phone = '',
});
...
}
and you have populated a List of Person with data from an API call:
List<Person> _personList = ...
To generate the TableRow, you can do it using List.generate Dart function:
return Table(
border: TableBorder.all(color: Colors.black),
children: List<TableRow>.generate(
_personList.length,
(index) {
final person = _personList[index];
return TableRow(
children: [
Padding(
padding: EdgeInsets.all(5.0),
child: Text(person.id.toString(), textAlign: TextAlign.center),
),
Padding(
padding: EdgeInsets.all(5.0),
child: Text(person.name, textAlign: TextAlign.center),
),
Padding(
padding: EdgeInsets.all(5.0),
child: Text(person.email, textAlign: TextAlign.center),
),
Padding(
padding: EdgeInsets.all(5.0),
child: Text(person.phone, textAlign: TextAlign.center),
),
],
);
},
growable: false,
),
);
It's pretty easy, actually! All you have to do is, make a list of TableRows, and put that in the children parameter of your table. For example
List<TableRow> tableRows = [];
// dynamically make TableRows and add them to the list
And then you can just do this:
Table(
children: tableRows,
// other stuff
)