VeryGoodOpenSource / formz

A unified form representation in Dart used at Very Good Ventures πŸ¦„

Home Page:https://pub.dev/packages/formz

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Validation with external information

ayalma opened this issue Β· comments

Hi and thank you for lib
How to validate input with external information like checking username availability , or checking password confirmation?

Hi @ayalma πŸ‘‹
Thanks for opening an issue and for the positive feedback!

Check out #5 and let me know if that helps πŸ‘

Thank you for your response.
For password confirmation we can use this way
But for sth like checking username availability with server , or loading dropdown items from server
I think we must be able to show loading indicator or error in ui with aid of input

@felangel, I'm also curious about how to implement server-side validation using Formz (e.g. email uniqueness check). Could there be some way of manually setting errors on FormzInput instances?

Love to hear your thoughts, and I'm happy to PR such functionality.

This is how I ended up doing it. I feels, however, that there should be a better way built into the library:

enum PasswordValidationError { empty, authFailed }

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

  final PasswordValidationError externalError;

  @override
  PasswordValidationError validator(String value) {
    if (externalError != null) {
      return externalError;
    } else if (value?.isNotEmpty == false) {
      return PasswordValidationError.empty;
    }
    return null;
  }
}

@djensen47, thanks for your workaround. I'd also been thinking about it, but it just doesn't feel right.

I've talked to @felangel, and he'll take a look soon.

Thanks for everyone's patience! I am actively discussing ways to achieve this and will report back with a proposal shortly πŸ‘

@felangel, have you been able to come up with a proposal?

A more abstract version of @djensen47's approach would be:

  1. Create extended_formz_input.dart:

    import 'package:formz/formz.dart';
    
    abstract class ExtendedFormzInput<T, E> extends FormzInput<T, E> {
      final E externalError;
    
      const ExtendedFormzInput.pure(T value)
          : externalError = null,
            super.pure(value);
    
      const ExtendedFormzInput.dirty(T value, this.externalError)
          : super.dirty(value);
      
      ExtendedFormzInput copyWithExternalError(E error);
      
      @override
      E get error => externalError ?? super.error;
      
      @override
      bool get valid => error == null;
    
      @override
      int get hashCode => value.hashCode ^ pure.hashCode ^ externalError.hashCode;
    
      @override
      bool operator ==(Object other) {
        if (other.runtimeType != runtimeType) return false;
        return other is ExtendedFormzInput<T, E> &&
            other.value == value &&
            other.externalError == externalError &&
            other.pure == pure;
      }
    }
    
  2. Extend it instead of FormzInput:

    import 'extended_formz_input.dart';
    
    enum EmailInputError { empty, used }
    
    class EmailInput extends ExtendedFormzInput<String, EmailInputError> {
     const EmailInput.pure() : super.pure('');
    
     const EmailInput.dirty(String value, [EmailInputError externalError])
         : super.dirty(value, externalError);
    
     @override
     EmailInputError validator(String value) {
       return value?.isNotEmpty == true ? null : EmailInputError.empty;
     }
    
     @override
     EmailInput copyWithExternalError(EmailInputError error) {
       return EmailInput.dirty(value, error);
     }
    }
  3. Use it:

    final emailInput = EmailInput.dirty(email);
    // Do some external validation
    final newEmailInput = emailInput.copyWithExternalError(EmailInputError.used);

Closing for now but feel free to comment with any additional questions and I'm happy to continue the conversation πŸ‘