i'm confusing with this kind of json.
because i never see someone explain about this kind of json data.
i get my jsondata from a link, and the json data show like this
{
"data": [
{
"jenis_komoditas": "Gabah IR 64 KP",
"harga": "5400",
"satuan": "Kg",
"persen": null,
"perubahan": "0",
"selisi": "0",
"image": "assets\/thumb\/gabah.png"
},
{
"jenis_komoditas": "Gabah IR 64 KG",
"harga": "6200",
"satuan": "Kg",
"persen": null,
"perubahan": "0",
"selisi": "0",
"image": "assets\/thumb\/gabah1.png"
}
]
}
it gets error.
can someone help me how to get the data from first json type?
You can parse your full json string with
Payload payload = payloadFromJson(jsonString);
print('${payload.data[0].jenisKomoditas}');
Related Class
// To parse this JSON data, do
//
// final payload = payloadFromJson(jsonString);
import 'dart:convert';
Payload payloadFromJson(String str) => Payload.fromJson(json.decode(str));
String payloadToJson(Payload data) => json.encode(data.toJson());
class Payload {
List<Datum> data;
Payload({
this.data,
});
factory Payload.fromJson(Map<String, dynamic> json) => Payload(
data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"data": List<dynamic>.from(data.map((x) => x.toJson())),
};
}
class Datum {
String jenisKomoditas;
String harga;
String satuan;
dynamic persen;
String perubahan;
String selisi;
String image;
Datum({
this.jenisKomoditas,
this.harga,
this.satuan,
this.persen,
this.perubahan,
this.selisi,
this.image,
});
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
jenisKomoditas: json["jenis_komoditas"],
harga: json["harga"],
satuan: json["satuan"],
persen: json["persen"],
perubahan: json["perubahan"],
selisi: json["selisi"],
image: json["image"],
);
Map<String, dynamic> toJson() => {
"jenis_komoditas": jenisKomoditas,
"harga": harga,
"satuan": satuan,
"persen": persen,
"perubahan": perubahan,
"selisi": selisi,
"image": image,
};
}
full code
import 'package:flutter/material.dart';
// To parse this JSON data, do
//
// final payload = payloadFromJson(jsonString);
import 'dart:convert';
Payload payloadFromJson(String str) => Payload.fromJson(json.decode(str));
String payloadToJson(Payload data) => json.encode(data.toJson());
class Payload {
List<Datum> data;
Payload({
this.data,
});
factory Payload.fromJson(Map<String, dynamic> json) => Payload(
data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"data": List<dynamic>.from(data.map((x) => x.toJson())),
};
}
class Datum {
String jenisKomoditas;
String harga;
String satuan;
dynamic persen;
String perubahan;
String selisi;
String image;
Datum({
this.jenisKomoditas,
this.harga,
this.satuan,
this.persen,
this.perubahan,
this.selisi,
this.image,
});
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
jenisKomoditas: json["jenis_komoditas"],
harga: json["harga"],
satuan: json["satuan"],
persen: json["persen"],
perubahan: json["perubahan"],
selisi: json["selisi"],
image: json["image"],
);
Map<String, dynamic> toJson() => {
"jenis_komoditas": jenisKomoditas,
"harga": harga,
"satuan": satuan,
"persen": persen,
"perubahan": perubahan,
"selisi": selisi,
"image": image,
};
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
String jsonString = '''
{
"data": [
{
"jenis_komoditas": "Gabah IR 64 KP",
"harga": "5400",
"satuan": "Kg",
"persen": null,
"perubahan": "0",
"selisi": "0",
"image": "assets\/thumb\/gabah.png"
},
{
"jenis_komoditas": "Gabah IR 64 KG",
"harga": "6200",
"satuan": "Kg",
"persen": null,
"perubahan": "0",
"selisi": "0",
"image": "assets\/thumb\/gabah1.png"
}
]
}
''';
void _incrementCounter() {
Payload payload = payloadFromJson(jsonString);
print('${payload.data[0].jenisKomoditas}');
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Output
I/flutter (23421): Gabah IR 64 KP
you are getting data in form of json array so you can simply call it iteratively from the object. like this
if you get data in data variable:
final jsondata=json.decode(data);
for (var dataf in jsondata['data']){
print(dataf['jenis_komoditas']);
}
Related
import 'package:flutter/material.dart';
import 'package:http_request/carditem.dart';
import 'package:http_request/user_data.dart';
// here we chose to have statefull widget because the state needs to be updated and we need to update some variables according to some conditions.
class UserScreen extends StatefulWidget {
const UserScreen({Key key}) : super(key: key);
#override
_UserScreenState createState() => _UserScreenState();
}
class _UserScreenState extends State<UserScreen> {
// here we created a variable to keep our information in it . this information comes from our user data class where we get the user data from http requests.
Map<String, dynamic> userinfo = {};
// this method is called as soon as the main widget is created . we call our http method here to have the live data as soon as we open the app .be aware that we cant use async and await here . we just call the method.
#override
void initState() {
super.initState();
getData();
}
// here we get hte live data from our userdata class .
Future getData() async {
//we create a userData object to get access to the getuserdata method.
UserData userData = UserData();
//we handle any error here
try {
// here we create a variable to the exact same type we are expecting .
//then we wait for the result of calling our userdata information.
Map<String, dynamic> data = await userData.getUserData();
// we call setState because we need to update a certain value here.
setState(() {
//we assign the the value of data to our variable called userinfo .try the reaosn we see no error behind them is that they are the same type.
userinfo = data;
});
// we catch errors here .
} catch (e) {
print(e);
}
}
// our nice build method ...this method is from our stateful class.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Work Harder'),
centerTitle: true,
),
body: ListView.builder(
itemBuilder: (context, index) => CardItem(
firstName: userinfo['firstName'],
avatarLink: userinfo['avatarLink'],
id: userinfo['id'],
lastName: userinfo['lastName'],
email: userinfo['email'],
),
),
);
}
}
as you can see here is my user_screen dart file the problem is when i hot reload the app is see the renderflex error, while everything seems fine. im a begginner in flutter and i would really appreciate your help.
i have tried singlechild scrollview , list view , expanded widget , but it doesn't work . please help me hotrestart may app without these long errors
import 'package:flutter/material.dart';
// we chose stateless because we don't need to change the state of our app.
class CardItem extends StatelessWidget {
const CardItem({
Key key,
this.firstName,
this.email,
this.avatarLink,
this.id,
this.lastName,
}) : super(key: key);
final String firstName;
final String email;
final String avatarLink;
final String id;
final String lastName;
#override
Widget build(BuildContext context) {
return Card(
color: Colors.lightBlueAccent[200],
elevation: 3,
shadowColor: Colors.blue[100],
child: Column(
children: [
Stack(
children: [
ListTile(
leading: Icon(Icons.check_box),
trailing: CircleAvatar(
child: Image.network(avatarLink),
),
title: Text(firstName),
subtitle: Text(lastName),
),
Positioned(
left: 48,
top: 15,
child: Text(
id,
style: TextStyle(
color: Colors.white70,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
Positioned(
left: 120,
top: 30,
child: Text(
'Email : $email',
style: TextStyle(
color: Colors.blue[900].withOpacity(0.6),
),
),
),
],
),
],
),
);
}
}
here is my card widget , if it helps.
import 'dart:convert';
import 'package:http/http.dart' as http;
// this is the file for our main http requests.
class UserData {
UserData({
this.firstName,
this.lastName,
this.email,
this.id,
this.avatarLink,
});
final String firstName;
final String lastName;
final String email;
final String id;
final String avatarLink;
//this method is response for getting the live data we want also its responsible for decoding it with 'dart convert' library and returning the result as an output.
Future getUserData() async {
//the url we are working with
final String stringUrl = 'https://reqres.in/api/users?page=2';
//sending the request to web and storing the result to a variable. we also have to wait for the results . (asynchronous operation).
http.Response response = await http.get(
Uri.parse(stringUrl),
);
//we create a variable to the exact type of our output . we want to add our items to this map to use it in the main screen.
Map<String, dynamic> userdetails = {};
//here we want to check if our request was successful if so, we continue our operation and if not we throw an error .
if (response.statusCode == 200) {
// here we are decoding the data that we got from our request above to a variable of type map.
Map<String, dynamic> decodedData = jsonDecode(response.body);
//here we try to iterate through a map .. but im not sure if its correct or not .
for (var user in decodedData.values) {
Map<String, dynamic> myusersInfo = {
'firstName': decodedData['data'][0]['first_name'],
'lastName': decodedData['data'][0]['last_name'],
'email': decodedData['data'][0]['email'],
'id': decodedData['data'][0]['id'].toString(),
'avatarLink': decodedData['data'][0]['avatar'],
};
// here we are trying to add the items to the map specified.
userdetails.addEntries(myusersInfo.entries);
return userdetails;
}
} else {
print(response.statusCode);
throw 'Problem with the get request';
}
}
}
the whole goal of this app was to practice some http request.
the last file I have in this app . I just added this maybe it helps you . thanks in advance.
A Column likes to expand until infinity.
This can be solved by putting an intrinsicHeight around the Column as followed:
This class is useful, for example, when unlimited height is available and you would like a child that would otherwise attempt to expand infinitely to instead size itself to a more reasonable height.
IntrinsicHeight(
child: Column(
children: [
],
)
);
https://api.flutter.dev/flutter/widgets/IntrinsicHeight-class.html
try column inside SingleChildScrollView
I have the following JSON hosted on localhost and am trying to resolve it in a FutureBuilder widget. I cannot resolve the data from the Json to display using the FutureBuilder widget. All I get is "Instance of LiteratureDataModel". Moreover, I cannot get the length of the data snapshot. The error I get is "The getter length isn't defined for the type Object"
{
"data": [
{
"authors": "author_name1",
"edition": "publication_edition1",
"id": 1,
"pubdate": "publication_date1",
"publisher": "publisher1",
"source": "literature_source1",
"title": "literature_title1"
},
{
"authors": "author_name2",
"edition": "publication_edition2",
"id": 2,
"pubdate": "publication_date2",
"publisher": "publisher2",
"source": "literature_source2",
"title": "literature_title2"
}
]
}
I generated the model class for the above Json using the following link:
https://app.quicktype.io/
Here is the class that was generated. I modified it to use null safety. The list of map objects according to the JSON prints successfully in the LiteratureDataModel factory constructor. So, the data is successfully received
class LiteratureDataModel {
LiteratureDataModel({
this.ultLiteratureDataModel,
});
final List<LiteratureModel>? ultLiteratureDataModel;
factory LiteratureDataModel.fromJson(Map<String, dynamic> json) => LiteratureDataModel(
ultLiteratureDataModel: List<LiteratureModel>.from(json["data"].map((data) {
print(data);
return LiteratureModel.fromJson(data);
})).toList(),
);
Map<String, dynamic> toJson() => {
"data": List<dynamic>.from(ultLiteratureDataModel!.map((data) => data.toJson())),
};
}
class LiteratureModel {
LiteratureModel({
this.authors,
this.edition,
this.id,
this.pubdate,
this.publisher,
this.source,
this.title,
});
final String? authors;
final String? edition;
final int? id;
final String? pubdate;
final String? publisher;
final String? source;
final String? title;
factory LiteratureModel.fromJson(Map<String, dynamic> json) => LiteratureModel(
authors: json["authors"],
edition: json["edition"],
id: json["id"],
pubdate: json["pubdate"],
publisher: json["publisher"],
source: json["source"],
title: json["title"],
);
Map<String, dynamic> toJson() => {
"authors": authors,
"edition": edition,
"id": id,
"pubdate": pubdate,
"publisher": publisher,
"source": source,
"title": title,
};
}
Here is the widget for displaying the data:
class Literature extends StatelessWidget {
final LiteratureService _literatureService = LiteratureService();
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(24.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(12)),
),
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: FutureBuilder(
future: _literatureService.fetchLiterature(http.Client()),
builder: (context, snapshot){
if (snapshot.hasData)
//return Text("${snapshot.data!}");
return ListView.builder(
//itemCount: snapshot.data!.length,
itemBuilder: (context, index){
return Text("${snapshot.data!}");
});
else
return CircularProgressIndicator();
},
),
)
),
),
);
}
}
The json is hosted on localhost, from which I can successfully pull the json. Here is the class used for fetching the json from local host
class LiteratureService {
LiteratureDataModel literatureFromJson(String literature) {
//print(literature);
return LiteratureDataModel.fromJson(json.decode(literature));
}
String literatureToJson(LiteratureDataModel literatureDataModel) => json.encode(literatureDataModel.toJson());
Future fetchLiterature(http.Client client) async {
final response = await client.get(Uri.parse("http://localhost_ip_address:8000/literature/ultliterature.json"));
//print("Http response: ${response.body}");
return literatureFromJson(response.body);
}
}
I referred to the following link to solve the problem, but could not solve it:
*SOLVED* Use json data stored in class in future builder
In the above link, the OP faced a similar issue as I did. I followed the changes recommended in the correct answer but realized its just another way of creating factory constructor that is there in LiteratureDataModel class. Moreover, I still could not get the length of the data snapshot.
I referred to the below link as well, which shows different ways of JSON serialization and deserialization as well, and still could not solve the problem.
https://bezkoder.com/dart-flutter-parse-json-string-array-to-object-list/#DartFlutter_parse_JSON_string_into_Nested_Object
What am I doing wrong in my code? Any advice on needed corrections to my code will be helpful.
I solved the problem by omitting the LiteratureDataModel class and changing the fetchLiterature() function in the following way:
Future<List<LiteratureModel>> fetchLiterature(http.Client client) async {
final response =
await client.get(Uri.parse("http://localhost_ip_address:8000/literature/literature.json"));
List<LiteratureModel> literatureModel = List<LiteratureModel>.from(
json.decode(response.body)["data"].map((data) => LiteratureModel.fromJson(data)).toList());
return literatureModel;
}
I also made the following changes to FutureBuilder using this link as a guide
builder: (context, AsyncSnapshot<List<LiteratureModel>> snapshot)
If anyone knows a better way of solving the question I posted, please let me know
this is my first question here on stackoverflow.
I'm working on my first real app after attending a few CS classes at University and some courses on Udemy. So I'm lacking a lot of software engineering knowledge.
My goal: I want to build a search for stocks by using an external API endpoint. For that, I have created 4 dart files to handle the searchscreen with inputs (My UI), networking, parsing, and basically returning the data.
My NetworkAPI class to handle all sorts of network requests looks like this. I'm trying to use the jsonDecode already here and returning that. This class waits for an URL that will be put together in another class (financeData):
class NetworkAPI {
final String url;
NetworkAPI(this.url);
Future getData() async {
http.Response response = await http.get(url);
if (response.statusCode == 200) {
String data = response.body;
return jsonDecode(data);
} else {
print(response.statusCode);
}
}
}
This is basically the Json I want to parse. If I understood the theory correctly it's a map with a list of objects.
{
"bestMatches": [
{
"1. symbol": "TESO",
"2. name": "Tesco Corporation USA",
"3. type": "Equity",
"4. region": "United States",
"5. marketOpen": "09:30",
"6. marketClose": "16:00",
"7. timezone": "UTC-04",
"8. currency": "USD",
"9. matchScore": "0.8889"
}
{....}
]
}
To parse this, I saw some really good explanations here on stack overflow. I'm basically trying to retrieve the information I'm interested in.
class SearchOutput {
final List<BestMatch> bestMatches;
SearchOutput({this.bestMatches});
factory SearchOutput.fromJson(Map<String, dynamic> parsedJson){
var list = parsedJson['bestMatches'] as List;
print(list.runtimeType);
List<BestMatch> searchResultList = list.map((i) => BestMatch.fromJson(i)).toList();
return SearchOutput(
bestMatches: searchResultList,
);
}
}
class BestMatch {
String symbol;
String name;
String type;
String region;
String currency;
BestMatch({
this.symbol,
this.name,
this.type,
this.region,
this.currency,
});
factory BestMatch.fromJson(Map<String, dynamic> parsedJson){
return BestMatch(
symbol: parsedJson["1. symbol"],
name: parsedJson["2. name"],
type: parsedJson["3. type"],
region: parsedJson["4. region"],
currency: parsedJson["8. currency"],
);
}
}
Now I created a class with a method that should return all my data and format it into a list. The URL still needs an searchInput, which will be handed over from a TextField Widget in the UI.
const apiKey = 'demo';
const alphaVantageSearchUrl =
'https://www.alphavantage.co/query?function=SYMBOL_SEARCH';
class FinanceData {
Future<dynamic> getSearchData(String searchInput) async {
var url = '$alphaVantageSearchUrl&keywords=$searchInput&apikey=$apiKey';
NetworkAPI networkAPI = NetworkAPI(url);
var searchData = await networkAPI.getData();
SearchOutput searchOutput = new SearchOutput.fromJson(searchData);
return searchOutput;
}
}
Testing with some print statements seems to fullfill my goal of being able to access the data. For example printing out the name of the second object out of my response.
print(searchOutput.bestMatches[1].name);
The last file is my UI where we have a TextField, that I push to the financeData class in order to build the URL. Currently, my goal would be, to be able to show just the name of any given object in my response in the UI. I have no idea how to initialize my financeDate and how to use the return from my finaceData class in the UI. (I took some design styles out of the code snippet).
class SearchScreenWatchlist extends StatefulWidget {
#override
_SearchScreenWatchlistState createState() => _SearchScreenWatchlistState();
}
class _SearchScreenWatchlistState extends State<SearchScreenWatchlist> {
String searchInput;
FinanceData financeData = FinanceData();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Container(
child: TextField(
onChanged: (value) {
searchInput = value;
},
),
),
TextButton(
onPressed: () {
financeData.getSearchData(searchInput);
setState(() {
});
},
child: Text('Search')),
Text(('Search Results for: $searchInput')),
Container(child: Text('**SHOW HERE THE NAME**')),
],
),
);
}
}
It would be my goal to show in the last container the name on any given object from my response for example RESPONSE.name[1]. Later on I will try to iterate throw all the objects and show a list of all names of the response.
Thanks a lot! I really appreciate your help!
I think changing SearchScreenWatchlist to the following should display the name of the first bestMatches entry after you pressed the Search button (if I didn't miss something).
Make sure to look further into setState and initState (And the StatefulWidget lifecycle in general). Also it may not be the most elegant way to initialize FinanceData() and SearchOutput() this way - However, awesome starter project!
class SearchScreenWatchlist extends StatefulWidget {
#override
_SearchScreenWatchlistState createState() => _SearchScreenWatchlistState();
}
class _SearchScreenWatchlistState extends State<SearchScreenWatchlist> {
String searchInput;
FinanceData financeData;
SearchOutput searchOutput;
#override
initState() {
super.initState();
financeData = FinanceData();
searchOutput = SearchOutput();
}
_handleButtonPress() async {
final fetchedSearchOutput = await financeData.getSearchData(searchInput);
setState(() {
searchOutput = fetchedSearchOutput;
});
}
_buildSearchResult() {
if(searchOutput.bestMatches != null && searchOutput.bestMatches.isNotEmpty) {
return Text(searchOutput.bestMatches.first.name);
}
else {
return Text("No data fetched");
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Container(
child: TextField(
onChanged: (value) {
setState(() {
searchInput = value;
});
},
),
),
TextButton(
onPressed: () => _handleButtonPress(),
child: Text('Search'),
),
Text(('Search Results for: $searchInput')),
Container(
child: _buildSearchResult(),
),
],
),
);
}
}
I am a newbie in flutter and I'm trying to create 3 dropdown menus from a json file hosted online. Here is a sample of the json file. This is the link to the json file and this is the model class:
class DropdownModel {
DropdownModel({
this.sports,
this.movies,
this.tv,
});
List<Movie> sports;
List<Movie> movies;
List<Movie> tv;
factory DropdownModel.fromJson(Map<String, dynamic> json) => DropdownModel(
sports: List<Movie>.from(json["sports"].map((x) => Movie.fromJson(x))),
movies: List<Movie>.from(json["movies"].map((x) => Movie.fromJson(x))),
tv: List<Movie>.from(json["tv"].map((x) => Movie.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"sports": List<dynamic>.from(sports.map((x) => x.toJson())),
"movies": List<dynamic>.from(movies.map((x) => x.toJson())),
"tv": List<dynamic>.from(tv.map((x) => x.toJson())),
};
}
class Movie {
Movie({
this.id,
this.name,
});
int id;
String name;
factory Movie.fromJson(Map<String, dynamic> json) => Movie(
id: json["id"],
name: json["name"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
};
}
How do I go about it?
EDIT
After searching around got a solution I came across this solution which answers my question
An example would be:
// Let's supose you have a variable of the DropdownModel
DropwdownModel model = DropdownModel(...);
// We store the current dropdown value
// Here you can put the default option
// Since you have Movies with id, I would recommend saving
// the movie value as the dropdownValue
String dropdownValue = '';
// For example, let's use the music
#override
Widget build(BuildContext context) {
// We define the dropdown button
return DropdownButton<String>(
// The value is the selected value, you should control the state
value: model.fromNameFromId(dropdownValue),
// The icon to open the dropdown
icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
// On changed is the method that it is called when a dropdown option
// is selected
onChanged: (String? newValue) {
// Here we change the state, as I noted before
// The newValue will be a movie id
setState(() {
dropdownValue = newValue!;
});
},
items: model.movies.map<DropdownMenuItem<String>>(
// We have to iterate through all the movies and return
// a list of DropdownMenuItems
(Movie m) {
return DropdownMenuItem<String>(
value: m.id,
// We display the movie name instead of the id
child: Text(m.name),
);
})
.toList(),
);
}
If you want three dropdowns, you would have to create three DropdownButton! You can find more information in the documentation!
I am currently building a flutter app where I want to calculate the distance between some objects and am using the Google Distance Matrix API to do so. I am having trouble parsing the json using Dart. All I want ultimately is a list of the distances from the json results so that I can index them and apply them to the data in my app.
The json results look like this:
{
"destination_addresses" : [
"destination address",
"destination address"
],
"origin_addresses" : [ "Origin addresses here" ],
"rows" : [
{
"elements" : [
{
"distance" : {
"text" : "4.3 mi",
"value" : 6998
},
"duration" : {
"text" : "14 mins",
"value" : 848
},
"status" : "OK"
},
{
"distance" : {
"text" : "6.7 mi",
"value" : 10728
},
"duration" : {
"text" : "22 mins",
"value" : 1327
},
"status" : "OK"
}
]
}
],
"status" : "OK"
}
I ultimately would like to end up with a list (in dart) that is just a list of the distance "text" values within the elements array but I am having trouble getting this to return. I have tried creating a class and mapping the json results to this but unsuccesfully as I am not very good at parsing json so any advice on how to end up with this list would be gratefully received!
I have tried this code to parse the json but am really struggling to make it work and then apply it:
class Topleveladd {
final String elements;
Topleveladd({this.elements});
factory Topleveladd.fromJson(Map<String, dynamic> parsedJson) {
return Topleveladd(elements: parsedJson['rows']);
}
}
class Elements {
List<Distance> distanceslist;
Elements({this.distanceslist});
factory Elements.fromJson(Map<String, dynamic> parsedJson) {
var list = parsedJson['elements'] as List;
print(list.runtimeType); //returns List<dynamic>
List<Distance> distancesList =
list.map((i) => Distance.fromJson(i)).toList();
return Elements(distanceslist: distancesList);
}
}
class Distance {
String text;
Distance({this.text});
factory Distance.fromJson(Map<String, dynamic> parsedJson) {
return new Distance(
text: parsedJson['distance'],
);
}
}
Okay this is it working with me accessing the JSON you've given as an asset so you'll probably have to change the loadData method for it to fit your needs.
DistanceMatrix class:
import 'dart:convert';
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;
class DistanceMatrix {
final List<String> destinations;
final List<String> origins;
final List<Element> elements;
final String status;
DistanceMatrix({this.destinations, this.origins, this.elements, this.status});
factory DistanceMatrix.fromJson(Map<String, dynamic> json) {
var destinationsJson = json['destination_addresses'];
var originsJson = json['origin_addresses'];
var rowsJson = json['rows'][0]['elements'] as List;
return DistanceMatrix(
destinations: destinationsJson.cast<String>(),
origins: originsJson.cast<String>(),
elements: rowsJson.map((i) => new Element.fromJson(i)).toList(),
status: json['status']);
}
static Future<DistanceMatrix> loadData() async {
DistanceMatrix distanceMatrix;
try{
String jsonData = await rootBundle.loadString('assets/data.json');
distanceMatrix = new DistanceMatrix.fromJson(json.decode(jsonData));
} catch (e){
print(e);
}
return distanceMatrix;
}
}
class Element {
final Distance distance;
final Duration duration;
final String status;
Element({this.distance, this.duration, this.status});
factory Element.fromJson(Map<String, dynamic> json) {
return Element(
distance: new Distance.fromJson(json['distance']),
duration: new Duration.fromJson(json['duration']),
status: json['status']);
}
}
class Distance {
final String text;
final int value;
Distance({this.text, this.value});
factory Distance.fromJson(Map<String, dynamic> json) {
return new Distance(text: json['text'], value: json['value']);
}
}
class Duration {
final String text;
final int value;
Duration({this.text, this.value});
factory Duration.fromJson(Map<String, dynamic> json) {
return new Duration(text: json['text'], value: json['value']);
}
}
Main.dart which uses ListView.builder to display the distances text and values as a ListTile:
import 'package:flutter/material.dart';
import 'package:hello_world/distance_matrix.dart';
void main() async {
runApp(new MyApp(
distanceMatrix: await DistanceMatrix.loadData(),
));
}
class MyApp extends StatefulWidget {
final DistanceMatrix distanceMatrix;
#override
_MyAppState createState() => new _MyAppState();
MyApp({this.distanceMatrix});
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Home"),
),
body: Material(
child: ListView.builder(
itemCount: widget.distanceMatrix.elements.length,
itemBuilder: (context, index){
return ListTile(
title: Text(widget.distanceMatrix.elements[index].distance.text),
subtitle: Text(widget.distanceMatrix.elements[index].distance.value.toString()),
);
},
)
)));
}
}
Image to show what you should get: