Создать асинхронный валидатор в Flutter - PullRequest
0 голосов
/ 26 марта 2019

У меня есть асинхронная функция в Flutter , которая принимает значение валидатора в качестве аргумента:

validatePhone(number) {
  bool _isValid;

  Requests.get("http://apilayer.net/api/validate?value=$number", json: true)
      .then((val) {
    if (val['valid']) {
      // setState(() {  <- also tried setting state here
      _isValid = true;
      // });
    } else {
      // setState(() {
      _isValid = false;
      // });
    }
  });

  return _isValid;
}

и

TextFormField(
  validator: (value) {
    if (value.isEmpty) {
      return 'Please your phone number';
    } else {
      if (validatePhone(value)) {
        return 'Your phone number is not valid';
      }
    }
  },
),

, но это не такДля работы всегда возвращается null или начальное значение, установленное в validatePhone.Любая идея, как я могу сделать эту работу?

1 Ответ

0 голосов
/ 26 марта 2019

Как было сказано в комментариях, невозможно иметь асинхронные валидаторы, поскольку ожидается, что validator вернет a String, а не "Future".

Однако в вашем коде есть ряд неправильных вещей.Прежде всего, validatePhone возвращается до установки _isValid, поэтому вы получаете значение null, потому что оно никогда не было установлено на что-либо.Ваш запрос завершается после возврата validatePhone и настройка _isValid в этот момент бесполезна.

Давайте попробуем исправить validatePhone:

Future<bool> validatePhone(number) async {
  bool _isValid;

  final val = await Requests.get(
          "http://apilayer.net/api/validate?value=$number",
          json: true);

  if (val['valid']) {
    // setState(() {
      _isValid = true;
    // });
  } else {
    // setState(() {
      _isValid = false;
    // });
  }

  return _isValid;
}

, как вы видите, его возвращаемое значение должно было стать Future<bool>, а не bool.Нет способа это исправить.Если validator было разрешено вернуть Future, то это могло бы сработать.

Вам нужно будет реализовать свою логику валидации нестандартным мучительным способом.

Редактировать: вот вам и нестандартный болезненный способ:)

String lastValidatedNumber;
String lastRejectedNumber;

// this will be called upon user interaction or re-initiation as commented below
String validatePhone(String number) {
  if (lastValidatedNumber == number) {
    return null;
  } else if (lastRejectedNumber == number) {
    return "Phone number is invalid";
  } else {
    initiateAsyncPhoneValidation(number);
    return "Validation in progress";
  }
}

Future<void> initiateAsyncPhoneValidation(String number) async {
  final val = await Requests.get(
          "http://apilayer.net/api/validate?value=$number",
          json: true);

  if (val['valid']) {
    lastValidatedNumber = number;
  } else {
    lastRejectedNumber = number;
  }
  _formKey.currentState.validate(); // this will re-initiate the validation
}

Вам нужен ключ формы:

final _formKey = GlobalKey<FormState>();

И ваша форма должна автоматически проверяться:

    child: Form(
      key: _formKey,
      autovalidate: true,
      child: TextFormField(
        validator: validatePhone
      )
    )

Я не уверен на 100%, будет ли это работать, ноэто стоит попробовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...