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:
Related
I have a json file that i'm trying to display as a list in my app.
here is the json file and how it is laid out:
{
"peoplesnames": [
"name1",
"name2",
"name3",
"name4",
"name5",
"name6",
"name7",
"name8"
]
}
and here is the code from my app:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class test extends StatefulWidget {
const test({Key? key}) : super(key: key);
#override
State<test> createState() => _testState();
}
class _testState extends State<test> {
List<String> peopleNames = [];
void getData() async {
http.Response response = await http.get(
Uri.parse('www.genericwebsite.com'),
);
if (response.statusCode == 200) {
String data = response.body;
final names = jsonDecode(data);
peopleNames.addAll((names['peoplesnames'] as List));
setState(() {});
return names;
} else {
print(response.statusCode);
}
}
#override
Widget build(BuildContext context) {
getData();
return Scaffold(
body: ListView.builder(
shrinkWrap: true,
itemCount: peopleNames.length,
itemBuilder: (context, index) {
return Text(peopleNames[index].toString());
}),
);
}
}
The problem seems to be coming from as List in the following line of code:
peopleNames.addAll((names['peoplesnames'] as List));
when as List is there I get the followiing red underline error and the code won't run.
The argument type 'List' can't be assigned to the parameter type 'Iterable'.
then, If i remove as List, the red line goes away but when I run the code, i get this error in the console
E/flutter ( 7999): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'List' is not a subtype of type 'Iterable'
I know the app is talking to the server correctly because if i replace
peopleNames.addAll((names['peoplesnames'] as List));
setState(() {});
return names;
with print(names), and run it, the names print in the console.
any help fixing this would be greatly appreciated.
cheers
Here is your answer
void convertJsonToList() {
String jsonData = '''
{
"peoplesnames": [
"name1",
"name2",
"name3",
"name4",
"name5",
"name6",
"name7",
"name8"
]
}
''';
Map<String, dynamic> jsonMap = jsonDecode(jsonData);
peoplesNamesList = List<String>.from(jsonMap['peoplesnames']);
print(peoplesNamesList);
}
Try this:
peopleNames.addAll((names['peoplesnames'].toList()));
I Have One Http Post Method Like This :
class ApiClientController extends GetxController {
Future<GetSideMenuInfoError?> GetInfoAfterLogin() async {
String? value = await storage.read(key: 'skey');
try {
final response = await dio.post(
Constant.baseUrl,
options: Options(
headers: {
"omax-apikey": "apikey",
},
),
data: {
"function": "portal_get_information",
"params": {
"portal_version": "1.0.0",
"portal_os": "linux",
"portal_os_version": "10",
"portal_browser": "chrome",
"portal_guid": "fd298776-6014-11ed-adbc-5256454165"
}
},
);
//print(response.data.toString());
GetSideMenuInfoError? responseBody = getSideMenuInfoErrorFromJson(response.data.toString());
return responseBody;
} on DioError catch (e) {
//return ;
print(e);
}
return null;
//IMPLEMENT USER LOGIN
}
}
And The Result Post Method My Json :
{
"result": 55456465,
"data": {
"reason": "session expired or not valid",
"uuid": "01dfca14-625559-11ed-aafa-0056546546"
}
}
Used This https://app.quicktype.io/ for Parsed Json To dart File Result Like This:
import 'package:meta/meta.dart';
import 'dart:convert';
GetSideMenuInfoError? getSideMenuInfoErrorFromJson(String str) => GetSideMenuInfoError?.fromJson(json.decode(str));
class GetSideMenuInfoError {
GetSideMenuInfoError({
#required this.result,
#required this.data,
});
final int? result;
final Data? data;
factory GetSideMenuInfoError.fromJson(Map<String, dynamic> json) => GetSideMenuInfoError(
result: json["result"],
data: Data.fromJson(json["data"]),
);
}
class Data {
Data({
#required this.reason,
#required this.uuid,
});
final String? reason;
final String? uuid;
factory Data.fromJson(Map<String, dynamic> json) => Data(
reason: json["reason"],
uuid: json["uuid"],
);
}
And My Question Is : How Can I Show value in Dart File Like reason or uuid In Other Class ?
My Way like This in Other Class And Not Worked:
In The Build Widget :
final apiClientController = Get.find<ApiClientController>();
apiClientController.GetInfoAfterLogin();
GetSideMenuInfoError? getSideMenuInfoError;
title: getSideMenuInfoError != null ?
Text(getSideMenuInfoError.result.toString()):Text('',),
Thank You For Helping Me...
Hello Im trying to get data from the Jasonplaceholder Api, and I want to map it in a dart model
but I tried videos on YouTube and none of them work and I use autogenerated models but the data that received are inside a list but in that list have nested maps
var myMap=[{
"name" : "Ravindu",
"age" : 20,
"scl" : "smc",
"address" :
{
"city" : "Kegalle",
"country" : "sri lanka"
}
},
{
"name" : "Ravindu1",
"age" : 20,
"scl" : "smc1",
"address" :
{
"city" : "Kegalle1",
"country" : "sri lanka1"
}
}];
like this I want this to map to a Molde class and also, I want to know how to access Items inside this map tried myMap[0]["address"] but it only retrieve the whole map of address in the 0 index
so How can I pass these type of Json data to a model class
this is the actual url im working with
'''final String url ="https://jsonplaceholder.typicode.com/users"'''
I get this error when I try this on darpad
Uncaught Error: TypeError: Instance of 'JsLinkedHashMap<String, String>': type 'JsLinkedHashMap<String, String>' is not a subtype of type 'List'
this is the code I tried on dartpad
void main() {
var myMap=[{
"name" : "Ravindu",
"age" : 20,
"scl" : "smc",
"address" :
{
"city" : "Kegalle",
"country" : "sri lanka"
}
},
{
"name" : "Ravindu1",
"age" : 20,
"scl" : "smc1",
"address" :
{
"city" : "Kegalle1",
"country" : "sri lanka1"
}
}];
print(myMap[0]);
var addressList = myMap[0]["address"]["city"];
print(addressList);
(addressList as List).forEach((i){
print(i["country"]);
});
}
The addressList will get from myMap[0]["address"] which will be another map. On Map, forEach callback provide key and value .forEach((key, value) {
void main() {
List<Map<String, dynamic>> myMap = [
{
"name": "Ravindu",
"age": 20,
"scl": "smc",
"address": {"city": "Kegalle", "country": "sri lanka"}
},
{
"name": "Ravindu1",
"age": 20,
"scl": "smc1",
"address": {"city": "Kegalle1", "country": "sri lanka1"}
}
];
print(myMap[0].toString());
final addressList = myMap[0]["address"]["city"];
print(addressList.toString()); // kegalle
final Map<String, String> address = myMap[0]["address"];
address.forEach((key, value) {
print(" $key $value");
});
}
I am also using Dart class generator extion
class Person {
final String? name;
final int? age;
final String? scl;
final Address? address;
Person({
this.name,
this.age,
this.scl,
this.address,
});
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
if(name != null){
result.addAll({'name': name});
}
if(age != null){
result.addAll({'age': age});
}
if(scl != null){
result.addAll({'scl': scl});
}
if(address != null){
result.addAll({'address': address!.toMap()});
}
return result;
}
factory Person.fromMap(Map<String, dynamic> map) {
return Person(
name: map['name'],
age: map['age']?.toInt(),
scl: map['scl'],
address: map['address'] != null ? Address.fromMap(map['address']) : null,
);
}
String toJson() => json.encode(toMap());
factory Person.fromJson(String source) => Person.fromMap(json.decode(source));
}
class Address {
final String? city;
final String? country;
Address({
this.city,
this.country,
});
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
if(city != null){
result.addAll({'city': city});
}
if(country != null){
result.addAll({'country': country});
}
return result;
}
factory Address.fromMap(Map<String, dynamic> map) {
return Address(
city: map['city'],
country: map['country'],
);
}
String toJson() => json.encode(toMap());
factory Address.fromJson(String source) => Address.fromMap(json.decode(source));
}
try to get the json structure with this model.
First of all be sure to have json_annotation and http as a normal dependency, and json_serializable, build_runner as a dev dependencies.
Example of pubspec.yaml:
dependencies:
json_annotation: ^4.7.0
# used for HTTP calls
http: ^0.13.5
# other dependencies
dev_dependencies:
build_runner: ^2.3.2
json_serializable: ^6.5.4
# other dependencies
Then you should create a model with the fromJson method. This is going to be used to deserialize the JSON you retrieve from the API call. I'm going to use a Dart file named user.dart
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
#JsonSerializable()
class User {
const User({
required this.id,
required this.name,
required this.username,
required this.email,
required this.address,
});
final int id;
final String name;
final String username;
final String email;
final Address address;
/// Connect the generated [_$UserFromJson] function to the `fromJson`
/// factory.
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
/// Connect the generated [_$UserToJson] function to the `toJson` method.
Map<String, dynamic> toJson() => _$UserToJson(this);
}
#JsonSerializable()
class Address {
const Address({
required this.city,
required this.street,
required this.zipcode,
});
final String city;
final String street;
final String zipcode;
factory Address.fromJson(Map<String, dynamic> json) =>
_$AddressFromJson(json);
Map<String, dynamic> toJson() => _$AddressToJson(this);
}
Now in your Terminal you should run flutter pub run build_runner build --delete-conflicting-outputs to build the generated file, in my case it will generate a file called user.g.dart.
Now you need a service to make the HTTP call and return the list of users, I'm going to create a file called users_service.dart
import 'dart:convert';
import 'package:stackoverflow/user.dart';
import 'package:http/http.dart' as http;
class UsersService {
Future<List<User>> getUsers() async {
final uri = Uri.parse('https://jsonplaceholder.typicode.com/users');
final response = await http.get(uri);
final responseString = response.body;
final jsonList = List.from(jsonDecode(responseString));
return jsonList.map((json) => User.fromJson(json)).toList();
}
}
Here you must focus on the jsonDecode method that converts the JSON to a Dart object, and in the User.fromJson method that deserializes the JSON object converting it into a valid User Dart class.
As you can see the address field is another class with its fromJson implementation.
This is the right way to perform JSON (de)serialization, because it doesn't involve doing it manually (more error prone)
Example usage:
import 'package:stackoverflow/users_service.dart';
Future<void> main() async {
final users = await UsersService().getUsers();
for (final user in users) {
print("${user.name} lives in ${user.address.city}");
}
}
which prints:
Leanne Graham lives in Gwenborough
Ervin Howell lives in Wisokyburgh
Clementine Bauch lives in McKenziehaven
Patricia Lebsack lives in South Elvis
Chelsey Dietrich lives in Roscoeview
Mrs. Dennis Schulist lives in South Christy
Kurtis Weissnat lives in Howemouth
Nicholas Runolfsdottir V lives in Aliyaview
Glenna Reichert lives in Bartholomebury
Clementina DuBuque lives in Lebsackbury
I have set up the streambuilder and stream async functions,but i do not know how to use it properly as it needs websockets. How can i use websockets in these case to fetch my Json data from my server?
Stream<List<Post>> FetchPosts(http.Client client) async* {
final response = await http.get("$SERVER_IP/api/articles/?format=json");
final parsed = jsonDecode(utf8.decode(response.bodyBytes)).cast<Map<String, dynamic>>();
yield parsed.map<Post>((json) => Post.fromJSON(json)).toList();
}
StreamBuilder<List<Post>>(
stream: FetchPosts(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData ? PostsList(posts: snapshot.data)
:
Center(child: CircularProgressIndicator(backgroundColor: Colors.pink,valueColor: new AlwaysStoppedAnimation<Color>(Colors.pinkAccent)));
},
),
Class
class Post {
final String id;
final String author;
final String caption;
Post({this.id, this.author,this.caption});
factory Post.fromJSON(Map<String, dynamic> jsonMapPost) {
return Post(
id: jsonMapPost['id'] as String,
caption: jsonMapPost['caption'] as String,
author: jsonMapPost['author'] as String,);}}
Json data
[{"id":"a4d64194-3d81-4a4e-b7e6-6fce36fea793","author":"a94d4433-ffaf-4af1-aa8d-67ac75bf2e53","caption":"this is caption",]}
You can use web_socket_channel package that provides StreamChannel wrappers for WebSocket connections.
With it you fetchPosts function can turn into something like that:
Stream<List<Post>> fetchPosts() {
final channel = IOWebSocketChannel.connect(Uri.parse("$SERVER_IP/api/articles/?format=json"));
return channel.stream.map((r) => parse(r));
}
If your websocket server emits message in this format:
[
{
"id": "a4d64194-3d81-4a4e-b7e6-6fce36fea793",
"author": "a94d4433-ffaf-4af1-aa8d-67ac75bf2e53",
"caption": "this is caption"
}
]
then your parse function can look like that:
List<Post> parse(String message) {
final json = jsonDecode(message) as List<dynamic>;
return json.map((j) => Post.fromJSON(j as Map<String, dynamic>)).toList();
}
I have a Json file having some user data as an array , I am able to read those data in my flutter project , But what I wanna do is to add some other user from the data I receive from the textfield in my flutter app.
Can anyone tell me how to do that ? Thanks in advance.
My Json file looks something like this.
{
"users": [
{
"id": 1,
"username": "steve",
"password": "captainamerica"
}
]
}
and I have to add another user with id - 2, username - tony, and password - ironman.
I have tried showing you how to map the JSON to OBJECT and then add a new user to the users object and then to JSON again.
Here's the complete code:
If you have any doubts, please ask:
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
UsersPodo _usersPodo; // Users object to store users from json
// A function that converts a response body into a UsersPodo
UsersPodo parseJson(String responseBody) {
final parsed = json.decode(responseBody);
return UsersPodo.fromJson(parsed);
}
class Demo extends StatefulWidget {
#override
_Demo createState() => _Demo();
}
class _Demo extends State<Demo> {
final String localJson = '''
{
"users": [
{
"id": 1,
"username": "steve",
"password": "captainamerica"
}
]
}'''; // local json string
Future<UsersPodo> fetchJSON() async {
return compute(parseJson, localJson);
}
Widget body() {
return FutureBuilder<UsersPodo>(
future: fetchJSON(),
builder: (context, snapshot) {
return snapshot.hasError
? Center(child: Text(snapshot.error.toString()))
: snapshot.hasData
? _buildBody(usersList: snapshot.data)
: Center(child: Text("Loading"));
},
);
}
Widget _buildBody({UsersPodo usersList}) {
_usersPodo = usersList;
_usersPodo.users.add(new Users(id: 1, username: "omishah", password: "somepassword")); // add new user to users array
return Text(_usersPodo.users[1].toJson().toString()); // just for the demo output
// use _usersPodo.toJson() to convert the users object to json
}
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xfff3f3f3),
appBar: AppBar(backgroundColor: Colors.red[900], title: Text("DEMO")),
body: body());
}
}
// PODO Object class for the JSON mapping
class UsersPodo {
List<Users> users;
UsersPodo({this.users});
UsersPodo.fromJson(Map<String, dynamic> json) {
if (json['users'] != null) {
users = new List<Users>();
json['users'].forEach((v) {
users.add(new Users.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.users != null) {
data['users'] = this.users.map((v) => v.toJson()).toList();
}
return data;
}
}
class Users {
int id;
String username;
String password;
Users({this.id, this.username, this.password});
Users.fromJson(Map<String, dynamic> json) {
id = json['id'];
username = json['username'];
password = json['password'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['username'] = this.username;
data['password'] = this.password;
return data;
}
}