How to validate textfield when posting to firestore in flutter?

161

It appears that the problem is a simple mistake with your control flow in the following code (see // comment):

 void _submitData() async {
    final _isValid = _formKey.currentState!.validate();
    FocusScope.of(context).unfocus();
    if (_isValid) {
      _formKey.currentState!.save();
    } // <----- this should not be here!
    try {
      setState(() {
        _isLoading = true;
      });
      final User? user = _auth.currentUser;
      final _uid = user!.uid;
      final orderId = ModalRoute.of(context)!.settings.arguments as String;
      FirebaseFirestore.instance
          .collection('orders')
          .doc(orderId)
          .set({
        'userId': _uid,
        'name': _name,
        'phoneNumber': _phoneNumber,
        'addressType': _addressType,
        'address': _fullAddress,
        'area': _area,
        'city': _city,
        'deliverySlot': _deliverySlotValue,
      }, SetOptions(merge: true));

    } catch (error) {
      _globalMethods.authDialog(context, error.toString());
    } finally {
      setState(() {
        _isLoading = false;
      });
      Navigator.of(context).pushReplacementNamed(OrderSuccess.routeName);
    }
  }

As you can see, even if the user input is not valid, you still continue to upload the results to Firebase anyway.

Try correcting like this:

void _submitData() async {
    final _isValid = _formKey.currentState!.validate();
    FocusScope.of(context).unfocus();
    if (_isValid) {
      _formKey.currentState!.save();
      try {
        setState(() {
          _isLoading = true;
        });
        final User? user = _auth.currentUser;
        final _uid = user!.uid;
        final orderId = ModalRoute.of(context)!.settings.arguments as String;
        FirebaseFirestore.instance.collection('orders').doc(orderId).set({
          'userId': _uid,
          'name': _name,
          'phoneNumber': _phoneNumber,
          'addressType': _addressType,
          'address': _fullAddress,
          'area': _area,
          'city': _city,
          'deliverySlot': _deliverySlotValue,
        }, SetOptions(merge: true));
      } catch (error) {
        _globalMethods.authDialog(context, error.toString());
      } finally {
        setState(() {
          _isLoading = false;
        });
        Navigator.of(context).pushReplacementNamed(OrderSuccess.routeName);
      }
    } else {
      // do nothing
    }
  }
Share:
161
Tushar Rai
Author by

Tushar Rai

Dart, Flutter

Updated on November 25, 2022

Comments

  • Tushar Rai
    Tushar Rai over 1 year

    I have added validator in TextField but validator is not working while submitting data. Save button saves the data with null value.

    import 'package:cloud_firestore/cloud_firestore.dart';
    import '../../screens/orders/order_success.dart';
    import '../../services/global_methods.dart';
    import 'package:firebase_auth/firebase_auth.dart';
    import 'package:flutter/material.dart';
    
    class PlaceOrder extends StatefulWidget {
      static const routeName = '/place-order';
    
      const PlaceOrder({Key? key}) : super(key: key);
    
      @override
      State<PlaceOrder> createState() => _PlaceOrderState();
    }
    
    class _PlaceOrderState extends State<PlaceOrder> {
    
      final _formKey = GlobalKey<FormState>();
      String? _name;
      int? _phoneNumber;
      String? _fullAddress;
      String? _area;
      String? _city;
      String? _addressType;
      final TextEditingController _addressController = TextEditingController();
      String? _addressValue;
      String? _deliverySlotValue;
      final FirebaseAuth _auth = FirebaseAuth.instance;
      late bool _isLoading = false;
      final GlobalMethods _globalMethods = GlobalMethods();
      final FocusNode _numberFocusNode = FocusNode();
    
      @override
      void initState() {
        setState(() {
          _isLoading = false;
        });
        super.initState();
      }
    
      @override
      void dispose() {
        _numberFocusNode.dispose();
        super.dispose();
      }
    
      void _submitData() async {
        final _isValid = _formKey.currentState!.validate();
        FocusScope.of(context).unfocus();
        if (_isValid) {
          _formKey.currentState!.save();
        }
        try {
          setState(() {
            _isLoading = true;
          });
          final User? user = _auth.currentUser;
          final _uid = user!.uid;
          final orderId = ModalRoute.of(context)!.settings.arguments as String;
          FirebaseFirestore.instance
              .collection('orders')
              .doc(orderId)
              .set({
            'userId': _uid,
            'name': _name,
            'phoneNumber': _phoneNumber,
            'addressType': _addressType,
            'address': _fullAddress,
            'area': _area,
            'city': _city,
            'deliverySlot': _deliverySlotValue,
          }, SetOptions(merge: true));
    
        } catch (error) {
          _globalMethods.authDialog(context, error.toString());
        } finally {
          setState(() {
            _isLoading = false;
          });
          Navigator.of(context).pushReplacementNamed(OrderSuccess.routeName);
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Add new address'),
          ),
          body: Form(
            key: _formKey,
            child: Padding(
              padding: const EdgeInsets.all(16.0),
              child: SingleChildScrollView(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: [
                    Row(
                      children: [
                        DropdownButton<String>(
                          items: const [
                            DropdownMenuItem<String>(
                              child: Text('Home'),
                              value: 'Home',
                            ),
                            DropdownMenuItem<String>(
                              child: Text('Office'),
                              value: 'Office',
                            ),
                            DropdownMenuItem<String>(
                              child: Text('Other'),
                              value: 'Other',
                            ),
                          ],
                          onChanged: (value) {
                            setState(() {
                              _addressValue = value.toString();
                              _addressController.text = value.toString();
    
                              print(_addressType);
                            });
                          },
                          hint: const Text('Select address type'),
                          value: _addressValue,
                        ),
                        const SizedBox(
                          width: 10,
                        ),
                        Expanded(
                          child: TextFormField(
                            key: const ValueKey('addressType'),
                            controller: _addressController,
                            validator: (val) {
                              if (val!.isEmpty) {
                                return 'Please select address type';
                              }
                              return null;
                            },
                            decoration: const InputDecoration(
                              labelText: 'Select your address type',
                            ),
                            onSaved: (val) {
                              _addressType = val.toString();
                            },
                          ),
                        ),
                      ],
                    ),
                    TextFormField(
                      onSaved: (value) {
                        _name = value!;
                      },
                      textInputAction: TextInputAction.next,
                      key: const ValueKey('name'),
                      validator: (value) {
                        if (value!.isEmpty) {
                          return 'Please enter your name';
                        }
                        return null;
                      },
                      decoration: InputDecoration(
                        labelText: 'Name',
                        filled: true,
                        border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(12),
                        ),
                        prefixIcon: const Icon(Icons.location_city),
                      ),
                    ),
                    const SizedBox(height: 8),
                    TextFormField(
                      onSaved: (value) {
                        _fullAddress = value!;
                      },
                      textInputAction: TextInputAction.next,
                      key: const ValueKey('streetAddress'),
                      validator: (value) {
                        if (value!.isEmpty) {
                          return 'Please enter your address';
                        }
                        return null;
                      },
                      decoration: InputDecoration(
                        labelText: 'Address',
                        filled: true,
                        border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(12),
                        ),
                        prefixIcon: const Icon(Icons.location_city),
                      ),
                    ),
                    const SizedBox(height: 8),
                    TextFormField(
                      onSaved: (value) {
                        _area = value!;
                      },
                      textInputAction: TextInputAction.next,
                      key: const ValueKey('area'),
                      validator: (value) {
                        if (value!.isEmpty) {
                          return 'Please enter your area';
                        }
                        return null;
                      },
                      decoration: InputDecoration(
                        labelText: 'Area',
                        filled: true,
                        border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(12),
                        ),
                        prefixIcon: const Icon(Icons.location_city),
                      ),
                    ),
                    const SizedBox(height: 8),
                    TextFormField(
                      onSaved: (value) {
                        _city = value!;
                      },
                      textInputAction: TextInputAction.next,
                      key: const ValueKey('city'),
                      validator: (value) {
                        if (value!.isEmpty) {
                          return 'Please enter your city';
                        }
                        return null;
                      },
                      decoration: InputDecoration(
                        labelText: 'City',
                        filled: true,
                        border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(12),
                        ),
                        prefixIcon: const Icon(Icons.location_city),
                      ),
                    ),
                    const SizedBox(height: 8),
                    TextFormField(
                      onSaved: (value) {
                        _phoneNumber = int.parse(value!);
                      },
                      textInputAction: TextInputAction.next,
                      // keyboardType: TextInputType.emailAddress,
                      onEditingComplete: () =>
                          FocusScope.of(context).requestFocus(_numberFocusNode),
                      key: const ValueKey('number'),
                      validator: (value) {
                        if (value!.length < 10) {
                          return 'Phone number must be 10 units';
                        }
                        return null;
                      },
                      decoration: InputDecoration(
                        labelText: 'Phone Number',
                        filled: true,
                        border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(12),
                        ),
                        prefixIcon: const Icon(Icons.phone),
                      ),
                    ),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        DropdownButton<String>(
                          items: const [
                            DropdownMenuItem<String>(
                              child: Text('11:00am to 1:00pm'),
                              value: '11:00am to 1:00pm',
                            ),
                            DropdownMenuItem<String>(
                              child: Text('1:00pm to 3:00pm'),
                              value: '1:00pm to 3:00pm',
                            ),
                            DropdownMenuItem<String>(
                              child: Text('3:00pm to 5:00pm'),
                              value: '3:00pm to 5:pm',
                            ),
                            DropdownMenuItem<String>(
                              child: Text('5:00pm to 7:00pm'),
                              value: '5:00pm to 7:00pm',
                            ),
                            DropdownMenuItem<String>(
                              child: Text('7:00pm to 9:pm'),
                              value: '7:00pm to 9:pm',
                            ),
                          ],
                          onChanged: (value) {
                            setState(() {
                              _deliverySlotValue = value.toString();
                            });
                          },
                          hint: const Text('Select Delivery Slot'),
                          value: _deliverySlotValue,
                        ),
                      ],
                    ),
                    Padding(
                      padding: const EdgeInsets.all(48.0),
                      child: SizedBox(
                        child: ElevatedButton(
                          onPressed: _submitData,
                          child: _isLoading
                              ? const CircularProgressIndicator()
                              : const Text(
                            'S U B M I T',
                            style: TextStyle(color: Colors.white),
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        );
      }
     }
    
    • Mouaz M Shahmeh
      Mouaz M Shahmeh about 2 years
      Add validation before send any thing to Firestore if you can, What I mean from UI.
    • user229044
      user229044 about 2 years
      Please reduce your code to a minimal complete example, see minimal reproducible example.
  • Tushar Rai
    Tushar Rai about 2 years
    none of the textfield validator is working.