How do I return the first five values from JSON response DART - flutter

I would like to return the first five value of name from the JSON response above
Future <List<UserModel>> fetchData() async {
final response =
await http.get(Uri.parse(URLCONST.API_URL));
if (response.statusCode == 200) {
List jsonResponse = json.decode(response.body);
return jsonResponse.map((user) => new UserModel.fromJson(user)).toList();
} else {
throw Exception('Unexpected error occured!');
}
}
Here's the model below.
class UserModel {
int id;
String name;
UserModel({
required this.id,
required this.name,
});
factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel(
id: json['id'],
name: json['name'],
);
}
}
API has several values in the list and I'd like to return the first 5 only

if i understood correctly, you can do something like this:
jsonResponse.map((user) => new UserModel
.fromJson(user))
// this will take only the first five elements of the iterable
.take(5)
// this will map each user to its corresponding name
.map((user) => user.name)
// this, as you already know, will convert the iterable to a list
.toList();
this will return a List<String> containing the first five names

Related

Convert class object to data value flutter dart

This is my JSON:
{
'malls' : [{'id':1 , 'name': 'salam'},{'id':2 , 'name': 'salam2'}]
}
And this is my modeling JSON classes:
class MALL {
final int id;
final String name;
MALL({required this.id, required this.name});
factory MALL.fromJson(Map<String, dynamic> data) {
return MALL(id: data['id'], name: data['name']);
}
}
class City {
final List<MALL> malls;
City({required this.malls});
factory City.fromJson(Map<String, dynamic> data) {
var list = data['malls'] as List;
List<MALL> mallList = list.map((i) => MALL.fromJson(i)).toList();
return City(malls: mallList);
}
}
This is my get method:
Future<List<MALL>> get() async {
var response = await http.get(Uri.parse(URL), headers: {"authorization": "Bearer ${token}", "Content-Type": "application/json"});
var data = jsonDecode(response.body);
City api = City.fromJson(data);
return data['malls'];
}
I get this output:
[Instance of 'MALL', Instance of 'MALL']
I want my JSON in output by I got the instance of my classes.
How can I convert the instances to my data? It means I want to return my JSON in output and I can access the keys of malls in my FutureBuilder.
If you wanna print the response of a Class you can override the toString method to print the response of the Class. Example:
class MALL {
final int id;
final String name;
MALL({required this.id, required this.name});
factory MALL.fromJson(Map<String, dynamic> data) {
return MALL(id: data['id'], name: data['name']);
}
#override
String toString() => "{ id : $id, name : $name}";
}
Now you will see the result in console.
Inside your FutureBuilder yo will get list of Malls. Thats you have to use loop or list view builder to access those elemet.
if you want to print the list data. you have to print first element
inside your future build when data is loded.
print(data.first.toString())
add this line of code inside your malls calss
#override
String toString() => "{ id : $id, name : $name}";

How to assign List<dynamic> to List<Khana>, where Khana is a model class in a parameter in Flutter-Firestore?

Actually, I am trying to get data from firebase and I am suffering from the Error:
Expected a value of type List < Khana >, but got one of type 'List< dynamic >'
I am getting data from the firebase, my fetchData function is:
Future<void> fetchAndSetOrder() async {
try {
await collectionRef.get().then((querySnapshot) {
for (var result in querySnapshot.docs) {
debugPrint("${result.runtimeType}=> ${result.data()}");
Orders newOrder = Orders.fromFirestore(result);
debugPrint("\n new order : $newOrder");
// _Order.add(newOrder);
debugPrint("new order added");
// _Order.add(Orders.fromMap(result as Map));
}
});
} catch (e) {
debugPrint("Error during Fetch:- $e");
}
}
and the Orders.fromFirestore constructor is:
factory Orders.fromFirestore(DocumentSnapshot<Object?> snapshot) {
final data = snapshot.data() as LinkedHashMap<String, dynamic>;
debugPrint("Inside From Firestore Function");
return Orders(
khana: data['khana'], // here is the error...
orderNumber: data['orderNumber'],
userId: data['userId'],
paymentCash: data['paymentCash'],
dateTime: data['dateTime'],
);
}
Orders class has:
class Orders{
List<Khana> khana; // this is another ModelClass
String userId;
int orderNumber;
DateTime dateTime;
bool paymentCash;
Orders({
required this.khana,
required this.userId,
required this.orderNumber,
required this.dateTime,
required this.paymentCash,
});
}
so, the issue is how can I read List from the firestore as a List ? Any other possible way to solve this issue.
My Khana Model is:
import 'dart:convert';
class Khana {
String mealName;
int id;
int price;
int quantity;
Khana({
required this.mealName,
required this.price,
required this.quantity,
required this.id,
});
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
result.addAll({'mealName': mealName});
result.addAll({'id': id});
result.addAll({'price': price});
result.addAll({'quantity': quantity});
return result;
}
factory Khana.fromMap(Map<String, dynamic> map) {
return Khana(
mealName: map['mealName'] ?? '',
id: map['id']?.toInt() ?? 0,
price: map['price']?.toInt() ?? 0,
quantity: map['quantity']?.toInt() ?? 0,
);
}
String toJson() => json.encode(toMap());
factory Khana.fromJson(String source) => Khana.fromMap(json.decode(source));
}
I am trying to read a List from the firestore snapshot.data(), it says it's return data type is List, and I want this list to be assigned to the List of my own ModelClass (i.e Khana), and I am not able to do that.
I even tried
factory Orders.fromFirestore(DocumentSnapshot<Object?> snapshot) {
final data = snapshot.data() as LinkedHashMap<String, dynamic>;
debugPrint("Inside From Firestore Function");
return Orders(
khana: data['khana'] as List<Khana>,
orderNumber: data['orderNumber'],
userId: data['userId'],
paymentCash: data['paymentCash'],
dateTime: data['dateTime'],
);
}
but got the same issue :(
Change your khana to this
khana: List<Khana>.from(data['khana'].map((x)=>Khana.fromJson(x)));

Error listing information from an API (Expected a value of type 'int', but got one of type 'String')

I'm getting information from a REST API, but when displaying the information I get the error:
Error: Exception: Expected a value of type 'int', but got one of type 'String'
This is my get method:
Future<List<Requests>> searchRequests() async {
try {
final response = await http.get(
Uri.parse(BaseUrl.baseUrl + 'api/search'));
if (response.statusCode == 200) {
List<Requests> list = parseRequests(response.body);
return list;
} else {
throw Exception("Error");
}
} catch (e) {
throw Exception(e.toString());
}
}
static List<Requests> parseRequests(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();
return parsed
.map<Requests>((json) => Requests.fromJson(json))
.toList();
}
and defined my model like this:
import 'package:flutter_gentelella/models/usuario.dart';
class Requests {
final String id;
final String data1;
final String data2;
final int data3;
const Requests({
required this.id,
required this.data1,
required this.data2,
required this.data3,
});
factory Requests.fromJson(Map<String, dynamic> json) {
return Solicitacoes(
id: json['_id'],
data1: json['data1'],
data2: json['data2'],
data3: json['user']['data3']);
}
Map<String, dynamic> toJson() => {
'_id': id,
'data1': data1,
'data2': data2,
'data3': data3,
};
}
At what point in the code do I convert to int?
I'm trying to generate the order list on the screen but I get the error reported above. I appreciate if someone helps me analyze!
I'd say that the problem is with the field data3: it's the only thing I see in your code defined as an int, and the error is telling you that something was expected as int but it came up as String.
Something like this shouls work (just handle the case in which data3 is not a number appropriately):
factory Requests.fromJson(Map<String, dynamic> json) {
return Solicitacoes(
id: json['_id'],
data1: json['data1'],
data2: json['data2'],
data3: int.tryParse(json['user']['data3']) ?? 'Not a number');
}

Flutter Firestore array with Maps. Do they work?

I can't stream (read) Documents that contain array properties that are Maps in Firestore.
Using Firestore with a document containing an array with a simple String type works as expected. Easy to write (append with FieldValue.arrayUnion(['data1','data2','data3']) and stream back out with code like:
var test2 = List<String>();
for (var item in data['items']) {
print('The item $item');
test2.add(item);
}
test2 can now be used as my items property.
When I try and use a List where item type becomes a Map in Firestore and is just a simple Class containing a few Strings and a date property. I can write these to FireStore but I can't read them back out.
The following code fails: (no errors in the Debug Console but it doesn't run)
var test2 = List<Item>();
data['items'].forEach((item) {
var description = item['description'];
print('The description $description'); // <-- I don't get past this
final x = Item.fromMap(item); // <-- so I can't even attempt this
return test2.add(x);
});
I never get to actually call my Item.fromMap constructor: here is another try:
// fails
final theItems = data['items'].map((x) {
return Item.fromMap(x); // <-- never get here
});
Although the DEBUG CONSOLE doesn't say there is any problem. If I inspect theItems variable (the debugger 'jumps' a couple of lines down to my return) after the failed iteration it looks like this:
MappedListIterable
_f:Closure
_source:List (1 item)
first:Unhandled exception:\ntype '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of type 'Map<String, dynamic>'\n#0 new Listing.fromMap.<anonymous closure> isEmpty:false
isNotEmpty:true
iterator:ListIterator
last:Unhandled exception:\ntype '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of
So bad things have happened but I have no idea why!
Has anyone actually written and retrieved Firestore array properties that contain Maps?
Any help in how to proceed would be greatly appreciated!
More: screen shot of the document
Here is the code that reads (streams) the collection
Stream<List<T>> collectionStream<T>({
#required String path,
#required T builder(Map<String, dynamic> data, String documentID),
#required String userId,
Query queryBuilder(Query query),
int sort(T lhs, T rhs),
}) {
Query query = Firestore.instance.collection(path);
if (queryBuilder != null) {
query = queryBuilder(query);
}
final Stream<QuerySnapshot> snapshots = query.snapshots();
return snapshots.map((snapshot) {
//print('document: path $path ${snapshot.documents[0]?.documentID}');
final result = snapshot.documents
.map((snapshot) => builder(snapshot.data, snapshot.documentID))
.where((value) => value != null)
.toList();
if (sort != null) {
result.sort(sort);
}
print('returning from CollectionStream');
return result;
});
}
the .map is where the problem comes in. The builder function resolves to this:
builder: (data, documentId) {
return Listing.fromMap(data, documentId);
},
Which ends up here
factory Listing.fromMap(
Map<String, dynamic> data,
String documentId,
) {
if (data == null) {
return null;
}
final theTime = (data['createdAt'] as Timestamp).toDate();
// see above code where I fail at getting at the items property/field
Here is the Item Class:
class Item {
Item(this.description, this.imageURL, this.thumbnailURL,
{this.status = ItemStatus.active,
this.type = ListingType.free,
this.price = 0,
this.isUpdate = false,
this.createdAt});
final String description;
final String imageURL;
final String thumbnailURL;
final ItemStatus status;
final ListingType type;
final int price;
final bool isUpdate;
DateTime createdAt;
factory Item.fromMap(
Map<String, dynamic> data,
) {
if (data == null) {
return null;
}
final theTime = (data['createdAt'] as Timestamp).toDate();
return Item(
data['description'],
data['imageURL'],
data['thumbnailURL'],
status: _itemStatusFromString(data['status']),
type: data['type'] == 'free' ? ListingType.free : ListingType.flatRate,
createdAt: theTime,
);
}
Map<String, dynamic> toMap() {
// enums are for shit in Dart
final statusString = status.toString().split('.')[1];
final typeString = type.toString().split('.')[1];
return {
'description': description,
'imageURL': imageURL,
'thumbnailURL': thumbnailURL,
'itemStatus': statusString,
'price': price,
'listingType': typeString,
if (!isUpdate) 'createdAt': DateTime.now(),
if (isUpdate) 'updatedAt': DateTime.now(),
};
}
}
The above is never called to read (we crash) ... it is called to write the data.
This is a known issue with Firestore. Here is the starting thread Flutter issues I found
From reading through the issues it seems lots of folks use a serializer package which is where the issue surfaced. Its still active...
Here is my solution NOT using a serializer and just doing it 'by hand'.
I was able simplify the problem and generate an error that was Google-able. Below is a single page which just writes and reads a single Document. The Class A and B are as small as can be.
So the code writes a single document to Firestore the contains two properties. A name and items. The items being the List of Class B that Class A contains. Checkout the Firebase console. The reading just does that.
No StreamController just the Console. The problem is in the fromMap method where we have to convert the array of objects in Firesote to a List of class instances in Dart. This should not be this difficult and at a minimum it should be documented ....
the line
var theRealItems = data['items'].map((i) => B.fromMap(i));
will generate the error. And needs to be replaced with
var theItems = data['items'].map((i) {
var z = Map<String, dynamic>.from(i);
print(z['description']);
return B.fromMap(z);
}).toList();
var theRealItems = List<B>.from(theItems);
Why this is so difficult is still a mystery to me! Anyone improving this code: I'm all ears.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class A {
A(this.name, this.items);
final name;
final List<B> items;
factory A.fromMap(
Map<String, dynamic> data,
String documentId,
) {
if (data == null) {
return null;
}
// we crash here !!!
var theRealItems = data['items'].map((i) => B.fromMap(i));
// uncomment the 6 lines below
// var theItems = data['items'].map((i) {
// var z = Map<String, dynamic>.from(i);
// print(z['description']);
// return B.fromMap(z);
// }).toList();
// var theRealItems = List<B>.from(theItems);
return A(data['name'], theRealItems);
}
Map<String, dynamic> toMap() {
var theItems = items.map((i) => i.toMap()).toList();
return {'name': name, 'items': theItems};
}
}
class B {
B(this.description);
final description;
factory B.fromMap(
Map<String, dynamic> data,
) {
if (data == null) {
return null;
}
return B(data['description']);
}
Map<String, dynamic> toMap() {
return {
'description': description,
};
}
}
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: () => _write(),
child: Text('Write the Doc'),
),
RaisedButton(
onPressed: () => _read(),
child: Text('Read the Doc ... check Debug Console!'),
),
],
),
),
);
}
_write() async {
try {
var b = B('Inside B!');
List<B> theList = List<B>();
theList.add(b);
var a = A('myName', theList);
await Firestore.instance
.collection('test')
.document('testDoc')
.setData(a.toMap());
print('returning from write!');
} catch (e) {
print('Error ${e.toString()}');
}
}
_read() async {
try {
var aFromFs = await Firestore.instance
.collection('test')
.document('testDoc')
.get();
var a = A.fromMap(aFromFs.data, aFromFs.documentID);
print('the A from FireBase $a with name ${a.name} first item ${a.items.first.description}');
print('returning from read!');
} catch (e) {
print('Oh no Error! ${e.toString()}');
}
}
}
In the below code Name refers to the name of your respective document and collection.
Let's say you want to get "imageURL" and "thumbnailUrl" for now and update the values without deleting or changing other fields inside the array.
String imageUrl ;
String thumbnailUrl;
DocumentReference _docReference = FirebaseFirestore.instance.collection(NAME).doc(NAME);
//refering to the specific document
Map<String, dynamic> neededData= allDocsFromTraining.data();
//getting all the keys and values inside the document
List<Map<String, dynamic>> _yourDocument=
(neededData["items"] as List<dynamic>)
.map((m) => Map<String, dynamic>.from(m))
.toList();
//only getting the list of items
for (int index = 0; index < _yourDocument.length; index++) {
Map<String, dynamic> _getMap = _yourDocument[index];
if (_getMap["price"] == 0)
//giving a condition to get the desired value and make changes
{
//setting the variables with the value from the database
setState(() {
imageUrl = _getMap["imageURL"];
thumbnailUrl = _getMap["thumbnailURL"]
});
///Use this if you want to update value of imageURL and thumbnailURL at that specific index of an array
_getMap['imageURL'] = "Your Updated URL";
_getMap['thumbnailURL'] = "Your Updated Url;
break;
} else {}
}
await _docReference.update({"items": _yourDocument});
//this adds the updated value to your database.

Convert list of object with array to and from json file

I want to convert a list of 'Box' objects to a json file and also read it back in (json file to a list a 'Box' objects), but I'm a bit stuck on the implementation. I have written the below code, but I can only write a single 'Box' object to the json and convert a single 'Box' object back. When I try to do this with a list I hit errors like data that gets overwritten or just a single object that gets returned.
So in short, I want to write a List to json and convert json to List
I have the following data structure
Box model
class Box {
final String nameBox;
final List<Item> items;
Box({#required this.nameBox, #required this.items});
factory Box.fromJson(Map<String, dynamic> json) {
var items = json['items'];
List<Item> itemsList = items.cast<Item>();
return new Box(
nameBox: json["nameBox"],
items: itemsList
);
}
Map<String, dynamic> toJson() => {
"nameBox": nameBox,
"items": items,
};
}
Box fromJson(String boxData) {
return Box.fromJson(json.decode(boxData));
}
String toJson(Box box) {
return json.encode(box.toJson());
}
Item model
class Item {
final String itemName;
final int quantity;
Item({#required this.itemName, #required this.quantity});
factory Item.fromJson(Map<String, dynamic> json) {
return new Item(itemName: json["itemName"], quantity: json["quantity"]);
}
Map<String, dynamic> toJson() => {
"itemName": itemName,
"quantity": quantity,
};
}
Item fromJson(String itemData) {
return Item.fromJson(json.decode(itemData));
}
String toJson(Item item) {
return json.encode(item.toJson());
}
writeToJson function
Future writeJson(Box box) async {
final file = await _localFile;
List<Box> tempRead = await returnBoxes();
if (tempRead.isEmpty || tempRead == null) {
return;
}
tempRead.add(box);
file.writeAsString(json.encode(tempRead));
}
readJson function
Future<List<Box>> returnBoxes() async {
final file = await _localFile;
List<Box> boxList = new List<Box>();
Map<String, dynamic> content = await json.decode(file.readAsStringSync());
boxList.add(Box.fromJson(content));
return boxList;
}
I also tried to cast the json content to a list, but then I hit some iterable errors. Any who can help me out?
JSON has this idiosyncrasy that everything is either an object or an array, and you don't know what you get until you decode it. Dart decodes the two json types into a Map<String, dynamic> and List<dynamic> respectively. (The reason that you get dynamic is because each of them could itself then be a value, a json array or a json object, recursively.)
Dart encodes a Dart object by calling toJson on it and a Dart list by emitting a [ then each member of the list then a ].
Knowing that, it's easy to encode and decode arrays/lists. (I removed all the unnecessary code.)
class Box {
final String nameBox;
final List<Item> items;
Box({#required this.nameBox, #required this.items});
factory Box.fromJson(Map<String, dynamic> json) => Box(
nameBox: json['nameBox'],
items: json['items'].map<Item>((e) => Item.fromJson(e)).toList(),
);
Map<String, dynamic> toJson() => {
'nameBox': nameBox,
'items': items,
};
}
class Item {
final String itemName;
final int quantity;
Item({#required this.itemName, #required this.quantity});
factory Item.fromJson(Map<String, dynamic> json) => Item(
itemName: json['itemName'],
quantity: json['quantity'],
);
Map<String, dynamic> toJson() => {
'itemName': itemName,
'quantity': quantity,
};
}
Future writeJson(Box box) async {
final file = await _localFile;
var boxes = await returnBoxes();
/* I think you probably don't want this...
if (boxes.isEmpty || boxes == null) {
return;
}*/
// but rather, this
if (boxes == null) boxes = [];
boxes.add(box);
await file.writeAsString(json.encode(boxes));
}
Future<List<Box>> returnBoxes() async {
final file = await _localFile;
// because the json is an array (i.e. enclosed in []) it will be decoded
// as a Dart List<dynamic>
List<dynamic> d = json.decode(await file.readAsString());
// here we map the List<dynamic> to a series of Box elements
// each dynamic is passed to the Box.fromJson constructor
// and the series is formed into a List by toList
return d.map<Box>((e) => Box.fromJson(e)).toList();
}