TimeToCode
TimeToCode

Reputation: 1838

how to display validation error message out from the textfield in flutter

enter image description here

how to display "this field is required" message out from the box. this message will display on button click.

here is the textfield code

-------------------EDITED QUESTION-------------------

Here is your code and modified it by adding one more textformfield

import 'package:flutter/material.dart';



class ExperimentApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        scaffoldBackgroundColor: Colors.white,
      ),
      home: ExperimentHome(),
    );
  }
}

class ExperimentHome extends StatelessWidget {
  final GlobalKey<FormFieldState> formFieldKey = GlobalKey();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Row(
          children: [
            Expanded(
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: RoundedInputField(
                  formFieldKey: formFieldKey,
                  icon: Icons.edit,
                  labelText: 'Label',
                  validate: (value) {
                    if (value == null || value.isEmpty) {
                      return "This field is required";
                    }
                    return null;
                  },
                ),
              ),
            ),
//this is one more TextFormField
            RoundedInputField(
                  formFieldKey: formFieldKey,
                  icon: Icons.edit,
                  labelText: 'Label1',
                  validate: (value) {
                    if (value == null || value.isEmpty) {
                      return "This field is required";
                    }
                    return null;
                  },
                ),
            
            IconButton(
              icon: Icon(Icons.check),
              onPressed: () {
                // you need to call `.validate` to actually validate the field.
                formFieldKey.currentState.validate();
              },
            )
          ],
        ),
      ),
    );
  }
}

class RoundedInputField extends StatelessWidget {
  final IconData icon;
  final FormFieldValidator<String> validate;
  final String labelText;

  final GlobalKey<FormFieldState> formFieldKey;

  // (before flutter 2.0) drop `required`
  const RoundedInputField({
    Key key,
    @required this.formFieldKey,
    
    
    @required this.labelText,
    @required this.icon,
    @required this.validate,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      key: formFieldKey,
      validator: validate,
      decoration: InputDecoration(
        icon: Icon(
          icon,
          color: Colors.blue,
        ),
        labelText: labelText,
      ),
    );
  }
}

this is error

════════ Exception caught by rendering library ═════════════════════════════════
RenderBox was not laid out: RenderTransform#3842d NEEDS-LAYOUT NEEDS-PAINT
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1940 pos 12: 'hasSize'

The relevant error-causing widget was
TextFormField-[LabeledGlobalKey<FormFieldState<dynamic>>#a4b32]
lib\abc.dart:87
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by widgets library ═══════════════════════════════════
Multiple widgets used the same GlobalKey.
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by widgets library ═══════════════════════════════════
Multiple widgets used the same GlobalKey.
════════════════════════════════════════════════════════════════════════════════

and it shows a plain white screen as output

Upvotes: 3

Views: 22705

Answers (3)

TimeToCode
TimeToCode

Reputation: 1838

Finally I got the solution! Here it works perfectly.

TextFormField widget:

import 'package:attendance_system_app/text_field_container.dart';
import 'package:flutter/material.dart';

class RoundedInputField extends StatelessWidget {
  final String hintText;
  final IconData icon;
  final ValueChanged<String> onChanged;
  final TextEditingController controller;
  final double fontsize;
  final FormFieldValidator<String> validate;
  final String errortext;
  final String labelText;
  final GlobalKey<FormFieldState> formFieldKey;
  //final  onsaved;

  const RoundedInputField(
      {Key key,
      this.labelText,
      this.formFieldKey,
      this.errortext,
      this.hintText,
      this.icon,
      this.validate,
      this.onChanged,
      this.controller,
      this.fontsize})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      decoration: InputDecoration(
        labelText: labelText,
        fillColor: Colors.blue[50],
        border: OutlineInputBorder(
          borderRadius: BorderRadius.circular(29.0),
        ),
      ),
      validator: validate,
      controller: controller,
      maxLength: 5,
    );
  }
}

And here you can call the widget.

class JafPersonals extends StatefulWidget {
  @override
  _JafPersonalState createState() => _JafPersonalState();
}

class _JafPersonalState extends State<JafPersonals> {
  TextEditingController _applicantName = new TextEditingController();
  TextEditingController _fatherName = new TextEditingController();
  final GlobalKey<FormState> _formkey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      drawer: new AdminDrawerCode(),
      appBar: AppBar(
        title: Image.asset(
          "assets/image/company_logo.png",
          height: 140,
          width: 280,
        ),

        //automaticallyImplyLeading: false,
        backgroundColor: Colors.white,
        iconTheme: IconThemeData(color: Colors.blue, size: 20),
        //leading: new Icon(Icons.menu,color: Colors.blue,),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.notifications, color: Colors.blue, size: 26),
            onPressed: () {
              // do something
            },
          )
        ],
      ),
      body: Form(
        key: _formkey,
        child: ListView(
          padding: EdgeInsets.all(16),
          children: [
            Text(" Employee Bio Data",
                style: TextStyle(
                    fontSize: 30,
                    fontWeight: FontWeight.bold,
                    color: Colors.blue[900])),
            SizedBox(
              height: 20,
            ),
            Text(" Personal data",
                style: TextStyle(
                    fontSize: 25,
                    fontWeight: FontWeight.bold,
                    color: Colors.blue[900])),
            SizedBox(
              height: 20,
            ),
            RoundedInputField(
              labelText: 'Applicant name',
              controller: _applicantName,
              validate: (value) {
                if (value.length < 4) {
                  return 'Enter at least 4 characters';
                } else {
                  return null;
                }
              },
            ),
            SizedBox(height: 10),
            RoundedInputField(
              labelText: 'Father name',
              controller: _applicantName,
              validate: (value) {
                if (value.length < 4) {
                  return 'Enter at least 4 characters';
                } else {
                  return null;
                }
              },
            ),
            RoundedButton(
              text: 'Submit',
              press: () {
                final isvalid = _formkey.currentState.validate();
                if (isvalid) {
                  _formkey.currentState.save();
                  Navigator.push(context,
                      MaterialPageRoute(builder: (context) => JafFamily()));
                }
              },
            ),
          ],
        ),
      ),
    );
  }
}

Upvotes: 0

VLXU
VLXU

Reputation: 729

You need to use a GlobalKey<FormFieldState> and actually call .validate on the field to validate the field.

When you call .validate, the TextFormField will validate the field and show the error message if the validate method returns a String.

More on TextFormField: https://api.flutter.dev/flutter/material/TextFormField-class.html

Code Sample (there are some syntatic differences as you seem to be using an older version of dart):

import 'package:flutter/material.dart';

void main() async {
  runApp(ExperimentApp());
}

class ExperimentApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        scaffoldBackgroundColor: Colors.white,
      ),
      home: ExperimentHome(),
    );
  }
}

class ExperimentHome extends StatelessWidget {
  final GlobalKey<FormFieldState> formFieldKey = GlobalKey();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Row(
          children: [
            Expanded(
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: RoundedInputField(
                  formFieldKey: formFieldKey,
                  icon: Icons.edit,
                  labelText: 'Label',
                  validate: (value) {
                    if (value == null || value.isEmpty) {
                      return "This field is required";
                    }
                    return null;
                  },
                ),
              ),
            ),
            IconButton(
              icon: Icon(Icons.check),
              onPressed: () {
                // you need to call `.validate` to actually validate the field.
                formFieldKey.currentState!.validate();
              },
            )
          ],
        ),
      ),
    );
  }
}

class RoundedInputField extends StatelessWidget {
  final IconData icon;
  final FormFieldValidator<String> validate;
  final String labelText;

  final GlobalKey<FormFieldState> formFieldKey;

  // (before flutter 2.0) drop `required`
  const RoundedInputField({
    Key? key,
    required this.formFieldKey,
    required this.labelText,
    required this.icon,
    required this.validate,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      key: formFieldKey,
      validator: validate,
      decoration: InputDecoration(
        icon: Icon(
          icon,
          color: Colors.blue,
        ),
        labelText: labelText,
      ),
    );
  }
}

Upvotes: 3

Why_So_Ezz
Why_So_Ezz

Reputation: 158

This will work for you.


 decoration: InputDecoration(
                                      focusedBorder: UnderlineInputBorder(
                                        borderSide: BorderSide(
                                            color: Colors.anyColor,
                                            width: 2),
                                      ),
                                      focusedErrorBorder: UnderlineInputBorder(
                                        borderSide: BorderSide(
                                            color: Colors.anyColor,
                                            width: 2),
                                      ),
                                      errorBorder:
                                          (value.isEmpty)
                                              ? UnderlineInputBorder(
                                                  borderSide: BorderSide(
                                                      color: Colors.anyColor),
                                                )
                                              : InputBorder.none,
                                      errorText:
                                          (value.isEmpty)
                                              ? "Minimum 3 characters required"
                                              : null,
                                      errorStyle: anyTextStyle(),
                                      hintText: "Name",
                                      hintStyle:
                                          anyTextStyle()),

Upvotes: 1

Related Questions