Example Code (Not working):
void main() {
List json = [
{
"sku": "SKU0001",
"uids": [
{
"uid": "U001"
}
]
}
];
var result = json.map( (item) {
item['no_desc'] = true; // able to add the key and bool value
item['uids'] = item['uids'].map( (uid) {
uid['is_scanned'] = true; // failed to add, but able to accept string value only.
return uid;
}).toList();
return item;
}).toList();
print(result);
}
return error 'bool' is not a subtype of type 'String'
Expected Result
[
{
sku: SKU0001,
no_desc: true,
uids: [
{
uid: U001,
is_scanned: true // must be boolean
}
]
}
]
It work when i try in String value.
uid['is_scanned'] = 'true';
How can I add bool value into the nested list?
If I am writing in javascript way,
it should be able to add the key into nested array ( list ).
But why in dart lang, it prompt me error?
Can someone expert in dart lang willing to explain to me?
Your issue can be fixed by creating a new Map instance in the inner .map method with the Map.from constructor.
item['uids'] = item['uids'].map( (uid) {
uid['is_scanned'] = true; // failed to add, but able to accept string value only.
return uid;
}).toList();
should be changed to:
item['uids'] = item['uids'].map( (uid) {
Map<String, dynamic> toReturn = Map.from(uid);
toReturn['is_scanned'] = true;
return toReturn;
}).toList();
I believe this issue is due to dart implicitly declaring the inner uids maps as Map<String, String> so creating a new instance changes this and allows you to assign any value to the keys of the Map.
Full working sample:
void main() {
List json = [
{
"sku": "SKU0001",
"uids": [
{
"uid": "U001"
}
]
}
];
var result = json.map( (item) {
item['no_desc'] = true;
item['uids'] = item['uids'].map( (uid) {
Map<String, dynamic> toReturn = Map.from(uid);
toReturn['is_scanned'] = true;
return toReturn;
}).toList();
return item;
}).toList();
print(result);
}
Related
I have this code that fetch data from internet:
Future fetchCfo(String barCode, String url) async {
final response = await http.get(Uri.parse(url + barCode));
if (response.statusCode == 200) {
Map<String, dynamic> responseBody = json.decode(utf8.decode(response.bodyBytes));
responseBody.forEach((key, value) {
if (value == null) {
responseBody.update(key, (value) => "");
}
});
return CfoModel.fromJson(responseBody);
} else {
return null;
}
}
And I need to replace the null values according to their type, for example if a field that was supposed to be an integer returns a null I need to replace it with 0, if a field that was supposed to be a list returns a null I need to replace it with a list empty []; and I don't know how to do this, my code replaces Strings but if a null appears in an int field, the code breaks.
For example, my model:
String? interfaceStatus;
bool? trasnP;
int? id;
String? name;
String? date;
bool? requiredStatus;
int? numberOf;
int? numberRegion;
List? parameters;
In case numberRegion returns a null, I need to replace with 0;
In case Transp returns a null, I need to replace with false;
in case name returns a null, I need to replace with empty String "";
Response I'm getting:
{
"interfaceStatus":"ok",
"trasnP":false,
"id":null,
"name":null,
"date":null,
"requiredStatus":true,
"numberOf":23,
"numberRegion":27,
"parameters":null
}
What I want to return:
{
"interfaceStatus":"ok",
"trasnP":false,
"id":0,
"name":"",
"date":"",
"requiredStatus":true,
"numberOf":23,
"numberRegion":27,
"Parameters":[
]
}
Anyone has a solution for this ?
I would recommend not updating any values in the responseBody just leave them as null but in the fromJson function you can give default values with the ?? operator such as:
fromJson(Map response) {
return CfoModel(
id: response[id] ?? 0,
array: response[array_element] ?? [],
);
}
How to fix code my code flutter and use plugin
filterContacts() {
setState(() {
List<Contact> _contacts = [];
_contacts.addAll(contacts);
if (searchController.text.isNotEmpty) {
_contacts.retainWhere(
(contact) {
String searchTerm = searchController.text.toLowerCase().trim();
String searchTermFlatten = flattenPhoneNumber(searchTerm);
String contactName = contact.displayName.toString().toLowerCase();
bool nameMatches = contactName.contains(searchTerm);
if (nameMatches == true) {
return true;
}
if (searchTermFlatten.isEmpty) {
return false;
}
var phone = contact.phones.firstWhere((phn) {
String phnFlattened = flattenPhoneNumber(phn);
return phnFlattened.contains(searchTermFlatten);
}, orElse: () => null);
return phone != null;
},
);
contactsFiltered = _contacts;
}
});
}
Flutter code How to fix code my code flutter and use plugin contacts_service,
this image is about a problem
contact.phones can be null, in this you need to check its value 1st then proceed,
you can use contact.phones?.firstWhere to handle this situation or
If you're sure it will have value, you can also do contact.phones!.firstWhere but I don't recommend this. You don't need to use orElse you want to pass null,
Item? phone = contact.phones?.firstWhere((phn) {
String phnFlattened = flattenPhoneNumber(phn);
return phnFlattened.contains(searchTermFlatten);
}, );
You can learn more about ?. !...
[how to fix now]
error code not complete
filterContacts() {
setState(() {
List<Contact> _contacts = [];
_contacts.addAll(contacts);
if (searchController.text.isNotEmpty) {
_contacts.retainWhere(
(contact) {
String searchTerm = searchController.text.toLowerCase().trim();
String searchTermFlatten = flattenPhoneNumber(searchTerm);
String contactName = contact.displayName.toString().toLowerCase();
bool nameMatches = contactName.contains(searchTerm);
if (nameMatches == true) {
return true;
}
if (searchTermFlatten.isEmpty) {
return false;
}
Item? phone = contact.phones?.firstWhere((phn) {
String phnFlattened = flattenPhoneNumber(phn);
return phnFlattened.contains(searchTermFlatten);
}, );
return phone != null;
},
);
contactsFiltered = _contacts;
}
});
}
I have and empty map, Map optionSelection = {};
And on every button click I want to add list of K,V pair map to optionSelection map.
Format in which I want to add Map.
{
"quiz_id": selectedOption,
"ques_id": questionId,
"user_ans_id": selectedOption,
}
In above Key and Value pair, in "ques_id": questionId -> questionId will be unique, So I want to check if the value already exist, if YES then I want to update the "user_ans_id": selectedOption value or else I want to add new list of K,V pair.
Below is the code I tried
final quesExist = optionSelection.containsValue(questionId);
if (quesExist) {
optionSelection.putIfAbsent(
"ques_id",
() => optionSelection.addAll(
{
"quiz_id": selectedOption,
"ques_id": questionId,
"user_ans_id": selectedOption,
},
),
);
} else {
optionSelection.addAll(
{
"quiz_id": selectedOption,
"ques_id": questionId,
"user_ans_id": selectedOption,
},
);
}
Hope I was able to explain my issue, Thank you in advance.
after a week of struggle and many tweaks in code, here is the final solution for above query.
// Declared empty List<Map>
List<Map> optionSelection = [];
// Variable to store bool value, if the question id exist
var questionExist;
// Feed the map in below form
Map<String, dynamic> userSelection = {
"quiz_id": widget.quizId,
"ques_id": questionId,
"user_ans_id": selectedOption,
};
// Check if the Ques Id Exist in List<Map> optionSelection
questionExist = optionSelection.any((map) => map.containsValue(questionId));
// Check using if else condition, if Ques Id exist, then run the forLoop,
// to iterate in List<Map>, else add a new Set of Map to the List<Map>
if (questionExist == true) {
print("If triggered");
for (var map in optionSelection) {
if (map.containsValue(questionId)) {
map.update("user_ans_id", (dynamic val) => selectedOption);
}
}
} else {
print("Else triggered");
optionSelection.add(userSelection);
}
Problem
I'm trying to receive data from a rest API in my flutter app, inside a future function but i keep getting the following error:
type 'CastList<dynamic, List>' is not a subtype of type 'List'.
The function I'm using to fetch the data is as follows:
static Future<List<Questionnaire>> fetchQuestionnaires() async {
try {
final response =
await http.get('http://10.0.2.2:4010/phone/questionnaires');
if (response.statusCode == 200) {
List<Questionnaire> resp =
json.decode(response.body).cast<List<Questionnaire>>();
List<Questionnaire> questionnaires = resp
.map<Questionnaire>((dynamic item) => Questionnaire.fromJson(item))
.toList();
log(
questionnaires.toString(),
);
return questionnaires;
} else {
throw Exception('Unable to fetch questionnaires');
}
} catch (error) {
log(error.toString());
}
}
I don't understand why this is. Why does using cast, cast to CastList<dynamic, Type> and not the original Type? What changes do I do to get my data?
The data model is given below.
Data Model
The Data i expect from my backend is like this. An array called questionnaires, containing multiples of a questionnaire, each containing an id and a displayQuestion. A displayQuestion in turn has the question text and the answers Array_.
For this, I have the following structure in my Json.
[
{
"questionId": 1,
"displayQuestions": [
{
"question": "how old are you",
"answers": [
"1",
"2",
"3",
"4"
]
}
]
}
]
This is my questionnaires.dart model
class Questionnaires {
List<Questionnaire> _questionnaires;
Questionnaires.fromJson(this._questionnaires);
}
This is questionnaire.dart model
class Questionnaire {
int questionnaireId;
List<DisplayQuestion> displayQuestions = [];
Questionnaire(this.questionnaireId, this.displayQuestions);
Questionnaire.fromJson(Map<String, dynamic> json)
: questionnaireId = json['questionnaireId'],
displayQuestions = json['displayQuestions'];
}
The code from display-question.dart model
class DisplayQuestion {
String _question;
List<String> _answers;
String get question => this._question;
List get answers => this._answers;
DisplayQuestion(this._question, [List<String> answers])
: this._answers = answers ?? [];
DisplayQuestion.fromJson(Map<String, dynamic> json)
: _question = json['question'],
_answers = json['answers'];
}
Why does using cast, cast to CastList<dynamic, Type> and not the original Type?
From the docs, myList.cast<MyType> returns a List<MyType>. In your case you're calling resp.cast<List<Questionnaire>>, so the return will be List<List<Questionnaire>>, which is not what you want.
If you're asking about CastList<dynamic, Type>, it's a subclass of List<Type>, see the source code. It's useful because CastList doesn't need to create a new list, it's just a wrapper around the original list where each element is cast with as Type before being returned.
What changes do I do to get my data?
The problem is you're calling resp.cast<Type> where resp is not a list that constains Type.
Here's a working sample based on the code you provided:
import 'dart:convert';
final sampleJson = """[
{
"questionId": 1,
"displayQuestions": [
{
"question": "how old are you",
"answers": [
"1",
"2",
"3",
"4"
]
}
]
}
]
""";
class DisplayQuestion {
String question;
List<String> answers;
DisplayQuestion.fromJson(Map<String, dynamic> json)
: question = json["question"],
answers = json["answers"].cast<String>();
String toString() => 'question: $question | answers: $answers';
}
class Questionnaire {
int questionnaireId;
List<DisplayQuestion> displayQuestions;
Questionnaire.fromJson(Map<String, dynamic> json)
: questionnaireId = json['questionnaireId'],
displayQuestions = (json['displayQuestions'] as List<dynamic>)
.map((questionJson) => DisplayQuestion.fromJson(questionJson))
.toList();
String toString() => '$displayQuestions';
}
List<Questionnaire> parseQuestionnaires() {
List<Questionnaire> questionnaires =
(json.decode(sampleJson) as List<dynamic>)
.map((questionnaireJson) => Questionnaire.fromJson(questionnaireJson))
.toList();
return questionnaires;
}
void main() {
print(parseQuestionnaires());
// => [[question: how old are you | answers: [1, 2, 3, 4]]]
}
I couldn't find a way to store the Type value in Map so that I could use it in is operator to check the validity of type using this map later on. Also, can is operator accept Type as a variable?
For eg, Below is hypothetical code solving the problem but it's invalid.
Map<String, Type> map = {
"sku": String,
"price": double,
"quantity": int,
};
dynamic value = 10;
if(value is map["quantity"]){
print("value is of type int and int is expected for quantity value");
}
You can do something like this:
class TypeCheck<T> {
const TypeCheck();
bool typeCheck(dynamic value) => value is T;
}
void main() {
Map<String, TypeCheck> map = {
"sku": TypeCheck<String>(),
"price": TypeCheck<double>(),
"quantity": TypeCheck<int>(),
};
dynamic value = 10;
if (map["quantity"]!.typeCheck(value)) {
print("value is of type int and int is expected for quantity value");
}
}
Im not sure I fully understand I understand what you are trying to do but why don't you try something like.
bool _validate(Map productDetails){
if (productDetails.containsKey("sold_individually") && productDetails["sold_individually"] is bool) {
//return true or false
}
else if (productDetails.containsKey("stock_quantity") && productDetails["stock_quantity"] is int){
//return true or false
}
else if (productDetails.containsKey("tax_class") && productDetails["tax_class"] is String && productDetails["tax_class"].isNotEmpty) {
//return true or false
} else {
//return true or false
}
}
As for the other part of your question you wont get an error but you will always return false. In contrast if you check if a variable is dynamic it will always return true.
I don't really understand your end goal. But from what you have, I don't think you are taking advantage of the strongly-typed nature of dart.
Assuming you are getting your map from an API, you could enforce
typing manually in your code as follows;
Map<String, Type> map = {
"sku": json['key'] as String,
"price": json['key'] as double,
"quantity": json['key'] as int,
};
And avoid using dynamic when declaring variables.
OR
In the case you have a user-defined type you what to compare, you can use the equatable package on a class for instance as follows;
class CustomMap extends Equatable {
String sky;
double price;
int quantity;
// here you put the fields of a class you want for two instances of a class to be equal.
#overide
List<Object> get props => [sky, price, quantity];
}
Update from your comment
You should have a custom class for the API objects for instance;
class Item extends Equatable {
String sku;
double price;
int quantity;
Item({this.sky, this.price, this.quantity});
// factory constructor
factory Item.fromMap(Map<String, dynmic> json) {
final sku = json['sku'] as String,
final price = (json['price'] as num) as double,
final quantity = json['quantity'] as num,
return Item(sku: sku, price: price, quantity: quantity);
}
// define equatable objects
#override
List<Object> get props => [sku, price, quantity];
}
Now you can use it as follows;
Future<Item> objectsFromService(Map<String, dynamic> json ) async {
http.Response response = http.get(url);
if(response.status == 200) {
final decodedJson = json.decode(response.body);
return Item.fromJson(decodedJson);
}else{
print('Error fetch data');
return null;
}
}
Hope it helps