I have a FutureBuilder that has no Data.
I have this Function to get the Data from the Backend:
Future<List<OrderReceipt>> getOrderReceipt(orderno) async {
final response = await HttpService.order_receipt(orderno);
var decoded = json.decode(response.body)["qry"].cast<Map<String,dynamic>>();
print(decoded);
var OrderR = await decoded.map<OrderReceipt>((json) => OrderReceipt.fromJson(json)).toList();
return OrderR;
}
This is the class with the mapping function:
class OrderReceipt {
final String LUKEBLART;
final String LUKEBLOART;
final String LUKEBLONR;
final String LUKEBLVC;
final String LUKEBLBNR;
final String LUKEBLDRAKT;
final String LUKEBLADS;
final String LUKEBLDATUM;
final String LUKEBLPGM;
final String LUKETIME;
final String LUKESART;
final String LUKEPAGE;
final String LUKELINE;
final String LUKELNR;
final String LUKETXT;
OrderReceipt({
required this.LUKEBLART,
required this.LUKEBLOART,
required this.LUKEBLONR,
required this.LUKEBLVC,
required this.LUKEBLBNR,
required this.LUKEBLDRAKT,
required this.LUKEBLADS,
required this.LUKEBLDATUM,
required this.LUKEBLPGM,
required this.LUKETIME,
required this.LUKESART,
required this.LUKEPAGE,
required this.LUKELINE,
required this.LUKELNR,
required this.LUKETXT,
});
factory OrderReceipt.fromJson(Map<String, dynamic> json) {
return OrderReceipt(
LUKEBLART: json['LUKEBLART'] as String ?? '',
LUKEBLOART: json['LUKEBLOART'] as String ?? '',
LUKEBLONR: json['LUKEBLONR'] as String ?? '',
LUKEBLVC: json['LUKEBLVC'] as String ?? '',
LUKEBLBNR: json['LUKEBLBNR'] as String ?? '',
LUKEBLDRAKT: json['LUKEBLDRAKT'] as String ?? '',
LUKEBLADS: json['LUKEBLADS'] as String ?? '',
LUKEBLDATUM: json['LUKEBLDATUM'] as String ?? '',
LUKEBLPGM: json['LUKEBLPGM'] as String ?? '',
LUKETIME: json['LUKETIME'] as String ?? '',
LUKESART: json['LUKESART'] as String ?? '',
LUKEPAGE: json['LUKEPAGE'] as String ?? '',
LUKELINE: json['LUKELINE'] as String ?? '',
LUKELNR: json['LUKELNR'] as String ?? '',
LUKETXT: json['LUKETX'] as String ?? '',
);}
}
And here is a example of the json (only one dataset):
[{LUKEBLADS: 222222, LUKEBLART: W , LUKEBLBNR: 333333, LUKEBLDATUM: 20230113, LUKEBLDRAKT: FX , LUKEBLOART: FX , LUKEBLONR: 4444, LUKEBLPGM: XXXKG , LUKEBLVC: X1 , LUKELINE: 41, LUKELNR: 36, LUKEPAGE: 1, LUKESART: 1, LUKETIME: Fri, 13 Jan 2023 09:54:02 GMT, LUKETXT: ExampleText USD 66,20 },]
There are a lot of spaces in LUKETXT, because I am generating a .pdf with monospace font (Just for good sizing from the AS400 Database I am working with)
The problem ist in the getOrderReceipt(orderno) Future, the future prints the decoded but did not return anything from await decoded.map<OrderReceipt>((json) => OrderReceipt.fromJson(json)).toList();.
I dont get any error - the FutureBuilder that builds the Future<List<OrderReceipt>> is processing for like two seconds and then there is no data.
I have two other FutureBuilders in my Project and dont have any problems with them. Does anybody know the error?
Thanks..
EDIT 1:
#Jozott, #Eric Martin and #pmatatias: I have updated the FutureFunction and removed the .cast<Map<String,dynamic>>() and also the await but nothing changes in the execution - the error is still there and the function ends by not returning anything from decoded.map<OrderReceipt>((json) => OrderReceipt.fromJson(json)).toList(); - my updated function:
Future<List<OrderReceipt>> getOrderReceipt(orderno) async {
final response = await HttpService.order_receipt(orderno);
print(response);
var decoded = json.decode(response.body)["qry"];
var OrderR = decoded.map<OrderReceipt>((json) => OrderReceipt.fromJson(json)).toList();
print(OrderReceipt);
return OrderR;
}
I also tried to change the factory function to:
...
...
factory OrderReceipt.fromJson(json) {
return OrderReceipt(
...
...
); }
...
...
EDIT 2:
This is as talked in the comments the FutureFunction with the try-catch-Block:
Future<List<OrderReceipt>> getOrderReceipt(orderno) async {
try {
final response = await HttpService.order_receipt(orderno);
print(response);
var decoded = json.decode(response.body)["qry"];
var OrderR = decoded.map<OrderReceipt>((json) =>
OrderReceipt.fromJson(json)).toList();
return OrderR;
} catch(err) {
print('Caught error: $err');
throw 'Caught error: $err';
}
}
The following Error is displayed:
type 'null' is not a subtype of type 'string' in type cast
And I also tried to comment out the "LUKETXT" in the Modell - and then it works.
Maybe this error can be thrown because there can be dots, colons and other special caracters in the value? -> But as I see in the devtools these special caracters are correctly decoded in the json.decode function to each of them headers and remain a String.
You made a typo in a name field. LUKETX instead of LUKETXT
In your factory :
LUKETXT: json['LUKETX'] as String ?? '',
Your code try to cast null value to a string. That's why you get this error.
As #jozott mentionned, you can use a code generator code like json_serializable to avoid typos :
https://pub.dev/packages/json_serializable
By the way, i don't think you have to declare the cast "as string" because dart infers the type. Imagine a String field name, you can write this :
User.fromJson(Map<String, dynamic> json)
: name = json['name'] ?? ''
Related
I want to fetch and format json data from this as a trial in flutter. However, during the formatting process, an exception occurs: type 'Null' is not a subtype of type 'String'.
And these are my code:
user_model.dart
class User {
int id;
String email;
String firstName;
String lastName;
String avator;
User({
required this.id,
required this.email,
required this.firstName,
required this.lastName,
required this.avator
});
factory User.fromJson(Map<String, dynamic> json) => User(
id : json['id'],
email : json['email'],
firstName : json['first_name'],
lastName : json['last_name'],
avator : json['avator']
);
}
user_api.dart
...
class UserApi {
Future<List<User>?> getUsers() async {
final url = Uri.parse('https://reqres.in/api/users?page=2');
try {
final res = await http.get(url);
if (res.statusCode == 200) {
final Map<String, dynamic> body = jsonDecode(res.body);
final List<User> users = body['data'].map((dynamic userData) => {
print('userData : $userData');
User.fromJson(userData) // There seems to be an error here.
}).toList();
return users;
} else {
return null;
}
} catch (e) {
print(e.toString());
}
return null;
}
}
And userData seems like this in my console:
flutter: userData : {id: 7, email: michael.lawson#reqres.in, first_name: Michael, last_name: Lawson, avatar: https://reqres.in/img/faces/7-image.jpg}
I don't think userData is kind of Null, but why do I get the exception?
You need to use json['avatar'] instead of json['avator']
factory User.fromJson(Map<String, dynamic> json) => User(
id : json['id'],
email : json['email'],
firstName : json['first_name'],
lastName : json['last_name'],
avator : json['avatar'] //here `a` instead of `o`
);
I just checked the link you have mentioned for the json you are using. There is a typo at your end. In the json, avatar is the correct field spelling. You have mentioned avator in your class's factory constructor.
So, avator is Null and thus, String avator is assigned to a Null value.
FYI: The error type 'Null' is not a subtype of type 'String' means that you are trying to assign a Null value to a String type variable.
its a typo in the fromJson method : as mentioned by yeasin-sheikh (You need to use json['avatar'] instead of json['avator']),
Yeasin-sheikh's answer
there are some json parsing websites, using that we can easily generate model class and other methods related to it.
eg : app.quicktype.io
just input the json response and generate the model class in required language.
error
I tried to fetch user's data from firebase using logged user uid . And also I used model
model code
Details detailsFromJson(String str) => Details.fromJson(json.decode(str));
class Details {
Details({
required this.id,
required this.age,
required this.drinkstalkSE,
required this.drinksUnderstandSE,
required this.familyChildren,
});
String id;
String age;
String drinkstalkSE;
String drinksUnderstandSE;
String familyChildren;
factory Details.fromJson(Map<String, dynamic> json) => Details(
id: json["id"] ?? "",
age: json["age"] ?? "",
drinkstalkSE: json["drinkstalkSE"] ?? "",
drinksUnderstandSE: json["drinksUnderstandSE"] ?? "",
familyChildren: json["familyChildren"] ?? "",
);
Map<String, dynamic> toJson() => {
"id": id,
"age": age,
"drinkstalkSE": drinkstalkSE,
"drinksUnderstandSE": drinksUnderstandSE,
"familyChildren": familyChildren,
};
}
backend code
bool loading = false;
#override
initState() {
super.initState();
loading = true;
getDetails();
}
Details? oneUserDetails;
Future<void> getDetails() async {
final sp = context.read<SignInProvider>();
final id = sp.uid;
final reference = FirebaseFirestore.instance.doc('users/$id');
final snapshot = reference.get();
final result = await snapshot.then(
(snap) => snap.data() == null ? null : Details.fromJson(snap.data()!));
print('result is ====> $result');
setState(() {
oneUserDetails = result;
loading = false;
});
}
screen code
Database image
In my code no any errors show I think problem have in my model but I couldn't understand what is the error and how to solve it. How to solve this error?
The values you use are listed, you need to create a separate section in the class for them. If you don't know exactly how, paste your json data on this site and it will handle it for you. You will see your mistake.
https://javiercbk.github.io/json_to_dart/
According to my knowledge, there is a problem with the model. In the model, the list is drinksUnderstandSE and drinkstalkSE both are strings but in the database, it is the list so it should be a list.
I am new to dart and I am trying to create a basic inventory app with different types of chemicals.
I am trying to fetch data from firebase, which is getting back to me perfectly, but when I am trying to store it locally with a custom Model Class, its throwing me the following error
type 'int' is not a subtype of type 'String'
Here is the code for fetching and storing data locally
Future<void> getLoadedData() async {
final url = Uri.parse(
'https://inventory-db0eb-default-rtdb.asia-southeast1.firebasedatabase.app/chemicalList.json?auth=$authToken');
try {
final response = await http.get(url);
final List<ChemModel> _tempChemical = [];
final _tempChemList = json.decode(response.body) as Map<String, dynamic>;
_tempChemList.forEach((elementId, value) {
_tempChemical.add(
ChemModel(
id: ' ',
name: ' ',
// name: value['name'] ?? "Empty",
formula: ' ',
// formula: value['formula'] ?? "Empty",
description: ' ',
molWeight: double.parse(value['molWeight']),
// description: value['description'] ?? "Empty",)
),
);
});
_chemicalList = _tempChemical;
notifyListeners();
} catch (error) {
print(error);
rethrow;
}}
This is my model class
class ChemModel with ChangeNotifier {
String id;
String name;
String formula;
double molWeight;
String description;
ChemModel(
{required this.id,
required this.name,
required this.formula,
this.description = "",
this.molWeight = 0});
}
I'm not sure where I am going wrong.
You can convert a value to double as follows
molWeight: value['molWeight'].toDouble(),
or
molWeight: (value['molWeight'] as int).toDouble(),
model class may be a nuisance if you share a screenshot of the data source I can help more clearly
for exp : I mean, the value from the data source is string, and if you're trying to keep it as a int in the model class, you might get this kind of error.
I am trying to perform user login with my flutter app but then I keep getting data != null error and that a Text Widget must have a non-null string.
Upon further debugging, I realized the response['message'] is printing a null value so I implement a condition to check if it's not null before proceeding but yet still it keeps giving me the same error.
When I use response['message'].toString(), it still gives the same error.
this is the full error being thrown 'data != null': A non-null String must be provided to a Text widget.
the issue seems to be from the response['message'] but I just can't seem to find ways to solve it
This is Auth controller class
class AuthController extends GetxController {
AuthService authService = AuthService();
ProjectApis projectApis = ProjectApis();
String name = '';
String email = '';
String password = '';
String confirmPassword = '';
var isPasswordHidden = true.obs;
Future loginUser(BuildContext context) async {
buildLoader(context, message: 'Loading...');
http.Response response = await authService.signInUser(
email,
password,
);
if (response.statusCode == 200) {
Map<String, dynamic> responseData = json.decode(response.body);
debugPrint(responseData.toString());
debugPrint(responseData['message']);
if (responseData["status"] == true) {
User user = User.fromJson(responseData);
UserPreferences().setUser(user);
Navigator.pop(context);
Get.offAll(() => BottomNavigation());
return;
} else {
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(responseData['message']),
));
return;
}
} else {
Navigator.pop(context);
showErrorDialog(context, message: "Server Error");
return;
}
}
}
This is the sign in function
Future<http.Response> signInUser(
String email,
String password,
) async {
Map data = {
'email': email,
'password': password,
};
var body = json.encode(data);
var url = Uri.parse(projectApis.loginUrl);
var response = await client.post(
url,
body: body,
headers: projectApis.headers,
);
return response;
}
This is the User model class
User userFromJson(String str) => User.fromJson(json.decode(str));
String userToJson(User data) => json.encode(data.toJson());
class User {
User({
this.id,
this.name,
this.email,
this.password,
this.passwordConfirm,
this.token,
});
int? id;
String? name;
String? email;
String? password;
String? passwordConfirm;
String? token;
String applicationDirPath = "";
factory User.fromJson(Map<String, dynamic> json) => User(
id: json["id"],
name: json["name"],
email: json["email"],
password: json["password"],
passwordConfirm: json["passwordConfirm"],
token: json["token"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"email": email,
"password": password,
"passwordConfirm": passwordConfirm,
"token": token,
};
}
Use null-operator like here
response['message'] ?? ''
If left side was null the right side will assing
But you can use this just if you are sure this happen because of this line
read in medium
Text widget doesn't accept nullable String, and reading map can provide null value. You can provide default value on null case like
Text(myMap["key"]??"defaultValue")
And for perser you can do
if (responseData["status"] != null && responseData["status"]==true ) {
I think problem is with the Text(responseData['message']), line.
Dart can't be sure that me message key exist on responseData Map. So Text(responseData['message']), can be null which is bad for null safety.
Just do:
String message = responseData['message'] ?? '';
The ?? operator will return an empty string in case ResponseData['message'] is null.
Then replace in your Text widget:
Text(message),
import 'package:firebase_database/firebase_database.dart';
class Post {
static const KEY = "key";
static const DATE = "date";
static const TITLE = "title";
static const BODY = "body";
final String date;
String key;
final String title;
final String body;
Post(this.date, this.key, this.title, this.body);
// String get ket => _key;
//
// String get date => _date;
//
// String get title => _title;
//
// String get body => _body;
Post.fromSnapshot(DataSnapshot snap)
: key = snap.key.toString(),
body = snap.value[BODY],
date = snap.value[DATE],
title = snap.value[TITLE];
toMap() {
return {BODY: body, TITLE: title, DATE: date};
}
}
error:
The method '[]' can't be unconditionally invoked because the receiver can be 'null'. (unchecked_use_of_nullable_value at [flutter_firebase] lib\models\post.dart:25)
The value in snap.value can be null on line 25. And then, trying to use the index operator [] on it (a possible null value) shows this error (It'd be the same as doing null[]).
Solution 1
Try checking where the data come from if it can be null. If that's the case, i.e. if null is really possible from DataSnapshot, you'd need to specify Post properties with a nullable type as well with the ? after the type like so:
class Post {
static const KEY = "key";
static const DATE = "date";
static const TITLE = "title";
static const BODY = "body";
final String? date;
String key;
final String? title;
final String? body;
Post(this.date, this.key, this.title, this.body);
...
And then default the value to something else using the ? unary postfix operator in conjunction with ?? if-null operator if it comes as null like the code snippet below. You'd need also to cast the snap.value, that is a Object? in the new Firestore 9.x, to a nullable Map<String, dynamic>?.
Post.fromSnapshot(DataSnapshot snap)
: key = snap.key.toString(),
body = (snap.value as Map<String, dynamic>?)?[BODY] ?? '',
date = (snap.value as Map<String, dynamic>?)?[DATE] ?? '',
title = (snap.value as Map<String, dynamic>?)?[TITLE] ?? '';
Solution 2
Otherwise, if null is not a possibility at all then you can force the value to be non-null with the ! null assertion operator, casting away nullability, like so:
Post.fromSnapshot(DataSnapshot snap)
: key = snap.key.toString(),
body = (snap.value! as Map<String, dynamic>)[BODY],
date = (snap.value! as Map<String, dynamic>)[DATE],
title = (snap.value! as Map<String, dynamic>)[TITLE];