Manually setting Flutter Validation Error Manually setting Flutter Validation Error dart dart

Manually setting Flutter Validation Error


I suppose, I could think of a solution, but I think it's kind of ugly.I could have an "error" variable, that is set when the request fails.I would then call formState.validate() a second time, in there: check the error variable and return it if it's not null.


You can use flutter_form_bloc and use addError method of TextFieldBloc.

usernameField.addError('That username is taken. Try another.');

Keep in mind that you can also use asynchronous validators.

This is a complete example:

dependencies:  flutter:    sdk: flutter  flutter_bloc: ^0.21.0  form_bloc: ^0.5.0  flutter_form_bloc: ^0.4.1+1
import 'package:flutter/material.dart';import 'package:flutter_bloc/flutter_bloc.dart';import 'package:flutter_form_bloc/flutter_form_bloc.dart';import 'package:form_bloc/form_bloc.dart';void main() {  runApp(MaterialApp(home: SignUpForm()));}class SignUpFormBloc extends FormBloc<String, String> {  final usernameField = TextFieldBloc();  final passwordField =      TextFieldBloc(validators: [Validators.passwordMin6Chars]);  @override  List<FieldBloc> get fieldBlocs => [usernameField, passwordField];  @override  Stream<FormBlocState<String, String>> onSubmitting() async* {    // Form logic...    try {      await _signUp(        throwException: true,        username: usernameField.value,        password: passwordField.value,      );      yield currentState.toSuccess();    } catch (e) {      // When get the error from the backend you can      // add the error to the field:      usernameField.addError('That username is taken. Try another.');      yield currentState          .toFailure('The error was added to the username field.');    }  }  Future<void> _signUp({    @required bool throwException,    @required String username,    @required String password,  }) async {    print(username);    print(password);    await Future<void>.delayed(Duration(seconds: 2));    if (throwException) throw Exception();  }}class SignUpForm extends StatelessWidget {  @override  Widget build(BuildContext context) {    return BlocProvider<SignUpFormBloc>(      builder: (context) => SignUpFormBloc(),      child: Builder(        builder: (context) {          final formBloc = BlocProvider.of<SignUpFormBloc>(context);          return Scaffold(            appBar: AppBar(title: Text('Sign Up Form')),            body: FormBlocListener<SignUpFormBloc, String, String>(              onSubmitting: (context, state) {                // Show the progress dialog                showDialog(                  context: context,                  barrierDismissible: false,                  builder: (_) => WillPopScope(                    onWillPop: () async => false,                    child: Center(                      child: Card(                        child: Container(                          width: 80,                          height: 80,                          padding: EdgeInsets.all(12.0),                          child: CircularProgressIndicator(),                        ),                      ),                    ),                  ),                );              },              onSuccess: (context, state) {                // Hide the progress dialog                Navigator.of(context).pop();                // Navigate to success screen                Navigator.of(context).pushReplacement(                    MaterialPageRoute(builder: (_) => SuccessScreen()));              },              onFailure: (context, state) {                // Hide the progress dialog                Navigator.of(context).pop();                // Show snackbar with the error                Scaffold.of(context).showSnackBar(                  SnackBar(                    content: Text(state.failureResponse),                    backgroundColor: Colors.red[300],                  ),                );              },              child: ListView(                children: <Widget>[                  TextFieldBlocBuilder(                    textFieldBloc: formBloc.usernameField,                    decoration: InputDecoration(labelText: 'Username'),                  ),                  TextFieldBlocBuilder(                    textFieldBloc: formBloc.passwordField,                    decoration: InputDecoration(labelText: 'Password'),                  ),                  Padding(                    padding: const EdgeInsets.all(8.0),                    child: RaisedButton(                      onPressed: formBloc.submit,                      child: Center(child: Text('SUBMIT')),                    ),                  ),                ],              ),            ),          );        },      ),    );  }}class SuccessScreen extends StatelessWidget {  const SuccessScreen({Key key}) : super(key: key);  @override  Widget build(BuildContext context) {    return Scaffold(      backgroundColor: Colors.green[300],      body: Center(        child: SingleChildScrollView(          child: Column(            children: <Widget>[              Icon(                Icons.sentiment_satisfied,                size: 100,              ),              RaisedButton(                color: Colors.green[100],                child: Text('Sign out'),                onPressed: () => Navigator.of(context).pushReplacement(                    MaterialPageRoute(builder: (_) => SignUpForm())),              )            ],          ),        ),      ),    );  }}


You can use controller in TextFormField to validate form and display server error.

TextEditingController controllerPassword = new TextEditingController();Widget build(BuildContext context) {...  TextFormField(    onFieldSubmitted: (value) => _signIn(),    validator: (input) {      if (input.length < 6)        return 'Your password is too short';      return null;    },    onSaved: (input) => _password = input,    decoration: InputDecoration(      labelText: 'Password',    ),    obscureText: true,    controller: controllerPassword,  )...}Future<void> _signIn() async {  final formState = _formKey.currentState;  if (!formState.validate()) return;  formState.save();  try {    ... // do fancy request stuff  } catch (e) {    // this is where I want to set the "validation" error     setState(() {        controllerPassword.text = "Server Error"     }));  }}

For more reference: Flutter Form Validation