Search code examples
flutterdartblocstate-managementflutter-bloc

How to properly show alertbox in flutter using bloc?


I'm trying to learn bloc and I want to show an alertbox if the credentials are not valid. Im getting the state to the ui. But the alert box is not popping up.

The code is as follows.

bloc

class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
  SignUpBloc() : super(SignUpInitialState()) {
    on<OnClickedLoginEvent>((event, emit) => emit(LoginState()));
    on<UserSignupEvent>(_signUp);
    on<ValidateUserEvent>(_validateUserCred);
  }

  Future<SignUpState> _signUp(
      UserSignupEvent event, Emitter<SignUpState> emit) async {
    debugPrint("${event.email},${event.password}");
    try {
      add(ValidateUserEvent(event.email)); // added this event

      //api calls

  }

  void _validateUserCred(ValidateUserEvent event, Emitter<SignUpState> emit) {
    if (event.email.isEmpty) {
      emit(UserCredNotValid("Email is empty"));
    }
    emit(UserCredValid("TESTing check valid"));
  }
 }
}

States

abstract class SignUpState extends Equatable {}

class UserCredNotValid extends SignUpState {
  final String message;
  UserCredNotValid(this.message);
  @override
  List<Object?> get props => [message];
}

class UserCredValid extends SignUpState{
  final String message;

  UserCredValid(this.message);
  @override
  List<Object?> get props => [message];

}

event

abstract class SignUpEvent extends Equatable {}

class ValidateUserEvent extends SignUpEvent{
  final String email;

  ValidateUserEvent(this.email);
  @override
  List<Object?> get props => [email];
}

on the ui i have used bloclistener

 BlocListener(
  bloc: BlocProvider.of<SignUpBloc>(context),
   listener: (context, state) {
         if (state is UserCredNotValid) {
          debugPrint(state.message); // i'm getting the value here. 
           AlertDialog(
            title: Text(state.message),
             );
             } 

Is this the correct way to show an widget based on state? If not what is the better way using bloc?


Solution

  • Based on the code that i see I have created a example and made some changes as per your need.

    Here I have used the following

    Instead of bloc lisetner i have used the BlocConsumer which does the work of both listing and building so you don't need any other listner to listen. Check also the bloc implementation. State is being emited based on the email empty type. if not the sign up process will continue.

    Main UI File

    import 'package:flutter/material.dart';
    import 'bloc/signup_state.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    import 'bloc/signup_bloc.dart';
    import 'bloc/signup_event.dart';
    
    void main() {
      runApp(MaterialApp(
        home: BlocProvider(
          create: (_) => SignUpBloc(),
          child: const MyApp(),
        ),
      ));
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Signup App'),
          ),
          body: const MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({Key? key}) : super(key: key);
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      TextEditingController emailcontroller = TextEditingController();
    
      TextEditingController passwordcontroller = TextEditingController();
    
      @override
      Widget build(BuildContext context) {
        return BlocConsumer(
          bloc: BlocProvider.of<SignUpBloc>(context),
          listener: (context, state) {
            print(state);
            if (state is UserCredNotValid) {
              print('this is empty');
              showDialog(
                context: context,
                builder: (ctx) => AlertDialog(
                  title: const Text("Email is empty "),
                  content: const Text("Please add email for signup process"),
                  actions: <Widget>[
                    TextButton(
                      onPressed: () {
                        Navigator.of(ctx).pop();
                      },
                      child: Container(
                        padding: const EdgeInsets.all(14),
                        child: const Text("okay"),
                      ),
                    ),
                  ],
                ),
              );
            }
          },
          builder: (context, state) => Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              TextField(
                controller: emailcontroller,
              ),
              TextField(
                controller: passwordcontroller,
              ),
              ElevatedButton(
                  onPressed: () {
                    context
                        .read<SignUpBloc>()
                        .add(ValidateUserEvent(emailcontroller.text));
                  },
                  child: Text('SignUp'))
            ],
          ),
        );
      }
    }
    
    
    

    Bloc file

    import 'dart:math';
    
    import 'package:flutter_bloc/flutter_bloc.dart';
    import '../bloc/signup_event.dart';
    import '../bloc/signup_state.dart';
    
    class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
      SignUpBloc() : super(SignUpInitialState()) {
        // on<OnClickedLoginEvent>((event, emit) => emit(LoginState()));
    
        // on<ValidateUserEvent>(_validateUserCred);
    
        on<ValidateUserEvent>((event, emit) {
          print(event.email.isEmpty);
          if (event.email.isEmpty) {
            emit(UserCredNotValid(event.email));
          } else {
            print(event.email);
            // this is where you signup event will be executed.
            add(UserSignupEvent());
          }
        });
    
        on<UserSignupEvent>((event, emit) {
          // this is where the signup api will be called.
        });
      }
    
      ///Not sure what you are doing nut i have commented it for now
    
    //   Future<SignUpState> _signUp(
    //       UserSignupEvent event, Emitter<SignUpState> emit) async {
    //     debugPrint("${event.email},${event.password}");
    //     try {
    //       add(ValidateUserEvent(event.email)); // added this event
    
    //       //api calls
    
    //   }
    
    //   void _validateUserCred(ValidateUserEvent event, Emitter<SignUpState> emit) {
    //     if (event.email.isEmpty) {
    //       emit(UserCredNotValid("Email is empty"));
    //     }
    //     emit(UserCredValid("TESTing check valid"));
    //   }
    //  }
    }
    
    

    Event File

    
    import 'package:equatable/equatable.dart';
    
    abstract class SignUpEvent extends Equatable {}
    
    class ValidateUserEvent extends SignUpEvent {
      final String email;
    
      ValidateUserEvent(this.email);
      @override
      List<Object?> get props => [email];
    }
    
    class UserSignupEvent extends SignUpEvent {
      @override
      List<Object?> get props => [];
    }
    
    

    State File

    import 'package:equatable/equatable.dart';
    
    abstract class SignUpState {}
    
    class UserCredNotValid extends SignUpState {
      final String message;
    
      UserCredNotValid(this.message);
    }
    
    class UserCredValid extends SignUpState with EquatableMixin {
      final String message;
    
      UserCredValid(this.message);
      @override
      List<Object?> get props => [message];
    }
    
    class SignUpInitialState extends SignUpState with EquatableMixin {
      @override
      List<Object?> get props => [];
    }