Search code examples
flutterkotlinbloc

Passing arguments in bloc flutter


I'm using Bloc pattern to manage the states of my application , I'm fetching some data from Api , and everything is set up so far , i got stuck in how can i pass a mealID ( the argument i want to pass in bloc to fetch the next api call . i need some help please , Thank you in advance .

  • This is my whole bloc code
 // bloc events 
 enum FoodEvent {category,food}


// bloc state
class FoodState {

}

class InitialLoading extends FoodState{

}
class Loading extends FoodState {}

class Error extends FoodState {
String error;
Error(this.error);
}

class Success extends FoodState {
CategoryModel? categoryModel;
Success(this.categoryModel);
}

class FoodSuccess extends FoodState {
FoodModel? foodModel;
FoodSuccess(this.foodModel);
}


  // Main Bloc class 
  class FoodBloc extends Bloc<FoodEvent,FoodState> {

  FoodRepository foodRepository = FoodRepository(authService: AuthService());

  FoodBloc() : super(InitialLoading()){
        on<FoodEvent>(_onFetchEvent);
  }

    Future<void> _onFetchEvent(FoodEvent event, Emitter<FoodState> emit,) async {

       switch(event){
         case FoodEvent.category:
           emit(Loading());
           try {
             var categoryModel = await foodRepository.getCategory();
             emit(Success(categoryModel));
           } catch (e) {
             emit(Error(e.toString()));
           }
           break;

         case FoodEvent.food:
           emit(Loading());
           try {
             /// Basically i need o pass mealID which i should receive and pass here from screen
             var food = await foodRepository.getFood("1252");
             emit(FoodSuccess(food));
           } catch (e) {
             emit(Error(e.toString()));
           }
           break;
       }
  }



}

  • Class where i init bloc and show data in ui

  class DetailsScreen extends StatefulWidget {
  String mealID;
  DetailsScreen({Key? key,required this.mealID}) : super(key: key);

  @override
  State<DetailsScreen> createState() => _DetailsScreenState();
}

class _DetailsScreenState extends State<DetailsScreen> {
   late FoodBloc foodBloc;
  @override
  void didChangeDependencies() {
    // Here i initialize my bloc 
    foodBloc = BlocProvider.of<FoodBloc>(context);
    foodBloc.add(FoodEvent.food);
    super.didChangeDependencies();
  }

  @override
  void dispose() {
    foodBloc.close();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

Solution

  • Passing argument from the UI depends on your usecases, you can pass using the event or updating your state with the value

    You may also consider changing your event to the recommended class based

    abstract class FoodEvent extends Equatable {
      @override
      List<Object> get props => [];
    }
    
    class CategoryFetched extends FoodEvent {}
    
    class FoodFetched extends FoodEvent {
      FoodFetched(this.mealId);
    
      final String mealId;
      @override
      List<Object> get props => [mealId];
    }
    

    So while adding event here just pass the MealId

    @override
      void didChangeDependencies() {
        // Here i initialize my bloc 
        foodBloc = BlocProvider.of<FoodBloc>(context);
        foodBloc.add(FoodFetched(mealId);
        super.didChangeDependencies();
    }
    

    And your bloc code can be simplified to this:

    class FoodBloc extends Bloc<FoodEvent,FoodState> {
    
      FoodRepository foodRepository = FoodRepository(authService: AuthService());
    
      FoodBloc() : super(InitialLoading()){
           on<CategoryFetched>(_onCategoryFetched);
           on<FoodFetched>(_onFoodFetched);
      }
    
      Future<void> _onFoodFetched(FoodFetched event, Emitter<FoodState> emit) async {
       try {
         var food = await foodRepository.getFood(event.mealId);
         emit(FoodSuccess(food));
       } catch (e) {
         emit(Error(e.toString()));
       }
     }
    
      Future<void> _onCategoryFetched(CategoryFetched event, Emitter<FoodState> emit) async {
      try {
        var categoryModel = await foodRepository.getCategory();
        emit(Success(categoryModel));
      } catch (e) {
        emit(Error(e.toString()));
      }
     }    
    }