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
}
}
Comments
-
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 about 2 yearsAdd validation before send any thing to Firestore if you can, What I mean from UI.
-
user229044 about 2 yearsPlease reduce your code to a minimal complete example, see minimal reproducible example.
-
-
Tushar Rai about 2 yearsnone of the textfield validator is working.