Mahmoud Abdellatief
Mahmoud Abdellatief

Reputation: 66

Flutter Bloc add event triggers only once for the same widget and won't trigger again

I'm new to Bloc ( coming from provider ), everything works fine except whenever i try to add a second event to the same bloc on the same widget it never gets triggered, even the mapEventToState doesn't trigger,

i first add an event to get posts in the initState, this works fine, later on i add event on the refresh indicator onRefresh function, everything inside the function triggers Except the bloc add event.

I'm using Equatable, so i tried without it and no difference . i tried to make separate class for each state, still Not working as well . i tried Not to close the bloc on dispose, also not working.

ForumMain widget is a child of a BottomNavigationTabBar

here is my code : main.dart

        List<BlocProvider<Bloc>> _blocProviders() => [
    BlocProvider<UserBloc>(
      create: (context) => UserBloc(userRepository: RepositoryProvider.of(context),navigator: RepositoryProvider.of(context),prefs: RepositoryProvider.of(context),
      ),
    ),
    BlocProvider<ForumBloc>(
      create: (context) => ForumBloc( RepositoryProvider.of(context),_userBloc, RepositoryProvider.of(context),),
    ),
    BlocProvider<WUpdateBloc>(
      create: (context) => WUpdateBloc(
        RepositoryProvider.of(context),
  RepositoryProvider.of(context)),
    ),
    BlocProvider<PlanBloc>(
        create: (context) => PlanBloc(RepositoryProvider.of(context),RepositoryProvider.of(context),
        )),
  ];
  Widget build(BuildContext context) {

    return LayoutBuilder(builder: (context, constraints) {
      return OrientationBuilder(builder: (context, orientation) {
        return RepositoryProvider(
          create: (context) => _dioInstance(),
          child: MultiRepositoryProvider(
            providers: _repositoryProviders(),
            child: MultiBlocProvider(
                providers: _blocProviders(),
                child: Builder(
                  builder: (context) => MaterialApp(
                    // theme: AppTheme.theme,
                    navigatorKey: navigatorKey,
                    navigatorObservers: [appNavigatorObserver],
                    localizationsDelegates: _getLocalizationsDelegates(),
                    supportedLocales: S.delegate.supportedLocales,
                    home: LoadingPage(),
                    debugShowCheckedModeBanner: false,
                  ),
                )),
          ),
        );
      });
    });
  } 

forum_bloc.dart

class ForumBloc extends Bloc<ForumEvent, ForumState> {

  ForumBloc(this._forumRepository, this._userBloc, this.navigator) : super(ForumState.defaultState());

  final ForumRepository _forumRepository;
  final UserBloc _userBloc;
  final AppNavigator navigator;

  @override
  Stream<ForumState> mapEventToState(
      ForumEvent event,
      ) async* {
    if (event is GetPostsEvent)  yield* _getPosts(event);
    if (event is GetCommentsEvent) yield* _getComments(event);
    if (event is RefreshPostsEvent)  yield* _refreshPosts(event);
    if (event is RefreshCommentsEvent) yield* _refreshComments(event);
    if (event is NewPostRequest) yield* _newPost(event);
    if (event is NewCommentRequest) yield* _newComment(event);
  }

  Stream<ForumState> _getPosts(GetPostsEvent event) async* {
    print("get posts event called");
    yield state.copyWith(status: BlocStatus.pending);
    try {
      // show progress hud
      final postsResponse = await _forumRepository.getPosts(event.trainerID);

      postsResponse.posts.sort((a, b) => b.datetimeCreated.compareTo(a.datetimeCreated));
      print(postsResponse.posts[0].question);
      yield state.copyWith(posts: postsResponse.posts, status: BlocStatus.success, total: postsResponse.posts.length);

    } on DioError catch (error) {
      // report error
      yield state.copyWith(status: BlocStatus.error, appError: error.toAppError());

    }

  }
  Stream<ForumState> _refreshPosts(RefreshPostsEvent event) async* {
    print("refresh posts event called");
    try {
      // show progress hud
      final postsResponse = await _forumRepository.getPosts(event.trainerID);
      print(postsResponse.posts.length);
      postsResponse.posts.sort((a, b) => b.datetimeCreated.compareTo(a.datetimeCreated));
      yield state.copyWith(posts: postsResponse.posts, status: BlocStatus.success, total: postsResponse.posts.length);

    } on DioError catch (error) {
      // report error
      // yield state.copyWith(status: BlocStatus.error, appError: error.toAppError());

    }
  }

forum_state.dart

    class ForumState extends Equatable {
  ForumState({
    this.total,
    this.posts,
    this.status,
    this.appError
  });
  final int total;
  final List<BlogPost> posts;
  final BlocStatus status;
  final AppError appError;
  factory ForumState.defaultState() => ForumState(
    total: 0,
    posts: [],
status: BlocStatus.idle,
appError: null
  );
  ForumState copyWith({
    int total,
    List<BlogPost> posts,
    AppError appError,
    BlocStatus status,  }) {  return ForumState(
      total: total ?? this.total,
      posts: posts ?? this.posts,
      status: status,
    );}
  @override
  List<Object> get props => [posts,total,status,appError];

  @override
  bool get stringify => true;
}

forum_state.dart failed trial to make separate class for each state

class ForumState extends Equatable {
  @override
  // TODO: implement props
  List<Object> get props => [];

}
class ForumStateLoading extends ForumState {

}
class ForumStateSuccess extends ForumState {
    ForumStateSuccess({
    this.total,
    this.posts,
  });
  final int total;
  final List<BlogPost> posts;

  @override
  List<Object> get props => [posts,total];

}
class ForumStateRefresh extends ForumState {
  ForumStateRefresh({
    this.total,
    this.posts,
  });
  final int total;
  final List<BlogPost> posts;

  @override
  List<Object> get props => [posts,total];

}
class ForumStateError extends ForumState {
  ForumStateError({
    this.error,

  });
  final AppError error;


  @override
  List<Object> get props => [error];
}

forum_event.dart

    abstract class ForumEvent extends Equatable  {
  const ForumEvent();
  @override
  List<Object> get props => [];
}
class GetPostsEvent extends ForumEvent {
  final String trainerID;
  GetPostsEvent(this.trainerID);

}
class RefreshPostsEvent extends ForumEvent {
  final String trainerID;
  RefreshPostsEvent(this.trainerID);
}
class GetCommentsEvent extends ForumEvent {
  final String postID;
  final String trainerID;
  GetCommentsEvent(this.postID,this.trainerID);
}
class RefreshCommentsEvent extends ForumEvent {
  final String postID;
  final String trainerID;
  RefreshCommentsEvent(this.postID,this.trainerID);
}
class SendPostEvent extends ForumEvent {
  final NewPostRequest postRequest;
  SendPostEvent(this.postRequest);
}
class SendCommentEvent extends ForumEvent {
  final NewCommentRequest commentRequest;
  SendCommentEvent(this.commentRequest);
}

forum_screen.dart

    class ForumMain extends StatefulWidget {
  @override
  _ForumMainState createState() => _ForumMainState();
}

class _ForumMainState extends State<ForumMain> {
  TextEditingController nameController = TextEditingController();
  MyTheme myTheme = MyTheme();
  ForumBloc _forumBloc;
  PlanBloc _planBloc;
  Completer<void> _refreshCompleter;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
   myTheme.initLoadingHUD();
    _forumBloc = BlocProvider.of<ForumBloc>(context);
    _planBloc = BlocProvider.of<PlanBloc>(context);
    _forumBloc.add(GetPostsEvent(_planBloc.state.chosenOrder.trainer.id));
    _refreshCompleter = Completer<void>();
  }
  @override
  void dispose() {
    _forumBloc.close();
    _planBloc.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {

    ScreenUtil.init(context, width: 375, height: 812, allowFontScaling: true);

    return BlocConsumer<ForumBloc,ForumState>(
        listener: (context, state) {
          print(state.status.toString());
          setState(() {
            _refreshCompleter?.complete();
            _refreshCompleter = Completer();
          });
          myTheme.errorBlocListener(context, state.appError);
        },
        cubit: _forumBloc,
        builder: (context, state) {
          return Scaffold(
              backgroundColor: Colors.white,
              appBar: ForumAppBar(
                height: 80.h,
                forum: true,
              ),
              body: state.status == BlocStatus.success ? Stack(
                children: [
                  RefreshIndicator(
                    onRefresh: () {
                       _forumBloc.add(RefreshPostsEvent(
                          _planBloc.state.chosenOrder.trainer.id));
                      return _refreshCompleter.future;
                    },
                    child: ListView(
                        children: state.posts.map((e) {

Upvotes: 2

Views: 2250

Answers (2)

digitaljoni
digitaljoni

Reputation: 1397

You can try instead of _blocProviders() just place the List of providers inside MultiBlocProvider( providers: [ ... ],.

I see. Please try removing the following code. I don't think you should close it in this widget, since this is not where you initialize it.

_forumBloc.close();
_planBloc.close();

Upvotes: 0

Chinmay Mourya
Chinmay Mourya

Reputation: 824

Please change your forum_event file like this:

   abstract class ForumEvent extends Equatable  {
    const ForumEvent([List props = const []]) : super();
   }


   class GetPostsEvent extends ForumEvent {
    final String trainerID;
    GetPostsEvent(this.trainerID);
    
    @override
    List<Object> get props => [trainerID];
   }

   class RefreshPostsEvent extends ForumEvent {
    final String trainerID;
    RefreshPostsEvent(this.trainerID);
    
    @override
    List<Object> get props => [trainerID];
   }

   class GetCommentsEvent extends ForumEvent {
    final String postID;
    final String trainerID;
    GetCommentsEvent(this.postID,this.trainerID);

    @override
    List<Object> get props => [postID, trainerID];
   }

   class RefreshCommentsEvent extends ForumEvent {
    final String postID;
    final String trainerID;
    RefreshCommentsEvent(this.postID,this.trainerID);

    @override
    List<Object> get props => [postID, trainerID];
   }

   class SendPostEvent extends ForumEvent {
    final NewPostRequest postRequest;
    SendPostEvent(this.postRequest);

    @override
    List<Object> get props => [postRequest];
   }

   class SendCommentEvent extends ForumEvent {
    final NewCommentRequest commentRequest;
    SendCommentEvent(this.commentRequest);

    @override
    List<Object> get props => [commentRequest];
   }

Upvotes: 1

Related Questions