I am learning flutter and trying to parse a json which is array or json objects like this.
[
{
"albumId": 1,
"id": 1,
"title": "accusamus beatae ad facilis cum similique qui sunt",
"url": "https://via.placeholder.com/600/92c952",
"thumbnailUrl": "https://via.placeholder.com/150/92c952"
},
{
"albumId": 1,
"id": 2,
"title": "reprehenderit est deserunt velit ipsam",
"url": "https://via.placeholder.com/600/771796",
"thumbnailUrl": "https://via.placeholder.com/150/771796"
},]
And here is my fetch function which fetches this data from server.
fetch() async{
var client = new http.Client();
try {
var uriResponse = await
client.get('https://jsonplaceholder.typicode.com/photos');
if(uriResponse.statusCode == 200){
var data = json.decode(uriResponse.body);//data is array of objects
List<Photo> pics= data.map((Map<String,dynamic> model)=> Photo.fromJson(model)).toList();
setState(() {
photos = data;
_isLoading = false;
});
}
} finally {
client.close();
}
}
But the line ;
List<Photo> pics= data.map((Map<String,dynamic> model)=> Photo.fromJson(model)).toList();
gives me error that:
ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: type '(Map<String, dynamic>, dynamic) => Photo' is not a subtype of type '(dynamic) => dynamic' of 'f'
Here is my Photo PODO class.
class Photo {
final int id;
final String title;
final String url;
final String thumbnailUrl;
Photo({this.id, this.title,this.url, this.thumbnailUrl});
factory Photo.fromJson(Map<String, dynamic> json) {
return Photo(
id: json['id'] as int,
title: json['title'] as String,
thumbnailUrl: json['thumbnailUrl'] as String,
url: json['url'] as String,
);
}
}
What i am doing wrong in the above code? Thanx in advance !
You can use quicktype it lets you copy in your JSON string and generates the Dart Objects
In my project I have done like this and its working
pics = (data as List).map((model) => Photo.fromJson(model)).toList();
Try using
pics = data.map((i)=>Photo.fromJson(i)).toList();
You are receiving an json array and not json object from server
try this if it didnt work make sure to print the the response body
Iterable<dynamic> l = json.decode(uriResponse.body);
List<Post> posts = l.map((model) => Post.fromJson(model)).toList();
Related
I have a Dart class that I am using as a node class for a tree data structure.
My goal here is to encode objects of this class and its child nodes recursively.
I have a toJson() method that takes the child Nodes List and calls jsonencode on them.
class Node{
String name;
Map<String, String> attributes;
List<Node> children = List<Node>();
Node(this.name, attributes) {
this.attributes = attributes;
this.children = List<Node>();
}
Node.fromJson(Map<dynamic,dynamic> _map) {
this.name = _map['name'];
this.children = new List<Node>();
this.attributes = _map['attributes'][0];
for(var i = 0; i < _map['children'].length;i++){
Node temp = new Node.fromJson(_map['children'][i]);
this.addChild(temp);
}
}
Map<String, dynamic> toJson() => {
'name': name,
'attributes': [attributes],
'children': [
...this.children.map(jsonEncode)
]
};
}
I have a unit test i created to test this functionality:
Node nodeMap = {
"name": "Name",
"attributes": [
{"#htag1": "tagval1"}
],
"children": [
{
"name": "NameChild1",
"attributes": [
{"#htag2": "tagval2"}
],
"children": []
},
{
"name": "NameChild2",
"attributes": [
{"#htag3": "tagval3"}
],
"children": []
}
]
};
UNode unodeInst = new UNode.fromJson(nodeMap);
// Act
var nodeCreate = nodeInst.toJson();
// Assert
expect(nodeCreate, equals(nodeMap));
Here is the output of my unit test
Expected: {
'name': 'Name',
'attributes': [{'#htag1': 'tagval1'}],
'children': [
{
'name': 'NameChild1',
'attributes': [{'#htag2': 'tagval2'}],
'children': []
},
{
'name': 'NameChild2',
'attributes': [{'#htag3': 'tagval3'}],
'children': []
}
]
}
Actual: {
'name': 'Name',
'attributes': [{'#htag1': 'tagval1'}],
'children': [
'{"name":"NameChild1","attributes":[{"#htag2":"tagval2"}],"children":[]}',
'{"name":"NameChild2","attributes":[{"#htag3":"tagval3"}],"children":[]}'
]
}
Which: at location ['children'][0] is '{"name":"NameChild1","attributes":[{"#htag2":"tagval2"}],"children":[]}' which expected a map
As you see its not encoding my object correctly.
I believe this is happening because when i reclusively call jsonencode this method returns a string that is placed into the children array.
I believe part of my problem is that i dont fully understand the d diffrence between jsonencode() and toJson().
It is my understanding that jsonencode() calls toJson().. but jsonencode() returns a string and toJson() returns a Map<String, dynamic>.. so i think what i want here is to call toJson() recursively and not jsonencode.
Does this sound correct?
But i cannot figure out how to do this on a list in this situation.
I have tried the following
...this.children.map(this.toJson())
but i get "The argument type 'Map<String, dynamic>' can't be assigned to the parameter type 'dynamic Function(Node)'"
...this.children.forEach((element) {element.toJson()})
but i get "Spread elements in list or set literals must implement 'Iterable'"
Does this mean i have to implement the Iterable interface in my class?
You're just using the map method incorrectly. Use the following instead.
[
...this.children.map((e) => e.toJson())
]
It's also unnecessary to use spread with a literal list or use this. You can simplify the code to just
children.map((e) => e.toJson()).toList()
In Dartlang/Flutter, I'm trying to create a List of Maps using .map() and .toList() but getting the above error message. I tried adding type annotations in various places, but they just caused similar but different type errors.
Here is the response body.
Response body: {"data":{"logsread":[{"id":"7a2dd3b","email":"email#gmail.com"}]}}
And here is the code.
http.post(url, body: read2).then((response) {
print("Response status: ${response.statusCode}");
print("Response body: ${response.body}");
var tempTodos;
tempTodos = jsonDecode(response.body)['data']['logsread']
.map((node) => {
'id': 0,
'title': node['email'],
'score': 0,
})
.toList();
return Upd(model.copyWith(todoList: tempTodos));
Model class is defined as follows:
class Model {
final String todo;
final List<String> todos;
final Map todoWithScore;
final List<Map> todoList;
Model(this.todo, this.todos, this.todoWithScore, this.todoList);
Model copyWith({
String todo,
List<String> todos,
Map todoWithScore,
List<Map> todoList,
}) =>
Model(
todo ?? this.todo,
todos ?? this.todos,
todoWithScore ?? this.todoWithScore,
todoList ?? this.todoList,
);
}
Try after adding " as List" as shown below.
tempTodos = (jsonDecode(response.body)['data']['logsread'] as List )
.map((node) => {
'id': 0,
'title': node['email'],
'score': 0,
})
.toList();
I have this simple Cloud Function:
export const getTasks = functions.https.onRequest((request, response) => {
admin.firestore().collection('tasks').get()
.then(snapshot => {
const results = []
snapshot.forEach(task => {
const data = task.data()
results.push(data)
})
response.send(results)
})
.catch(error => {
console.log(error)
response.status(500).send(error)
})
});
The https call, from the browser, gives me a correct json:
[
{
title: "A title",
dueDate: "2018-07-03T18:33:27.537Z",
isComplete: true,
type: "task",
date: "2018-07-02T18:33:27.537Z"
},
{
type: "task",
date: "2018-07-02T18:36:25.506Z",
title: "Wowo",
dueDate: "2018-07-02T21:59:59.000Z",
isComplete: true
},
{
title: "Abc",
dueDate: "2018-07-04T18:31:58.050Z",
isComplete: false,
type: "task",
date: "2018-07-02T18:31:58.050Z"
}
]
But when I try to receive data from the iOS client through the function, I get a FIRHTTPSCallableResult object and a nil object:
functions.httpsCallable("getTasks").call() { (result, error) in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
//...
}
// ...
}
print( "result -> \(type(of: result))")
print( "result?.data -> \(type(of: result?.data))")
Log:
result -> Optional<FIRHTTPSCallableResult>
result?.data -> Optional<Any>
I tried to use JSON parsing but it does not work. How can I get the json?
Thanks
The API documentation for the data field states:
The data is in the form of native objects. For example, if your
trigger returned an array, this object would be an NSArray. If your
trigger returned a JavaScript object with keys and values, this object
would be an NSDictionary.
Since you're sending an array of objects from your function, you would treat the contents of data as an NSArray of NSDictionary objects.
I've searched around and looked at all the SDK docs and on Contentful's API docs I am having difficulty understanding how to add a media field with a link to an asset when creating a new entry. I can successfully create the other fields, but a media field should be an object but I am not sure exactly how to format that so Contentful will accept it.
const videoAsset = yield client.getAsset(assetID)
fields = {
title: {
"en-US": 'Title' //works
},
description: {
"en-US": 'Description' //works
},
video: {
"en-US": //contenful api wants an object, what does this object look like?
//i have a published asset in videoAsset returned by client.getAsset()
},
team: {
"en-US": 'Community' //works
},
}
const entryCreated = yield space.createEntry(action.payload.contentType, {
fields: fields
})
When I I say "works" I mean that I can successfully create an entry that appears in Contentful space.
I got it!
This person wasn't doing exactly the same thing but the answer in terms of formatting was here:
https://github.com/contentful/contentful-management.js/issues/57
Basically the field should look like this:
const videoAsset = yield client.getAsset(assetID)
fields = {
title: {
"en-US": 'Title' //works
},
description: {
"en-US": 'Description' //works
},
video: {
"en-US": {
sys: {
type: "Link", linkType: "Asset", id: assetID
}
}
}, //this formatting works!
team: {
"en-US": 'Community' //works
},
}
const entryCreated = yield space.createEntry(action.payload.contentType, {
fields: fields
})
I have a problem to serialize a json from a list of object
My goal is to have this format =>
var tag =
{
RCP: {name: "Dossier à présenter en RCP", type: "checkbox", events: {change: function(e) { console.log(e.data); console.log(e); } }, callback: function(key, opt){ console.log("key : " + key); console.log(opt); alert(opt.$trigger.attr("id")); }},
COL: {name: "Dossier à présenter en colloque", type: "checkbox", callback: function(key, opt){ console.log("key : " + key); console.log(opt); alert(opt.$trigge.attr("id")); }},
COM: {name: "Commentaire", type: "textarea", callback: function(key, opt){ console.log("key : " + key); console.log(opt); alert(opt.$trigge.attr("id")); }}
};
I'm using EF to retrieve the data as this :
var list = (from e in l_entities.TAG
where e.tag_site_code.Trim() == siteCode.Trim()
select new CvrTag
{
Id = e.tag_id,
Name = e.tag_libelle,
Type = e.tag_site_code
}
).ToList();
But I retrieve a classic Array when I use JsonConvert.SerializeObject(list).
So my question is :
- How to have braces instead array's brackets
- How to have an id (ie: RCP or COL) before the json object without quotes
- Same to inside json object (ie: name or type)
Thanks for your help
Since you are invoking ToList(), your serialization will be a list/array. If you want an object instead, use ToDict():
var dict = (from e in l_entities.TAG
where e.tag_site_code.Trim() == siteCode.Trim()
select new CvrTag
{
Id = e.tag_id,
Name = e.tag_libelle,
Type = e.tag_site_code
}
).ToDict(t => t.Id);