Обновление ошибки TextFormField вне валидатора - PullRequest
0 голосов
/ 25 марта 2020

В соответствии с документами TextFormField, единственный способ получить отображение erorr под TextFormField - это вернуть строку ошибки из функции валидатора. Тем не менее, у меня есть текстовый ввод, который может быть проверен только после вызова на сервер, и ответ от сервера (если он действителен) также необходимо использовать позже. Поэтому я делаю это только тогда, когда пользователь нажимает Отправить. Однако, если сервер возвращает неверный ответ, мне нужно обновить текст ошибки, но, поскольку я вне валидатора, я не могу этого сделать.

Правильно ли я подхожу к этому? Есть ли способ выполнить sh это?

TextFormField(
    autofocus: true,
    onSaved: (String value) => passcode = value,
),
SizedBox(50.0),
RaisedButtton(
    child: Text('SUBMIT'),
    onPressed: () async {
        _formKey.currentState.save();

        dynamic response = await someServerCall();

        if (response.token) {
            // Valid, use token
        } else {
            // INVALID, update error text somehow
        }
    }
)

(у всего здесь есть разные родители, включая столбец и форму, но это в основном то, что я делаю)

Ответы [ 2 ]

0 голосов
/ 27 марта 2020

Вы можете использовать flutter_form_blo c.

Каждое поле имеет метод addError, и вы можете вызывать его где угодно, в вашем случае это будет в методе onSubmitting после получение ответа от сервера.

class MyFormBloc extends FormBloc<String, String> {
  final email = TextFieldBloc();

  MyFormBloc() {
    addFieldBlocs(fieldBlocs: [email]);
  }

  @override
  void onSubmitting() async {
   // Awesome logic...
   username.addError('That email is taken. Try another.');
  }
}

Вы также можете иметь асинхронные валидаторы со временем отката

class MyFormBloc extends FormBloc<String, String> {
  final username = TextFieldBloc(
    asyncValidatorDebounceTime: Duration(milliseconds: 300),
  );

  MyFormBloc() {
    addFieldBlocs(fieldBlocs: [username]);

    username.addAsyncValidators([_checkUsername]);
  }

  Future<String> _checkUsername(String username) async {
    await Future.delayed(Duration(milliseconds: 500));
    if (username.toLowerCase() != 'flutter dev') {
      return 'That username is already taken';
    }
    return null;
  }
}

Вот небольшая демонстрационная программа, которую вы можете запустить, и учебник находится в форма бл c веб-сайт

pubspe c .yaml

dependencies:
  flutter_form_bloc: ^0.11.0

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';

void main() => runApp(App());

class App extends StatelessWidget {
  const App({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: SubmissionErrorToFieldForm(),
    );
  }
}

class SubmissionErrorToFieldFormBloc extends FormBloc<String, String> {
  final username = TextFieldBloc();

  SubmissionErrorToFieldFormBloc() {
    addFieldBlocs(
      fieldBlocs: [
        username,
      ],
    );
  }

  @override
  void onSubmitting() async {
    print(username.value);

    await Future<void>.delayed(Duration(milliseconds: 500));

    if (username.value.toLowerCase() == 'dev') {
      username.addError(
        'Cached - That username is taken. Try another.',
        isPermanent: true,
      );

      emitFailure(failureResponse: 'Cached error was added to username field.');
    } else {
      username.addError('That username is taken. Try another.');

      emitFailure(failureResponse: 'Error was added to username field.');
    }
  }
}

class SubmissionErrorToFieldForm extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => SubmissionErrorToFieldFormBloc(),
      child: Builder(
        builder: (context) {
          final formBloc =
              BlocProvider.of<SubmissionErrorToFieldFormBloc>(context);

          return Theme(
            data: Theme.of(context).copyWith(
              inputDecorationTheme: InputDecorationTheme(
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(20),
                ),
              ),
            ),
            child: Scaffold(
              appBar: AppBar(title: Text('Submission Error to Field')),
              body: FormBlocListener<SubmissionErrorToFieldFormBloc, String,
                  String>(
                onSubmitting: (context, state) {
                  LoadingDialog.show(context);
                },
                onSuccess: (context, state) {
                  LoadingDialog.hide(context);

                  Navigator.of(context).pushReplacement(
                      MaterialPageRoute(builder: (_) => SuccessScreen()));
                },
                onFailure: (context, state) {
                  LoadingDialog.hide(context);

                  Scaffold.of(context).showSnackBar(
                      SnackBar(content: Text(state.failureResponse)));
                },
                child: SingleChildScrollView(
                  physics: ClampingScrollPhysics(),
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Column(
                      children: <Widget>[
                        TextFieldBlocBuilder(
                          textFieldBloc: formBloc.username,
                          keyboardType: TextInputType.multiline,
                          decoration: InputDecoration(
                            labelText: 'Username',
                            prefixIcon: Icon(Icons.sentiment_very_satisfied),
                          ),
                        ),
                        Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: Text('"dev" will add a cached error'),
                        ),
                        RaisedButton(
                          onPressed: formBloc.submit,
                          child: Text('SUBMIT'),
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}

class LoadingDialog extends StatelessWidget {
  static void show(BuildContext context, {Key key}) => showDialog<void>(
        context: context,
        useRootNavigator: false,
        barrierDismissible: false,
        builder: (_) => LoadingDialog(key: key),
      ).then((_) => FocusScope.of(context).requestFocus(FocusNode()));

  static void hide(BuildContext context) => Navigator.pop(context);

  LoadingDialog({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async => false,
      child: Center(
        child: Card(
          child: Container(
            width: 80,
            height: 80,
            padding: EdgeInsets.all(12.0),
            child: CircularProgressIndicator(),
          ),
        ),
      ),
    );
  }
}

class SuccessScreen extends StatelessWidget {
  SuccessScreen({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Icon(Icons.tag_faces, size: 100),
            SizedBox(height: 10),
            Text(
              'Success',
              style: TextStyle(fontSize: 54, color: Colors.black),
              textAlign: TextAlign.center,
            ),
            SizedBox(height: 10),
            RaisedButton.icon(
              onPressed: () => Navigator.of(context).pushReplacement(
                  MaterialPageRoute(
                      builder: (_) => SubmissionErrorToFieldForm())),
              icon: Icon(Icons.replay),
              label: Text('AGAIN'),
            ),
          ],
        ),
      ),
    );
  }
}

0 голосов
/ 25 марта 2020

Почему бы вам не добавить серверный вызов внутри функции валидатора. Используйте валидатор внутри TextFormField, как указано ниже,

TextFormField( 
                validator: _validateEmail,
                  onSaved: (String value) {
                    email = value;
                  },
                ),


  String _validateEmail(String value) async {
//call to a server inside a validator function
        dynamic response = await someServerCall();
         String  _token="";
        if (response.token) {
            // Valid, use token

           setState((){
       _token = response.token
            });
            return null;
        } else {
            // INVALID, update error text somehow
            return "error";
        }

  }

, если валидатор получает значение NULL, тогда он не будет отображать никаких ошибок, но если он получит какую-либо строку, он будет отображать эту строку как ошибку. Теперь для кнопки


RaisedButtton(
    child: Text('SUBMIT'),
    onPressed: (){
       if (_formKey.currentState.validate()){} _formKey.currentState.save();}
)

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