0

I'm creating a form in Flutter and want the following functionality:

  1. If the user enters a URL, I want to ensure it is valid with a regular expression.
  2. If the user leaves the field blank, I do not want to return an error message.

The following Reg Exp validator performs this way when I perform these four steps:

  • If I hot reload and enter a valid URL, it accepts it.
  • If I change the input field to a new non-valid URL, it still accepts it.
  • If I hot reload and enter an invalid URL, it does not accept it.
  • If I change the URL to a valid URL, it still does not accept it.

It's as if it only runs the validator once and then any subsequent entry is not checked again. I do have a field that uses value.isEmpty as a validator and it does work as expected by checking the input each time I click my button with _formKey.currentState.save();

child: TextFormField(
              decoration: InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Related URL',
              ),
              textInputAction: TextInputAction.next,
              keyboardType: TextInputType.url,
              focusNode: _relatedUrlFocusNode,
              onFieldSubmitted: (_) {
                FocusScope.of(context).requestFocus(_notesFocusNode);
              },
              //this doesn't work
              validator: (String value) {
                if (RegExp(r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?")
                        .hasMatch(value)) {
                  return 'Please enter a valid URL';
                }
                return null;
              },
              onSaved: (String value) {
                relatedUrl = value;
              },
            ),

...other fields...

ElevatedButton(
            child: Text('ADD & ACTIVATE'),
            onPressed: () {
              if (!_formKey.currentState.validate()) {
                return;
              }
              ScaffoldMessenger.of(context)
                  .showSnackBar(SnackBar(content: Text('Processing Data')));
              _formKey.currentState.save();
            },
          )

How do I ensure it performs the validator each time I click submit?

1 Answer 1

3

You have two problems with your code:

  1. Your check should be if (!RegExp(r"...").hasMatch(value)) {} instead of if (RegExp(r"...").hasMatch(value)) {}
  2. Your Regular Expression is not correct. You may check here. (Dart RegExp are the same as Javascript RegExp)

Solution with validators package

Instead of a RegExp, you can use the validators package.

enter image description here

Full source code for easy copy-paste:

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:validators/validators.dart';

void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'URL Validation Demo',
      home: HomePage(),
    ),
  );
}

class HomePage extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final _formKey = useState(GlobalKey<FormState>());
    final _focusNode = useFocusNode();
    return Scaffold(
      body: Container(
        padding: EdgeInsets.all(8.0),
        alignment: Alignment.center,
        child: Form(
          key: _formKey.value,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              TextFormField(
                decoration: InputDecoration(
                  border: OutlineInputBorder(),
                  labelText: 'URL',
                ),
                validator: (value) {
                  if (!isURL(value)) {
                    return 'Please enter a valid URL';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 24.0),
              ElevatedButton(
                child: Text('VALIDATE'),
                onPressed: () {
                  if (_formKey.value.currentState.validate()) {
                    ScaffoldMessenger.of(context).showSnackBar(
                        SnackBar(content: Text('Processing Data')));
                  }
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Thierry! Good catch on the ! (not). I was playing around trying to fix it before I asked the question and had taken it out to inverse the logic (hence I was able to get an initial expected validation).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.