How to compare value within 2 TextFormField

Viewed 1360

I wish to validate if the values within 2 TextFormFields matches.

I could validate them individually.

But how could I capture both those values to validate by comparing?

import 'package:flutter/material.dart';

class RegisterForm extends StatefulWidget {
  @override
  _RegisterFormState createState() => _RegisterFormState();
}

class _RegisterFormState extends State<RegisterForm> {

  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Stack(
        children: [
          Container(
            padding: EdgeInsets.all(20),
            height: double.infinity,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  TextFormField(
                    decoration: InputDecoration(
                      hintText: 'Password'
                    ),
                    validator: (value) {
                      // I want to compare this value against the TextFormField below.
                      if(value.isEmpty){
                        return 'is empty';
                      }
                      return value;
                    },
                  ),
                  TextFormField(
                    decoration: InputDecoration(
                        hintText: 'Confirm Password'
                    ),
                    validator: (value) {
                      if(value.isEmpty){
                        return 'is empty';
                      }
                      return value;
                    },
                  ),
                  RaisedButton(
                    onPressed: (){
                      if (_formKey.currentState.validate()) {
                        print('ok');
                      } else {
                        print('not ok');
                      }
                    },
                  ),
                ],
              ),
          )
        ],
      ),
    );
  }
}

One possible solution as follows.

I could store them as values within _RegisterFormState and retrieve them within the validate blocks. But is there a cleaner way to achieve this?

class _RegisterFormState extends State<RegisterForm> {

    
    final _formKey = GlobalKey<FormState>();

    String password;
    String confirmPassword;

.....

    TextFormField(
        decoration: InputDecoration(
            hintText: 'Password'
        ),
        validator: (value) {
            // I want to compare this value against the TextFormField below.
            if(value.isEmpty){
                setState(() {
                    password = value;
                });
                performValidation(password, confirmPassword); // some custom validation method 
                return 'is empty';
            }
            return value;
        },
    ),

    ..... 
}

P.S: If there would be a better way to do it via a state management tool, I am using Provider. Not looking for Bloc solutions.

2 Answers

There are few steps I have performed to achieve this. You can refer that to achieve your goal.

  1. Create a stateful widget and return a InputBox from there

  2. add a property named as callback and set it's datatype as

    ValueSetter callback;

  3. assign this callback to onChanged Event of the input box

onChanged: (text) { widget.callback(text); },

  • Use your custom widget in the class where you want to use the input box

  • while using your widget pass a callback to it

                InputWithLabel(
    
                   callback: (value) {
    
                       password = value;
    
                     },
                 ),
                 InputWithLabel(
    
                   callback: (value) {
    
                         confirmPassword = value;
    
                   },
                 ),
    
  • and at last, we have to compare those values, you can bind a key to your form add use it in saved event of it. You can wrap it in Button's callback

    if (InputValidation.validatePasswordandConfirm(password, cpassword)) {
    // your after form code
    }
    

To have it a real time comparison mark one of the input's callback in setState(){} and create a new property in your Custom Text Widget named as compareTxt;

and on validator check for compare text and return the error message

validator: (text) {
          if (widget.comaparetext != text) {
            return 'Password does not match';
          }

I had the same problem but I was using custom TextFormField widgets. So this is how I achieved it:

Problem:
I had two TextFormField widgets in a Form and I wanted to compare the values of those two TextFormWidgets, to check whether the value of one filed is greater then the other.

Solution:
I defined two controllers globally, because the TextFormWidgets were in a separate class.

final _startingRollNumberController = TextEditingController();
final _endingRollNumberController = TextEditingController();

Passed these controllers to the instances of TextFormField in the Form class.

CustomTextField('Starting R#', _startingRollNumberController),
CustomTextField('Ending R#', _endingRollNumberController),

And validated them in the TextFormField class.

class CustomTextField extends StatelessWidget {
  // *===== CustomTextField class =====* //
  CustomTextField(this._hintText, this._controller);

  final String _hintText;
  final _controller;
  @override
  Widget build(BuildContext context) {
    return TextFormField(
      validator: (value) {
        final _startingRollNumber = _startingRollNumberController.text;
        final _endingRollNumber = _endingRollNumberController.text;
        // Starting roll-number needs to be smaller then the ending roll-number.
        if (!_startingRollNumber.isEmpty && !_endingRollNumber.isEmpty) {
          if (int.parse(_startingRollNumber) >= int.parse(_endingRollNumber)) {
            return 'starting roll number must be smaller.';
          }
        }
      },
    );
  }
}

This may not be the best approach but this is how I achieved it. There is also, this flutter_form_builder package which can be used to achieve this easily using the form key.
A related question: Flutter: Best way to get all values in a form

Related