Home > Enterprise >  How to cast parsed response from Model to a local variable in Flutter
How to cast parsed response from Model to a local variable in Flutter

Time:01-16

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:

  1. You are casting the LoginModel object returned from LoginModel.fromJson(...) as a Map<String, dynamic> instead of casting value['data'] as Map<String, dynamic>.

  2. You are also assigning the LoginModel.fromJson(...) to a variable of type Map<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:

  1. Make the _loginResponse variable a LoginModel instead of a Map<String, dynamic>
  2. Make the loginResponse getter return a LoginModel object instead of a Map<String, dynamic>
  3. Cast value['data'] to a Map<String, dynamic> and pass it into LoginModel.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();
  }
}
  • Related