Flutter get list elements from API result with BloC Pattern

Issue

I’m new at BloC Pattern. I’m sending a request to an weather API and it returns a JSON result like in below.
As you can see the result is array of json object

I formatted it to weather model in my response class.

Weather Model Class

class Weather {
  String date;
  String day;
  String icon;
  String description;
  String status;
  String degree;
  String min;
  String max;
  String night;
  String humidity;

  Weather({this.date, this.day, this.icon, this.description, this.status,
      this.degree, this.min, this.max, this.night, this.humidity});

  Weather.init(this.date, this.day, this.icon);

  factory Weather.fromJson(Map<String, dynamic> json){
    return Weather(
      date: json['date'] as String,
      day:  json['day'] as String,
      icon: json['icon'] as String,
      description: json['description'] as String,
      status: json['status'] as String,
      degree: json['degree'] as String,
      min: json['min'] as String,
      max: json['max'] as String,
      night: json['night'] as String,
      humidity: json['humidity'] as String,
    );
  }

Response Class

class WeatherResponse {
  bool success;
  String city;
  List<Weather> result;

  WeatherResponse({this.success, this.city, this.result});

  factory WeatherResponse.fromJson(Map<String, dynamic> json) {
    var weathersFromJson = json['result'] as List<dynamic>;
    List<Weather> weatherList = List<Weather>();
    weathersFromJson.forEach((element) {
      Weather weather = Weather.fromJson(element);
      weatherList.add(weather);
    });

    return WeatherResponse(
      success: json['success'] as bool,
      city:  json['city'] as String,
      result: weatherList
    );

  }
}

Weather Bloc

enum WeatherEvent { getWeather, getDetails }

class WeatherBloc extends Bloc<WeatherEvent, Weather> {
  WeatherBloc(Weather initialState) : super(initialState);

  @override
  Stream<Weather> mapEventToState(WeatherEvent event) async*{
    switch (event) {
      case WeatherEvent.getWeather:
        WeatherRequest().fetchWeathers().then((weatherResponse) =>
          weatherResponse.result.forEach((element) {
            return element;
          })
        );
        break;

      case WeatherEvent.getDetails:
        break;
    }
  }
}

I want to use yield instead of return element and when data comes I want to send this datas weather list results element to UI.

UI Bloc Builder

 BlocBuilder<WeatherBloc, Weather>(
            builder: (context, result) {
              print(result.date);
              return (Text(result.date));
            },
          ),

Maybe I’m missing something. When I write
print(result.date); to my Bloc class it prints. But in the UI class and BlocBuilder there is nothing. When I debug it I see that: after the return element line work it’s not jump to the BlocBuilder cause for each is continues. But when it finish it still not jump. Maybe my architecture or approach can be wrong. Also I’m open to suggestions about thats.

So to summarize I can’t get "stream result’s list element" one by one as stream in bloc builder. Can anyone help?

Solution

You have not defined a state for your Bloc.
You should create a state

class WeatherState
class WeatherLoaded extends WeatherState{
      final Weather weather;
  WeatherLoaded(this.weather);
}

Then your Bloc class should look like this WeatherEvent and WeatherState

class WeatherBloc extends Bloc<WeatherEvent, WeatherState> {
  WeatherBloc(Weather initialState) : super(initialState);

  @override
  Stream<Weather> mapEventToState(WeatherEvent event) async*{
    switch (event) {
      case WeatherEvent.getWeather:
        // Api call call that returns a weather object.
        final res = await WeatherRequest().fetchWeathers();
        yield WeatherLoaded(res);
        break;

      case WeatherEvent.getDetails:
        break;
    }
  }
}

Next, your Bloc Builder should look like this

         BlocBuilder<WeatherBloc, WeatherState>(
            builder: (context, WeatherState state) {
              if(state is WeatherLoaded) {
                return (Text(state.date));
              }
              
            },
          ),

You should rewrite your API call to return a Weather object

Answered By – Tayormi

Answer Checked By – Marilyn (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *