[FIXED] Flutter: How to access different properties from different classes?

Issue

I’m building a weather app so I can learn working with API’s and Bloc together. So far so good.
However I have one problem, how can I access different properties from different classes?

This is my code with the Classes:

import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:hava/services/openWeatherMapApi.dart';
import 'package:http/http.dart' as http;
import 'package:geolocator/geolocator.dart';

// To parse this JSON data, do
//
//     final getWeatherDetails = getWeatherDetailsFromJson(jsonString);

GetWeatherDetails getWeatherDetailsFromJson(String str) =>
    GetWeatherDetails.fromJson(json.decode(str));

String getWeatherDetailsToJson(GetWeatherDetails data) =>
    json.encode(data.toJson());

class GetWeatherDetails {
  GetWeatherDetails({
    required this.cod,
    required this.message,
    required this.cnt,
    required this.list,
    required this.city,
  });

  String cod;
  int message;
  int cnt;
  List<ListElement> list;
  String city;

  factory GetWeatherDetails.fromJson(Map<String, dynamic> json) =>
      GetWeatherDetails(
        cod: json["cod"],
        message: json["message"],
        cnt: json["cnt"],
        list: List<ListElement>.from(
            json["list"].map((x) => ListElement.fromJson(x))),
        city: City.fromJson(json["city"]).toString(),
      );

  Map<String, dynamic> toJson() => {
        "cod": cod,
        "message": message,
        "cnt": cnt,
        "list": List<dynamic>.from(list.map((x) => x.toJson())),
        "city": city.toString(),
      };
}

class City {
  City({
    required this.id,
    required this.name,
    required this.coord,
    required this.country,
    required this.population,
    required this.timezone,
    required this.sunrise,
    required this.sunset,
  });

  int id;
  String name;
  Coord coord;
  String country;
  int population;
  int timezone;
  int sunrise;
  int sunset;

  factory City.fromJson(Map<String, dynamic> json) => City(
        id: json["id"],
        name: json["name"],
        coord: Coord.fromJson(json["coord"]),
        country: json["country"],
        population: json["population"],
        timezone: json["timezone"],
        sunrise: json["sunrise"],
        sunset: json["sunset"],
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "name": name,
        "coord": coord.toJson(),
        "country": country,
        "population": population,
        "timezone": timezone,
        "sunrise": sunrise,
        "sunset": sunset,
      };
}

class Coord {
  Coord({
    required this.lat,
    required this.lon,
  });

  double lat;
  double lon;

  factory Coord.fromJson(Map<String, dynamic> json) => Coord(
        lat: json["lat"].toDouble(),
        lon: json["lon"].toDouble(),
      );

  Map<String, dynamic> toJson() => {
        "lat": lat,
        "lon": lon,
      };
}

class ListElement {
  ListElement({
    required this.dt,
    required this.main,
    required this.weather,
    required this.sys,
    required this.dtTxt,
  });

  int dt;
  Main main;
  List<Weather> weather;
  Sys sys;
  DateTime dtTxt;

  factory ListElement.fromJson(Map<String, dynamic> json) => ListElement(
        dt: json["dt"],
        main: Main.fromJson(json["main"]),
        weather:
            List<Weather>.from(json["weather"].map((x) => Weather.fromJson(x))),
        sys: Sys.fromJson(json["sys"]),
        dtTxt: DateTime.parse(json["dt_txt"]),
      );

  Map<String, dynamic> toJson() => {
        "dt": dt,
        "main": main.toJson(),
        "weather": List<dynamic>.from(weather.map((x) => x.toJson())),
        "sys": sys.toJson(),
        "dt_txt": dtTxt.toIso8601String(),
      };
}

class Main {
  Main({
    required this.temp,
    required this.feelsLike,
    required this.tempMin,
    required this.tempMax,
  });

  double temp;
  double feelsLike;
  double tempMin;
  double tempMax;

  factory Main.fromJson(Map<String, dynamic> json) => Main(
        temp: json["temp"].toDouble(),
        feelsLike: json["feels_like"].toDouble(),
        tempMin: json["temp_min"].toDouble(),
        tempMax: json["temp_max"].toDouble(),
      );

  Map<String, dynamic> toJson() => {
        "temp": temp,
        "feels_like": feelsLike,
        "temp_min": tempMin,
        "temp_max": tempMax,
      };
}

class Sys {
  Sys({
    required this.pod,
  });

  String pod;

  factory Sys.fromJson(Map<String, dynamic> json) => Sys(
        pod: json["pod"],
      );

  Map<String, dynamic> toJson() => {
        "pod": pod,
      };
}

class Weather {
  Weather({
    required this.id,
    required this.main,
    required this.description,
    required this.icon,
  });

  int id;
  String main;
  String description;
  String icon;

  factory Weather.fromJson(Map<String, dynamic> json) => Weather(
        id: json["id"],
        main: json["main"],
        description: json["description"],
        icon: json["icon"],
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "main": main,
        "description": description,
        "icon": icon,
      };
}

class GetWeatherService {
  late LocationPermission checkPermission;
  late LocationPermission requestPermission;

  List coordinatesList = [];
  late dynamic latitude;
  late dynamic longitude;

  //CHECK AND GET LOCATION PERMISSION
  Future checkAndGetLocationPermissions() async {
    // Check if gps is enabled
    bool servicestatus = await Geolocator.isLocationServiceEnabled();
    await Geolocator.requestPermission();
    await Geolocator.checkPermission();

   

    if (servicestatus) {
      if (kDebugMode) {
        print("GPS service is enabled");
      }
      Position position = await Geolocator.getCurrentPosition(
          desiredAccuracy: LocationAccuracy.high);
      latitude = position.latitude;
      print(latitude);
      longitude = position.longitude;
      print(longitude);
      coordinatesList.add(latitude);
      coordinatesList.add(longitude);

      if (kDebugMode) {
        print(coordinatesList);
      }
      return coordinatesList;
    } else {
      if (kDebugMode) {
        print("GPS service is disabled.");
      }

    }

    // final response = await http.get(Uri.parse(
    //     "api.openweathermap.org/data/2.5/forecast?lat=${$position.lattude}&lon=$longitude&appid=$openWeatherMapApiKey"));
    // final weatherDetails = getWeatherDetailsFromJson(response.body);
    // return weatherDetails;
  }

  Future<GetWeatherDetails> getWeather() async {
    dynamic latLong = await checkAndGetLocationPermissions() as List;

    // print(latLong.runtimeType);
    print("latLong, $latLong");
    double latitude = latLong[0];
    double longitude = latLong[1];

    final response = await http.get(Uri.parse(
        "http://api.openweathermap.org/data/2.5/forecast?lat=$latitude&lon=$longitude&appid=$openWeatherMapApiKey"));
    final weatherDetails = getWeatherDetailsFromJson(response.body.toString());

    return weatherDetails;
  }
}

With the code above I am only able to acces properties from GetWeatherDetails such as ‘city’.

I would like to be able to acces other propertes from other classes such as the ones in Classes, Main, City and List Element. How can I achieve this?

I am calling this method getWeather like this (home_bloc.dart):

import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:hava/services/weatherService.dart';

part 'home_event.dart';
part 'home_state.dart';

class HomeBloc extends Bloc<HomeEvent, HomeState> {
  final GetWeatherService _getWeatherService;

  HomeBloc(this._getWeatherService) : super(HomeLoadingState()) {
    on<LoadApiEvent>((event, emit) async {
      // TODO: implement event handler
      emit(HomeLoadingState());
      final activity = await _getWeatherService.getWeather();
      print(activity.city);
      emit(HomeLoadedState(activity.city));
    });
  }
}

This is the Json Response:

{
  "cod": "200",
  "message": 0,
  "cnt": 40,
  "list": [
    {
    "dt": 1663880400,
    "main": {
      "temp": 295.86,
      "feels_like": 296.33,
      "temp_min": 295.86,
      "temp_max": 295.86
    },
    "weather": [
      {
      "id": 803,
      "main": "Clouds",
      "description": "broken clouds",
      "icon": "04n"
      }
    ],
    "dt_txt": "2022-09-22 21:00:00"
    },
    {
      "dt": 1663880400,
      "main": {
        "temp": 295.86,
        "feels_like": 296.33,
        "temp_min": 295.86,
        "temp_max": 295.86
      },
      "weather": [
        {
        "id": 803,
        "main": "Clouds",
        "description": "broken clouds",
        "icon": "04n"
        }
      ],
      "dt_txt": "2022-09-22 21:00:00"
      }
  ],
  "city": {
    "id": 2351027,
    "name": "Akko",
    "coord": {
      "lat": 10.34,
      "lon": 10.99
    },
    "country": "NG",
    "population": 6129,
    "timezone": 3600,
    "sunrise": 1663391140,
    "sunset": 1663434946
  }
}

I have shortened the above json response to show weather details of 2 days only, but in the actual response it show weather details of 5 days.

The classes were generated in "quicktype" by pasting the json response.

Thank you for any help!

Edit 1: Code above reformatted.

Edit 2:Added Json response code above. I have shortened the above json response to show weather details of 2 days only, but in the actual response it show weather details of 5 days.

The classes were generated in "quicktype" by pasting the json response.

Solution

The problem is you are assigning string type to "city" but "city" is City type(which is an object) consist of other attributes.

change this:

class GetWeatherDetails {
   GetWeatherDetails({
required this.cod,
required this.message,
required this.cnt,
required this.list,
required this.city,
  });

   String cod;
   int message;
   int cnt;
   List<ListElement> list;
   City city; //here you assigned string but should be City type

  factory GetWeatherDetails.fromJson(Map<String, dynamic> json) =>
    GetWeatherDetails(
       cod: json["cod"],
       message: json["message"],
       cnt: json["cnt"],
       list: List<ListElement>.from(
        json["list"].map((x) => ListElement.fromJson(x))),
       city: City.fromJson(json["city"]), //here also you are changing it to 
    string
     );

    Map<String, dynamic> toJson() => {
    "cod": cod,
    "message": message,
    "cnt": cnt,
    "list": List<dynamic>.from(list.map((x) => x.toJson())),
    "city": city,  //here also you are changing it to string
  };
 }

  class City {
   City({
    required this.id,
    required this.name,
    required this.coord,
    required this.country,
    required this.population,
    required this.timezone,
    required this.sunrise,
    required this.sunset,
    });

Now you can access the other property of City class

   HomeBloc(this._getWeatherService) : super(HomeLoadingState()) {
      on<LoadApiEvent>((event, emit) async {
       // TODO: implement event handler
        emit(HomeLoadingState());
        final activity = await _getWeatherService.getWeather();
        print(activity.city.coord.lat);
        print(activity.city.name);
        // here you can access all

        print(activity.city.list[0].main.temp);// you can loop through 
         the list and get the specific value. I just assigned the 
         first index

     });
   }

Answered By – brook yonas

Answer Checked By – Gilberto Lyons (Easybugfix Admin)

Leave a Reply

(*) Required, Your email will not be published