I still like to call myself a novice when it comes to parsing a JSON response into a model class for usage. I have a certain JSON response which I have converted into a Model using one of those websites that does all the hard work. However, I repeatedly keep getting errors saying type 'LoginModel' is not a subtype of type 'Map<String, dynamic>'
when I make the API Call. Here is the response followed by the code:
The JSON response:
{
"data": {
"access_token": "*********",
"role": 0,
"id": 000,
"lat": "0.0",
"lng": "0.0",
"radius": 200,
"department": "IIIII",
"approval": 1
}
}
This here is the Model class:
class LoginModel {
Data? data;
LoginModel({this.data});
LoginModel.fromJson(Map<String, dynamic> json) {
data = json['data'] != null ? Data.fromJson(json['data']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.data != null) {
data['data'] = this.data!.toJson();
}
return data;
}
}
class Data {
String? accessToken;
int? role;
int? id;
String? lat;
String? lng;
int? radius;
String? department;
int? approval;
Data(
{this.accessToken,
this.role,
this.id,
this.lat,
this.lng,
this.radius,
this.department,
this.approval});
Data.fromJson(Map<String, dynamic> json) {
accessToken = json['access_token'];
role = json['role'];
id = json['id'];
lat = json['lat'];
lng = json['lng'];
radius = json['radius'];
department = json['department'];
approval = json['approval'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['access_token'] = this.accessToken;
data['role'] = this.role;
data['id'] = this.id;
data['lat'] = this.lat;
data['lng'] = this.lng;
data['radius'] = this.radius;
data['department'] = this.department;
data['approval'] = this.approval;
return data;
}
}
The class where I get the error:
class LoginController with ChangeNotifier {
NetworkServices networkServices = NetworkServices();
Map<String, dynamic> _loginResponse = {}; //I would like to store the parsed response into this variable for local use
Map<String, dynamic> get loginResponse {
return _loginResponse;
}
Future<void> login(dynamic data, BuildContext context) async {
networkServices
.postLoginRequest(ApiUrl.loginUrl, data, context)
.then((value) {
_loginResponse =
LoginModel.fromJson(value['data']) as Map<String, dynamic>; //I'm pretty sure this is what I've done wrong
print('SUCCESS: $_loginResponse');
}).onError((error, stackTrace) {
// Loader(false);
print('ERRROR: $error'); //This is where the error gets printed after it comes from the NetworkServices class where the API Call is made
});
notifyListeners();
}
}
Network Class where the API gets called:
class NetworkServices {
Future<dynamic> postLoginRequest(
String url, dynamic data, BuildContext context) async {
var jsonResponse;
try {
final response = await http.post(Uri.parse(url),
body: json.encode(data),
headers: {
'Content-Type': 'application/json'
}).timeout(const Duration(seconds: 30));
jsonResponse = returnResponse(response);
print('FROM NETWORK: $jsonResponse');
} on SocketException {
Flushbar(
leftBarIndicatorColor: Colors.red,
icon: const Icon(Icons.warning, color: Colors.white),
message: 'Ooops!!! Something went wrong',
).show(context);
}
return jsonResponse;
}
dynamic returnResponse(http.Response response) {
if (response.statusCode >= 200 && response.statusCode <= 300) {
dynamic jsonResponse = json.decode(response.body);
return jsonResponse;
} else if (response.statusCode >= 400 || response.statusCode == 404) {
return 'An Error Occured';
} else if (response.statusCode >= 404) {
return 'Invalid Request';
} else {
return 'Error Occured While Communicating with Servers!!! Please try again later';
}
}
}
CodePudding user response:
Problems:
You are casting the
LoginModel
object returned fromLoginModel.fromJson(...)
as aMap<String, dynamic>
instead of castingvalue['data']
asMap<String, dynamic>.
You are also assigning the
LoginModel.fromJson(...)
to a variable of typeMap<String, dynamic>
,_loginResponse
.
Solution:
Change this line of code:
_loginResponse = LoginModel.fromJson(value['data']) as Map<String, dynamic>;
to this:
_loginResponse = value['data'] as Map<String, dynamic>;
Update:
In other to store the login information in the LoginModel
, you need to make the following to the LoginController
class:
- Make the
_loginResponse
variable aLoginModel
instead of aMap<String, dynamic>
- Make the
loginResponse
getter return aLoginModel
object instead of aMap<String, dynamic>
- Cast
value['data']
to aMap<String, dynamic>
and pass it intoLoginModel.fromJson(...)
Your updated LoginController
class will be:
class LoginController with ChangeNotifier {
NetworkServices networkServices = NetworkServices();
LoginModel _loginResponse = LoginModel();
LoginModel get loginResponse {
return _loginResponse;
}
Future<void> login(dynamic data, BuildContext context) async {
networkServices
.postLoginRequest(ApiUrl.loginUrl, data, context)
.then((value) {
_loginResponse =
LoginModel.fromJson(value['data'] as Map<String, dynamic>);
print('SUCCESS: $_loginResponse');
}).onError((error, stackTrace) {
// Loader(false);
print('ERRROR: $error');
});
notifyListeners();
}
}