Как проверить форму при отправке во флаттере с помощью flutter_bloc?

Это мой экран изменения пароля. Я использовал flutter_bloc для реализации шаблона mvvc. Эта страница отлично работает с bloc. Но то, что я пытаюсь достичь, - это проверить форму при отправке формы. Поскольку я был новичком в трепетании, я понятия не имею, как это сделать.

Событие смены пароля

abstract class ChangePasswordEvent extends Equatable {
  const ChangePasswordEvent();
}

class SubmitButtonPressed extends ChangePasswordEvent {
  final String oldPassword;
  final String newPassword;

  const SubmitButtonPressed({@required this.oldPassword, this.newPassword});

  @override
  List<Object> get props => [oldPassword, newPassword];
}

Изменить состояние пароля

abstract class ChangePasswordState extends Equatable {
  const ChangePasswordState();

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

class ChangePasswordInitial extends ChangePasswordState {}

class ChangePasswordLoading extends ChangePasswordState {}

class ChangePasswordSuccess extends ChangePasswordState {}

class ChangePasswordFailure extends ChangePasswordState {
  final String error;

  const ChangePasswordFailure({@required this.error});

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

  @override
  String toString() => 'ChangePasswordFailure { error: $error }';
}

Блок изменения паролей

class ChangePasswordBloc
    extends Bloc<ChangePasswordEvent, ChangePasswordState> {
  final UserRepository userRepository;

  ChangePasswordBloc({
    @required this.userRepository,
  }) : assert(userRepository != null);

  @override
  ChangePasswordState get initialState => ChangePasswordInitial();

  @override
  Stream<ChangePasswordState> mapEventToState(
      ChangePasswordEvent event) async* {
    if (event is SubmitButtonPressed) {
      yield ChangePasswordLoading();

      try {
        final bool isPasswordChanged = await userRepository.changePassword(
          event.oldPassword,
          event.newPassword,
        );

        if (isPasswordChanged) {
          yield ChangePasswordSuccess();
        }
      } catch (error) {
        yield ChangePasswordFailure(error: error);
      }
    }
  }
}

Страница изменения пароля

class ChangePasswordPage extends StatelessWidget {
  final UserRepository userRepository;

  ChangePasswordPage({Key key, @required this.userRepository})
      : assert(userRepository != null),
        super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Change Password'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: BlocProvider(
          create: (context) {
            return ChangePasswordBloc(
              userRepository: userRepository,
            );
          },
          child: ChangePasswordForm(),
        ),
      ),
    );
  }
}

Форма изменения пароля

class ChangePasswordForm extends StatefulWidget {
  @override
  _ChangePasswordFormState createState() => _ChangePasswordFormState();
}

class _ChangePasswordFormState extends State<ChangePasswordForm> {
  final userRepository = UserRepository();
  final _formKey = GlobalKey<FormState>();

  final _oldPassController = TextEditingController();
  final _newPassController = TextEditingController();
  final _confirmPassController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    _onSubmitButtonPressed() {
      BlocProvider.of<ChangePasswordBloc>(context).add(
        SubmitButtonPressed(
          oldPassword: _oldPassController.text,
          newPassword: _newPassController.text,
        ),
      );
    }

    return BlocListener<ChangePasswordBloc, ChangePasswordState>(
      listener: (context, state) {
        if (state is ChangePasswordFailure) {
          Scaffold.of(context).showSnackBar(
            SnackBar(
              content: Text('${state.error}'),
              backgroundColor: Colors.red,
            ),
          );
        }

        if (state is ChangePasswordSuccess) {
          Scaffold.of(context).showSnackBar(
            SnackBar(
              content: Text('Password Changed Successfully'),
              backgroundColor: Colors.green,
            ),
          );
        }
      },
      child: BlocBuilder<ChangePasswordBloc, ChangePasswordState>(
        builder: (context, state) {
          return Form(
            key: _formKey,
            child: Column(
              children: [
                TextFormField(
                  decoration: InputDecoration(labelText: 'Old Password'),
                  controller: _oldPassController,
                ),
                SizedBox(height: 20.0),
                TextFormField(
                  decoration: InputDecoration(labelText: 'New Password'),
                  controller: _newPassController,
                  obscureText: true,
                ),
                SizedBox(height: 20.0),
                TextFormField(
                  decoration: InputDecoration(labelText: 'Confirm Password'),
                  controller: _confirmPassController,
                  obscureText: true,
                  validator: (value) {
                    final String _newPassword = _newPassController.text;

                    if (_newPassword != value) {
                      return "Password Mismatch";
                    }

                    return null;
                  },
                ),
                SizedBox(height: 20.0),
                RaisedButton(
                  onPressed: () {
                    if (state is! ChangePasswordLoading) {
                      final form = _formKey.currentState;

                      if (form.validate()) {
                        return _onSubmitButtonPressed();
                      }

                      return null;
                    }
                  },
                  child: Text('Submit'),
                ),
              ],
            ),
          );
        },
      ),
    );
  }
}

person Dheepak S    schedule 18.02.2020    source источник
comment
Вы проверяете его при отправке _formKey.currentState.validate(). В чем будет ваша проблема?   -  person Sebastian    schedule 18.02.2020
comment
Оформить заказ flutter_form_bloc, он bloc предназначен для форм, это сэкономит вам много кода в вашем случае .   -  person GiancarloCode    schedule 21.02.2020


Ответы (2)


Вы можете посмотреть их пример по адресу: Проверка формы

В примере проверяется формат электронной почты и пароля, вы должны изменить его соответствующим образом. Ваше состояние должно быть примерно таким:

class MyFormState extends Equatable {
  final String email;
  final bool isEmailValid;
  final String password;
  final bool isPasswordValid;
  final bool formSubmittedSuccessfully;

  bool get isFormValid => isEmailValid && isPasswordValid;
  //....
}

BLoC для проверки:

class MyFormBloc extends Bloc<MyFormEvent, MyFormState> {
  final RegExp _emailRegExp = RegExp(
    r'^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$',
  );
  final RegExp _passwordRegExp = RegExp(
    r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$',
  );

  @override
  MyFormState get initialState => MyFormState.initial();

  @override
  void onTransition(Transition<MyFormEvent, MyFormState> transition) {
    print(transition);
  }

  @override
  Stream<MyFormState> mapEventToState(
    MyFormEvent event,
  ) async* {
    if (event is EmailChanged) {
      yield state.copyWith(
        email: event.email,
        isEmailValid: _isEmailValid(event.email),
      );
    }
    if (event is PasswordChanged) {
      yield state.copyWith(
        password: event.password,
        isPasswordValid: _isPasswordValid(event.password),
      );
    }
    if (event is FormSubmitted) {
      yield state.copyWith(formSubmittedSuccessfully: true);
    }
    if (event is FormReset) {
      yield MyFormState.initial();
    }
  }

  bool _isEmailValid(String email) {
    return _emailRegExp.hasMatch(email);
  }

  bool _isPasswordValid(String password) {
    return _passwordRegExp.hasMatch(password);
  }
}

И метод построения формы:

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<MyFormBloc, MyFormState>(
      builder: (context, state) {
        if (state.formSubmittedSuccessfully) {
          return SuccessDialog(onDismissed: () {
            _emailController.clear();
            _passwordController.clear();
            _myFormBloc.add(FormReset());
          });
        }
        return Form(
          child: Column(
            children: <Widget>[
              TextFormField(
                controller: _emailController,
                decoration: InputDecoration(
                  icon: Icon(Icons.email),
                  labelText: 'Email',
                ),
                keyboardType: TextInputType.emailAddress,
                autovalidate: true,
                validator: (_) {
                  return state.isEmailValid ? null : 'Invalid Email';
                },
              ),
              TextFormField(
                controller: _passwordController,
                decoration: InputDecoration(
                  icon: Icon(Icons.lock),
                  labelText: 'Password',
                ),
                obscureText: true,
                autovalidate: true,
                validator: (_) {
                  return state.isPasswordValid ? null : 'Invalid Password';
                },
              ),
              RaisedButton(
                onPressed: state.isFormValid ? _onSubmitPressed : null,
                child: Text('Submit'),
              ),
            ],
          ),
        );
      },
    );
  }
person Thuong    schedule 10.04.2020

Я считаю, что не лучше использовать пакет flutter_bloc для целей проверки, так как это приведет к перестройке всех элементов управления. Вместо этого используйте примитивные объекты, такие как Stream и Provider, как описано здесь. https://www.youtube.com/watch?v=JqWK4oitJFs

Дополнительная ссылка: https://medium.com/swlh/how-to-create-a-simple-login-form-in-flutter-using-bloc-pattern-b55ad52a2a10

person MoeHamdan    schedule 24.06.2020