Search code examples
fluttervalidationdartbloc

how can i confirm password using formz in flutter


When I want to confirm my password, but i can not compare the first and last passwords.

Here my password class. It works fine, but confirmPassword section not.

class Password extends FormzInput<String, PasswordValidationError> {
  const Password.pure() : super.pure('');
  const Password.dirty([String value = '']) : super.dirty(value);

  static final _passwordRegExp = RegExp(r'^[A-Za-z\d@$!%*?&]{8,}$');

  @override
  PasswordValidationError? validator(String value) {
    if (value.isEmpty) {
      return PasswordValidationError.empty;
    }
    return _passwordRegExp.hasMatch(value)
        ? null
        : PasswordValidationError.invalid;
  }
}

You can ask what is the value in validator. Let me show you.

  void passwordChanged(String value) {
    final password = Password.dirty(value);
    emit(state.copyWith(
      password: password,
      status: Formz.validate(
          [state.name, state.email, password, state.confirmPassword]),
    ));
  }

This is my normal password field. Now let's look confirm section.

class ConfirmPassword
    extends FormzInput<String, ConfirmedPasswordValidationError> {
  const ConfirmPassword.pure() : super.pure('');
  const ConfirmPassword.dirty([String value = '']) : super.dirty(value);

  static final _confirmPasswordRegExp = RegExp(r'^[A-Za-z\d@$!%*?&]{8,}$');
  
  @override
  ConfirmedPasswordValidationError? validator(String value) {
    if (value.isEmpty) {
      return ConfirmedPasswordValidationError.empty;
    } else if (!_confirmPasswordRegExp.hasMatch(value)) {
      return ConfirmedPasswordValidationError.invalid;
    }
    return (password**I mentioned here** == value)
        ? null
        : ConfirmedPasswordValidationError.mismatch;
  }
}

and value in validator:

  void confirmPasswordChanged(String value) {
    final confirmPassword =
        ConfirmPassword.dirty(value);
    emit(state.copyWith(
      confirmPassword:
          state.password.valid ? confirmPassword : const ConfirmPassword.pure(),
      status: Formz.validate(
          [state.name, state.email, state.password, confirmPassword]),
    ));
  }

How can i reach the first (normal) value field in confirmPassword section? Or Is there any way to the use with formz?


Solution

  • This is a validator

     import 'package:formz/formz.dart';
    
    enum ConfirmedPasswordValidationError {
      invalid,
      mismatch,
    }
    
    class ConfirmedPassword extends FormzInput<String, ConfirmedPasswordValidationError> {
      final String password;
    
      const ConfirmedPassword.pure({
        this.password = ''
      }) : super.pure('');
    
      const ConfirmedPassword.dirty({
        required this.password,
        String value = ''
      }) : super.dirty(value);
    
      @override
      ConfirmedPasswordValidationError? validator(String value) {
        if (value.isEmpty) {
          return ConfirmedPasswordValidationError.invalid;
        }
        return password == value
            ? null
            : ConfirmedPasswordValidationError.mismatch;
      }
    }
    
    extension Explanation on ConfirmedPasswordValidationError {
      String? get name {
        switch(this) {
          case ConfirmedPasswordValidationError.mismatch:
            return 'passwords must match';
          default:
            return null;
        }
      }
    }
    

    state management func bloc

      void _passwordConfirmationChanged(PasswordConfirmationChangede,Emitter<SignUpFormState> emit){
        final confirmedPassword = ConfirmedPassword.dirty(
          password: state.password.value,
          value: e.passwordConfirmStr,
        );
        emit(state.copyWith(
          confirmedPassword: confirmedPassword,
          status: Formz.validate([
            state.email,
            state.password,
            confirmedPassword,
          ]),
        ));
      }
    

    Widget class

    class _ConfirmPasswordInput extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return BlocBuilder<SignUpFormBloc, SignUpFormState>(
          buildWhen: (previous, current) =>
              previous.password != current.password ||
              previous.confirmedPassword != current.confirmedPassword,
          builder: (context, state) {
            return TextField(
              key: const Key('signUpForm_confirmedPasswordInput_textField'),
              onChanged: (confirmPassword) => context.read<SignUpFormBloc>()
                .add(SignUpFormEvent.passwordConfirmationChanged(confirmPassword)),
              obscureText: true,
              decoration: InputDecoration(
                labelText: 'confirm password',
                helperText: '',
                errorText: state.confirmedPassword.invalid
                    ? 'passwords do not match'
                    : null,
              ),
            );
          },
        );
      }
    }