i try to build a map to add it into firestore.
Produkt Class:
class Produkt{
String name;
int anzahl;
Produkt({
this.name,
this.anzahl,
});
factory Produkt.fromJson(Map<String, dynamic> parsedJson){
return Produkt(
name:parsedJson['Name'],
anzahl:parsedJson['Anzahl']
);
}
Map<String, dynamic> toProduktJson() =>
{
"Name" : name,
"Anzahl" : anzahl
};
}
ProduktList Class:
class ProduktList{
final List<Produkt> produkte;
ProduktList({
this.produkte,
});
factory ProduktList.fromJson(Map<String, dynamic> parsedJson){
var list = parsedJson["Produkte"] as List;
List<Produkt> produkte = list.map((i) => Produkt.fromJson(i.cast<String, dynamic>())).toList();
return ProduktList(
produkte: produkte,
);
}
Map<String, dynamic> toProdukteJson() =>
{
"Produkte" : [
produkte[0].toProduktJson(),
produkte[1].toProduktJson(),
produkte[2].toProduktJson(),
]
};
}
I wanted that the Map looks like:
{
"Produkte" : [
produkte[0].toProduktJson(),
produkte[1].toProduktJson(),
produkte[2].toProduktJson(),
]
};
But if the List produkte has a length of 2, the Map should have 2 and it the List have a length of 10, the Map should have 10 entries.
How can i do this?
Pls help me.
Thank you
An option would be the following:
Map<String, dynamic> toProdukteJson() {
Map map = new Map<String, dynamic>();
if (produkte != null) {
map["produkte"] = produkte.map((produkt) => produkt.toJson()).toList();
}
return map;
}
class Produkt {
final String id;
...
Produkt(this.id, ...);
Map toJson() => {'id' : id, ...};
}
Related
I have a Map of List of Maps as a set of data (dataMap) and want to transform like below with using Map.update method. This caught an error: Uncaught Error: TypeError: Closure 'main__convertIdFromStringToDocRef_closure': type '(dynamic) => num' is not a subtype of type '(String) => String'. I should misunderstand something about Map.update, but am not sure what it is... Can you please teach me?
void main() {
num _convertStringToNum(dynamic str, String collection) {
if (str is String) { return num.tryParse(str); }
if (str is num) { return str; }
return null;
}
Map<String, dynamic> _convertIdFromStringToNum(Map<String, dynamic> map, String collection) {
map.update('id', (mapId) => _convertStringToNum(mapId, collection));
return map;
}
Map<String, dynamic> dataMap = {
'types': [
{
'id': '123',
'name': 'foo',
},
{
'id': '234',
'name': 'bar',
}
],
};
dataMap.update('types', (types) {
if (!(types is List<Map<String, dynamic>>)) { return null; }
types.map((Map<String, dynamic> type) => _convertIdFromStringToNum(type, 'types')).toList();
return types;
});
}
This code can run on DartPad.
I had strange issue as in Yours too.
Seems like if map entry is initialised with String it cannot be modified to num:
Map<String, dynamic> item = {
"id": "123",
"name": "TEST"
};
// this throws exception that `item['id']` has `String` value and we are trying to replace it with `num`
item['id'] = num.tryParse(item['id']);
I found workaround by creating custom class with constructor which converts input to necessary type of field:
class Type {
num id;
String name;
num convertToNum(dynamic input) {
switch (input.runtimeType) {
case int: break;
case num: break;
case String: return num.tryParse(input); break;
default: return null;
}
return input;
}
Type(id, name) {
this.id = convertToNum(id);
this.name = name;
}
static fromMap(Map map) {
return Type(map['id'], map['name']);
}
Map toMap() {
return {
"id": this.id,
"name": this.name
};
}
}
and while iterating list using .map I'm creating instance of Type and calling toMap method which returns unique object.
void main() {
Map<String, dynamic> dataMap = {
'types': [
{
'id': 111,
'name': 'foo',
},
{
'id': '123',
'name': 'foo',
},
{
'id': '234',
'name': 'bar',
}
],
};
dataMap['types'] = (dataMap['types'] is List<Map>)
? dataMap['types'].map((type) => Type.fromMap(type).toMap())
: null;
print(dataMap);
}
I found the solution by myself. (But still have an unclear points on the real cause...)
The problem is with .map(MapEntry<K2, V2> f(K key, V value)) method. The argument of the method is a function MapEntry<K2, V2> f(K key, V value), and as described in the code I expect Map<String, dynamic> on its key, but actually it is JsLinkedHashMap<String, String> (the value is String). As I tried assigning non-String value through map.update('id', (mapId) => _convertStringToNum(mapId, collection)); in the function _convertIdFromStringToNum, it throw the exception.
So I changed the code as below. I create a new Map<String, dynamic> (newMap) and then do .update() on it.
void main() {
num _convertStringToNum(dynamic str, String collection) {
if (str is String) { return num.tryParse(str); }
if (str is num) { return str; }
return null;
}
Map<String, dynamic> _convertIdFromStringToNum(Map<String, dynamic> map, String collection) {
final Map<String, dynamic> newMap = Map<String, dynamic>.from(map);
newMap.update('id', (mapId) => _convertStringToNum(mapId, collection));
return newMap;
}
Map<String, dynamic> dataMap = {
'types': [
{
'id': '123',
'name': 'foo',
},
{
'id': '234',
'name': 'bar',
}
],
};
dataMap.update('types', (types) {
if (!(types is List<Map<String, dynamic>>)) { return null; }
return types.map((Map<String, dynamic> type) => _convertIdFromStringToNum(type, 'types')).toList();
});
}
I'm new to Dart 2. I want a class to have a property. It's a reference of other class. it's not an instance but class itself. In TypeScript, it's possible to write as below. Is there a same way in Dart 2?
class Item { }
class ItemList {
itemClass: typeof Item;
}
const itemList = new ItemList();
itemList.itemClass = Item;
UPDATED:
I added some more context. The following is minimal sample code. I want to delegate a role of instantiation to super class.
class RecordBase {
id = Math.random();
toJson() {
return { "id": this.id };
};
}
class DbBase {
recordClass: typeof RecordBase;
create() {
const record = new this.recordClass();
const json = record.toJson();
console.log(json);
}
}
class CategoryRecord extends RecordBase {
toJson() {
return { "category": "xxxx", ...super.toJson() };
};
}
class TagRecord extends RecordBase {
toJson() {
return { "tag": "yyyy", ...super.toJson() };
};
}
class CategoryDb extends DbBase {
recordClass = CategoryRecord;
}
class TagDb extends DbBase {
recordClass = TagRecord;
}
const categoryDb = new CategoryDb();
categoryDb.create();
const tagDb = new TagDb();
tagDb.create();
I have tried to make you sample code into Dart. As I told before, you cannot get a reference to a class and call the constructor on runtime based on this reference.
But you can make a reference to a method which constructs the object of you class.
import 'dart:math';
class RecordBase {
static final Random _rnd = Random();
final int id = _rnd.nextInt(100000);
Map<String, dynamic> toJson() => <String, dynamic>{'id': id};
}
abstract class DbBase {
final RecordBase Function() getRecordClass;
RecordBase record;
Map<String, dynamic> json;
DbBase(this.getRecordClass);
void create() {
record = getRecordClass();
json = record.toJson();
print(json);
}
}
class CategoryRecord extends RecordBase {
#override
Map<String, dynamic> toJson() {
return <String, dynamic>{'category': 'xxxx', ...super.toJson()};
}
}
class TagRecord extends RecordBase {
#override
Map<String, dynamic> toJson() {
return <String, dynamic>{'tag': 'yyyy', ...super.toJson()};
}
}
class CategoryDb extends DbBase {
CategoryDb() : super(() => CategoryRecord());
}
class TagDb extends DbBase {
TagDb() : super(() => TagRecord());
}
void main() {
final categoryDb = CategoryDb();
categoryDb.create(); // {category: xxxx, id: 42369}
final tagDb = TagDb();
tagDb.create(); // {tag: yyyy, id: 97809}
}
I am not really sure if the create() method should be seen as a method or a constructor. So I choose to make it a method to be closer to your code.
How to get one by one values in Nested structures with Lists json structure.
controller.dart
final jsonResponse = json.decode(response.body);
AssetRegister model = AssetRegister.fromJson(jsonResponse);
print(model.data);
how to print like this print(model.dart.i);//error
model.dart
class AssetRegister {
final List<Data> data;
AssetRegister({this.data});
factory AssetRegister.fromJson(Map<String, dynamic> json) {
var list = json['data'] as List;
print(list.runtimeType);
List<Data> assetList = list.map((i) => Data.fromJson(i)).toList();
return AssetRegister(data: assetList);
}
}
class Data {
final int i;
final String d;
Data({this.i, this.d});
factory Data.fromJson(Map<String, dynamic> json) {
return Data(
i: json['i'],
d: json['d'],
);
}
}
You should provide toString method implementation for Data class like this:
class Data {
final int i;
final String d;
Data({this.i, this.d});
factory Data.fromJson(Map<String, dynamic> json) {
return Data(
i: json['i'],
d: json['d'],
);
}
#override
String toString() => return 'i = $i, $d';
}
i created a method and when i built it, this error comes:
type '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of type 'List<dynamic>' in type cast
Then i deleted the method and the error is still there.
Here my Code:
class Produkt{
String name;
int anzahl;
Produkt({
this.name,
this.anzahl,
});
factory Produkt.fromJson(Map<String, dynamic> parsedJson){
return Produkt(
name:parsedJson['Name'],
anzahl:parsedJson['Anzahl']
);
}
Map<String, dynamic> toProduktJson() =>
{
"Name" : name,
"Anzahl" : anzahl
};
}
Class ProduktList
class ProduktList{
final List<Produkt> produkte;
ProduktList({
this.produkte,
});
factory ProduktList.fromJson(Map<String, dynamic> parsedJson){
var list = parsedJson["Produkte"] as List;
List<Produkt> produkte = list.map((i) => Produkt.fromJson(i.cast<String, dynamic>())).toList();
return ProduktList(
produkte: produkte,
);
}
Map<String, dynamic> toProdukteJson() =>
{
"Produkte" : [
produkte[0].toProduktJson(),
produkte[1].toProduktJson(),
]
};
}
I think the error comes from here, but i am not sure:
datenUebertragen(int index, AsyncSnapshot<QuerySnapshot> snapshot, ProduktList produkte){
Firestore.instance.runTransaction((transaction) async{
await transaction.update(
Firestore.instance.collection("Benutzer").document("Anton").collection("Einkaufsliste").document(
snapshot.data.documents[index].documentID),
produkte.toProdukteJson()
);
}
);
}
I call this method on an IconButton onPressed.
Can anyone help me?
Thank you
EDIT:
I call it like this:
ProduktList produkte = new ProduktList.fromJson(snapshot.data.documents[index].data);
the data look like:
{Produkte: [{Anzahl: 201, Name: Zucker}, {Anzahl: 10, Name: Backpulver}]}
EDIT:
It looks like this!
EDIT:
try changing this :
var list = parsedJson["Produkte"] as List;
to this :
final List list = parsedJson["Produkte"] as List;
I asked a question before about Dart encoding/decoding to JSON, however, the libraries that were suggested were not complete and I decided to manually handle that.
The objective is to convert these objects to a map.
class Parent extends Object {
int id;
String name;
List<Child> listChild = new List<Child>();
Map toMap() => {"id":id, "name":name, "listChild":listChild};
}
class Child extends Object {
int id;
String childName;
Map toMap() => {"id":id, "childName":childName};
}
When doing
print(JSON.encode(parent.toMap()));
I am seeing it go here, any suggestion how to make this work?
if (!stringifyJsonValue(object)) {
checkCycle(object);
try {
var customJson = _toEncodable(object);
if (!stringifyJsonValue(customJson)) {
throw new JsonUnsupportedObjectError(object);
}
_removeSeen(object);
} catch (e) {
throw new JsonUnsupportedObjectError(object, cause : e);
}
}
}
Map toMap() => {"id":id, "name":name: "listChild": listChild.map((c) => c.toJson().toList())};
is valid for JSON.
import 'dart:convert' show JSON;
...
String json = JSON.encode(toMap());
You can also use the toEncodeable callback - see How to convert DateTime object to json
If your class structure does not contain's any inner class then follow
class Data{
String name;
String type;
Map<String, dynamic> toJson() => {
'name': name,
'type': type
};
}
If your class uses inner class structure
class QuestionTag {
String name;
List<SubTags> listSubTags;
Map<String, dynamic> toJson() => {
'name': name,
'listSubTags': listSubTags.map((tag) => tag.toJson()).toList()
};
}
class SubTags {
String tagName;
String tagDesc;
SubTags(this.tagName, this.tagDesc);
Map<String, dynamic> toJson() => {
'tagName': tagName,
'tagDesc': tagDesc,
};
}
Just rename Map toMap() into Map toJson() and it will work fine. =)
void encode() {
Parent p = new Parent();
Child c1 = new Child();
c1 ..id = 1 ..childName = "Alex";
Child c2 = new Child();
c2 ..id = 2 ..childName = "John";
Child c3 = new Child();
c3 ..id = 3 ..childName = "Jane";
p ..id = 1 ..name = "Lisa" ..listChild = [c1,c2,c3];
String json = JSON.encode(p);
print(json);
}
class Parent extends Object {
int id;
String name;
List<Child> listChild = new List<Child>();
Map toJson() => {"id":id, "name":name, "listChild":listChild};
}
class Child extends Object {
int id;
String childName;
Map toJson() => {"id":id, "childName":childName};
}