ssuhat
ssuhat

Reputation: 7656

Flutter Bloc - How to show keep showing error when submit is fail

I'm learning bloc and using equatable.

here is my code

login_state.dart

import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';

abstract class LoginState extends Equatable {
  @override
  List<Object> get props => [];
}

class LoginInitial extends LoginState {}

class LoginLoading extends LoginState {}

class LoginSuccess extends LoginState {
  final Map token;

  LoginSuccess({@required this.token});
}

class LoginFailure extends LoginState {
  final Map error;

  LoginFailure({@required this.error});

  @override
  List<Object> get props => null;
}

login_view

  @override
  Widget build(BuildContext context) {
    final bool loading = _authStore.loading;

    return BlocProvider(
        create: (BuildContext context) => _loginBloc,
        child: BlocListener<LoginBloc, LoginState>(
          listener: (BuildContext context, state) {
            if (state is LoginFailure) {
              print("loginFailure is triggered with ${state.error}");
              FlashAlert(context: context, message: state.error['message']).showFlash();
            }
          },
          child: Scaffold(
            resizeToAvoidBottomInset: true,
            resizeToAvoidBottomPadding: true,
            backgroundColor: Colors.white,
            appBar: AppBar(
              automaticallyImplyLeading: true,
            ),
            body: Container(
              padding: EdgeInsets.symmetric(horizontal: spacing(3)),
              margin: EdgeInsets.only(top: spacing(2)),
              child: widget.isLogin ? loginView() : registerView(),
            ),
            floatingActionButton: FloatingActionButton(
              backgroundColor: theme.primaryColor,
              onPressed: () {
                widget.isLogin ? handleLogin('') : handleRegister();
              },
              child: loading ? Progress() : Icon(EvaIcons.arrowIosForward),
            ),
          ),
        ));
  }

I've tried putting [error] on get props.

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

The problem is FlashAlert is only run 1 times when error occur. How can I keep using equatable but keep triggering the FlashAlert when error occur?.

THanks.

----- edit using blocbuilder ---

@override
  Widget build(BuildContext context) {
    final bool loading = _authStore.loading;

    return BlocProvider(
      create: (BuildContext context) => _loginBloc,
      child: BlocBuilder<LoginBloc, LoginState>(builder: (BuildContext context, state) {
        if (state is LoginFailure) {
          print("loginFailure is triggered with ${state.error}");

          FlashAlert(context: context, message: state.error['message']).showFlash();
        }

        return Scaffold(
          resizeToAvoidBottomInset: true,
          resizeToAvoidBottomPadding: true,
          backgroundColor: Colors.white,
          appBar: AppBar(
            automaticallyImplyLeading: true,
          ),
          body: Container(
            padding: EdgeInsets.symmetric(horizontal: spacing(3)),
            margin: EdgeInsets.only(top: spacing(2)),
            child: widget.isLogin ? loginView() : registerView(),
          ),
          floatingActionButton: FloatingActionButton(
            backgroundColor: theme.primaryColor,
            onPressed: () {
              widget.isLogin ? handleLogin('') : handleRegister();
            },
            child: state is LoginLoading ? Progress() : Icon(EvaIcons.arrowIosForward),
          ),
        );
      }),
    );
  }

return error:

VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: setState() or markNeedsBuild() called during build. This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase. The widget on which setState() or markNeedsBuild() was called was: Overlay-[LabeledGlobalKey<OverlayState>#21a25]

Upvotes: 1

Views: 1884

Answers (1)

Viren V Varasadiya
Viren V Varasadiya

Reputation: 27137

You are using BlocListener that's why you are facing this error.BlocListener will only execute once only.

Following lines are from official documentation.

BlocListener is a Flutter widget which takes a BlocWidgetListener and an optional Bloc and invokes the listener in response to state changes in the bloc. It should be used for functionality that needs to occur once per state change such as navigation, showing a SnackBar, showing a Dialog, etc...

You can use BlocBuilder and it will solve your issue.

Update:

This is happening because when build method call at that time your are trying to show FlashAlert, so you can avoid it by adding wait of 1 microsecond.

call following method instead on doing in bloc.

 void callme() async {
    await Future.delayed(Duration(microseconds: 1));
    if (state is LoginFailure) {
      print("loginFailure is triggered with ${state.error}");

      FlashAlert(context: context, message: state.error['message']).showFlash();
    }
  }

Upvotes: 1

Related Questions