Home > Software design >  How to validate Flutter Text Form Field before updating Firestore database
How to validate Flutter Text Form Field before updating Firestore database

Time:02-28

I'm having trouble validating a text form field before data is uploaded to the Firestore database. There aren't any issues with Firestore, only with the way I have written my code.

The validation is to check that the text field is not null or empty, the same as the Flutter codelab. If the text field is empty an error message should appear and the user should remain on the same page until the text field has data. Once the text field is valid the data should be saved to Firestore, a snackbar confirmation should appear on the page and the user should be navigated to a different page.

With the code I have written the user navigates to the new page and the snackbar message appears even if all of the text form fields are empty (invalid). I tried to remove extra code to make it easier to view the code. In my form I have three text fields with identical validation rules. Any help would be greatly appreciated. Thanks.

My Text Form Field:

TextFormField(
labelText: 'Trivia Game Url',
onChanged: (val) {
triviaGameImageURL = val as String;
},
controller: _triviaGameImageURLController,
validator: _triviaGameImageURLValidator,
),

Validation method:

 String? _triviaGameImageURLValidator(value) {
      if (value == null || value.isEmpty) {
        return 'Image Url is required';
      }
      return null;
    }

Method to update Firestore when user taps button:

Future<void> createFirestoreTriviaGame() async {
  final form = _formKey.currentState;
  if (form!.validate()) {
    setState(() {
      _isLoading = true;
    });
    String triviaGameID = const Uuid().v4();
    Map<String, dynamic> triviaGameMap = {
      FirebaseString.triviaGameID: triviaGameID,
      FirebaseString.triviaGameImageURL: triviaGameImageURL,

    };
    await firestoreMethods
        .addTriviaGameData(
      triviaGameData: triviaGameMap,
      triviaGameID: triviaGameID,
    )
        .then((value) {
      setState(() {
        _isLoading = false;
      });
    });
  }
  ScaffoldMessenger.of(context).showSnackBar(
    const SnackBar(
      content: Text(SnackBarString.triviaGameCreated),
    ),
  );
  Timer(const Duration(seconds: 2), () {
    Navigator.pushReplacement(
      context,
      MaterialPageRoute(
        builder: (context) => const AddTriviaGamePage(),
      ),
    );
  });
}

CodePudding user response:

In your code the snackbar and navigation is outside the if (form!.validate()) block. Simply extend this block to include everything that you want to execute only on a valid form, and display a message if validation fails.

The snackbar and navigation should happen on successful save only, after Firestore async call completes. I recommend not to mix async/await with .then, these are the same. So simple await Firestore method, put this in a try/catch block and execute snackbar and navigation on success.

CodePudding user response:

You need to wrap the textfield in a form widget and assign a form key to the form widget

 final GlobalKey<FormState> formKey = GlobalKey<FormState>();
Form(
      key: formKey,
      child: Column(
        children: [
... your text fields

// validate 
    if (formKey.currentState!.validate()) {
  • Related