I want to validate the user input in flutter - flutter

I'm trying to validate different user inputs, and i want to inform them which input is null
i tried to show an alert dialog whenever the user hit the submit button while an input is null, but then i got an error and it didn't open the page saying i have to fill the information before i even open the page. However i tried a something else but unfortunately it didn't work ether this is what i did.
TextFormField(
key: _formKey,
validator: (value) {
if (value == null) {
return 'please write a review';
} else if (DATA == null) {
return 'please select a category';
} else if (image == null) {
return 'please add an image';
} else if (tag == null) {
return 'please select sub category';
} else if (_descriptionController.text == null) {
return 'please select a location';
} else
return null;
},
maxLines: 20,
maxLength: 200,
controller: _descriptionController2,
decoration: InputDecoration(
contentPadding:
EdgeInsets.only(left: 10.0, top: 16.0),
hintText: "What do you think about the place?",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16.0)),
),
),
That's what i added to the button when it's pressed
onPressed: () {
bool valid = validation();
if (valid)
addData(image!, DATA!, lat, lng, _descriptionController2.text,
tag!, loggedInUser2!);
Navigator.pop(context);
},
lastly this is the validation method
bool validation() {
final form = _formKey.currentState;
if (form!.validate()) {
return true;
}
return false;
}
can any one help?

The validator(String? value) in widget TextFormField should validate ONLY for its text value. Other fields like Data, image... should be handled in another place.
I'm also working on validator for TextFormField and I realize that we shouldn't check null. Because when you first time navigate to this screen, the TextFormField will immediately show red error message below and it could make user uncomfortable. You should check null only when user press "Save/Comment" button and show popup/snack bar if the text is null/empty.
Also I got some tricks that you may interest:
Use extension (extension for String?) if you has some special cases can be used in future, like: valid email, valid password (8 character, special symbols)...
Don't forget to use function .trim() to remove white space on textEditingController.

i think is unnecessary for doing validation of DATA,image, etc for description field.
TextFormField will return String, it will always false when you do validation for DATA, image, etc.
just do like this:
Form(
key:_formKey,
child: Column(
children:[
TextFormField(
validator: (String? value) {
// runType value is String?
// which is it always false when you compare to image, or Data.
if (value == null) {
return 'please write a description';
else
return null;
},
controller: _descriptionController2,
),
then if you want to do validation for other data, i think you can make it manually.
if (DATA== null) {
//do something
}
...etc

Related

Validation in Flutter

I want to know how to make a validation in flutter where IF a TextFormField is filled then when you hit "send" then it doesn't let you go to the next section until all other textformfields must be filled, BUT if one of the TextFormFields is NOT filled when you hit send then it lets you pass to the next section. This is for a job form where a section is NOT mandatory, but only if one field has been filled then it becomes mandatory.
If you have a Form widget that contains all your FormFields (not only text-ones, but also dropdowns and such), the validation occurs on all your fields at once if you write your submit code this way:
final _formKey = GlobalKey<FormState>();
var tecUser = TextEditingController();
var tecPwd = TextEditingController();
[...]
//inside your widget tree...
Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: tecUser,
validator: (value) {
//your validation code: return null when value is right
//or a string if there's some error
},
decoration: InputDecoration(hintText: "username".tr()),
),
const SizedBox(height: 10),
TextFormField(
controller: tecPwd,
validator: (value) {
//your validation code: return null when value is right
//or a string if there's some error
},
obscureText: true,
),
const SizedBox(height: 10),
OutlinedButton(child: const Icon(Icons.login), onPressed: () => _submit()),
[...]
void _submit() async {
if (_formKey.currentState!.validate()) {
//all validators returned null, so you can proceed with your logic
} else {
//this happens when at least one of the validators returned a string
//by default, the error string returned by the validators will be displayed
//near each field, so you won't have to worry about handling the error cases and the else here won't even be necessary
}
}
This is an excerpt from an actual login form.
EDIT:
Ok, now I understand what you want to do. You have a group of fields that aren't mandatory, but they instead are mandatory if at least one of them has some value.
You need to assign a different TextEditingController to each of this fields: then, you need to assign a validator to each FormField that does something like this:
//insert all the TextEditingController in a list
var tecList = <TextEditingController>[tec1, tec2...]
//then, set a validator like this
(value) {
bool notMandatory = true;
for (var tec in tecList){
notMandatory = notMandatory && tec.text.isEmpty;
}
if (!notMandatory) return "Fill all fields";
//some other validation here
}
If you use a TextEditingController you can use the .text.isNotEmpty statement an write yourself a litte if function to check everything.
TextEditingController controller = TextEditingController();
if (controller.text.isNotEmpty) {
print("have fun with your new job")
}

fetch values from firebase Realtime database and compare them to form input using flutter

I'm working on flutter form validation, and I want to check if the input values match values that already exist in the database.
here's some of my code:
late DatabaseReference dbRef;
#override
void initState() {
super.initState();
dbRef = FirebaseDatabase.instance.ref().child('/Suppliers/');
}
Directionality(
textDirection: TextDirection.rtl,
child: TextFormField(
validator: (value) {
if (value == "") {
return "you must provide a username";
} else if (value != null && value.length < 6) {
return "username can't be shorter than 6";
} else if (dbRef
.orderByChild("username")
.equalTo(
_accountUserNameController.value) ==
_accountUserNameController.value) {
return "username already exists";
}
return null;
},
controller: _accountUserNameController,
style: TextStyle(
fontSize: 16.0,
),
decoration: InputDecoration(
labelText: "إسم المستخدم",
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.account_circle_rounded),
),
),
all of the validation I added works just fine except when I add this part
else if (dbRef
.orderByChild("username")
.equalTo(
_accountUserNameController.value) ==
_accountUserNameController.value) {
return "username already exists";
}
in attempt to check if the input value matches any value already stored in the database.
This code defines a query, but it doesn't load any data from the database yet:
dbRef
.orderByChild("username")
.equalTo(
_accountUserNameController.value)
To actually load the data you'll need to call get() on the query, and then check if the snapshot you get back exists.

controller and initial value in TextFormField do not work

I use TextFormField to get stored value from Firestore and display it to user in it's (edit profile) page,with ability to change field value.
My question is:
how can i enable initial value(to get stored value) and controller to pick entered value by the user.
I read the document and i know i can't use both together,but is there an idea to allow textfield to get stored value and edit it in the same time?
TextFormField(
controller: phone_controller,
keyboardType: TextInputType.number,
decoration: InputDecoration(
icon: const Icon(Icons.phone),
hintText: phone,
// labelText: phone,
floatingLabelBehavior: FloatingLabelBehavior.never,
),
validator: (value) {
String pattern = r'(^(?:[+0]9)?[0-9]{10,12}$)';
RegExp regExp = new RegExp(pattern);
if (value.isEmpty || !regExp.hasMatch(value) ) {
return 'Please enter valid phone number like 01001234567';
}
return null;
},
)
In your initState, you can set the initial value of the controller.
#override
void initState() {
super.initState();
phone_controller.text = 'phone_no';
}
phone_controller now has a default value;

Flutter : onSaved event not fired after selected item in MultiSelect

I am using Flutter Multiselect from official - flutter_multiselect: ^0.5.1
everything works fine , but onSaved() event not fired after selecting/deselecting and clicking the save button in MultiSelect Widget. i just wanna print the selected/deselected item in console.
Note : am also trying to get via change() event , its works only if we selecting the option, not works while deselcting.
help me to resolve this problem
Sample Code:
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
),
alignment: Alignment.center,
child: new MultiSelect(
maxLength: 1,
maxLengthText: "",
autovalidate: false,
dataSource: countries,
textField: 'country_name',
valueField: 'country_id',
hintText: "Select Your Country",
initialValue: countryID,
value: countryID,
required: true,
validator: (value) {
if (value == null) {
return 'Please Select Country';
}
},
filterable: true,
change: (values) {
if (values != null) {
setState(() {
countryID = values.cast<String>();
getStatesByCountry();
});
}
//this event emitted while selecting option from multiselect
//not works on deselecting option from multiselect
},
onSaved: (value) {
debugPrint("on save event");
print(value);
//always not emitting
},
),
)
Since I cannot see whole code, it's hard to tell but I would guess you don't save the whole form like this:
void _onFormSaved() {
final FormState form = _formKey.currentState;
form.save();
}
I would recommend to follow this original example
Hope it somehow help. Cheers
i dont know its a correct way, but in my case just cleaned a build and reinstalled packge will emit onchange event while removing items in multiselect,nothing else works me

Detect 'enter key' press in flutter

In my case i need to scan barcode and fetch product details. Normally barcode scanner devices emit enter key(keycode=13) event at end of scanning, But in flutter enter key is not same as Done so how can code to detect enter key pressed in my TextFormField widget?
if you are using TextField then you have to add onSubmitted in your text field to detect when user press Enter key. For my case, I changed Done in keyboard to TextInputAction.Search. It also works for TextInputAction.Done too. here is a sample code
TextField(
onSubmitted: (value){
//value is entered text after ENTER press
//you can also call any function here or make setState() to assign value to other variable
},
textInputAction: TextInputAction.search,
)
The solution above works, but I believe RawKeyboardListener is a more reliable and flexible solution. You just need to cover the text field with it and start to listen to keyboard events:
var focusNode = FocusNode();
RawKeyboardListener(
focusNode: focusNode,
onKey: (event) {
if (event.isKeyPressed(LogicalKeyboardKey.enter)) {
// Do something
}
},
child: TextField(controller: TextEditingController())
)
As a second option you can use onKey method of the FocusNoded and pass the node to your text field:
var focusNode = FocusNode(onKey: (node, event) {
if (event.isKeyPressed(LogicalKeyboardKey.enter)) {
// Do something
// Next 2 line needed If you don't want to update the text field with new line.
// node.unfocus();
// return true;
}
return false;
});
TextField(focusNode: focusNode, controller: TextEditingController())
In case someone is looking for the same solution (as Al Walid Ashik) but for TextFormField, just use the following:
TextFormField(
/// ...
onFieldSubmitted: (value) {
/// do some stuff here
},
),
TextFormField(
maxLines: null,
autovalidate: true,
validator: (value){
if(value.contains('\n')){
doFun(value);
}
}
)
When user press enter key new line create in text box. We check with that.
maxLine:null - to hide multiline
autovalidate:true -to automatically run validator fun
'\n' - new line ('\s'-whitespace,'\t'-tab.. etc)
In addition to the Sergey Yamshchikov's answer:
In case if it is a multiline TextField (maxLines: null) and you want to catch up the entered key and prevent passing it into the text field, you can use this approach:
RawKeyboardListener(
focusNode: FocusNode(onKey: (node, event) {
if (event.isKeyPressed(LogicalKeyboardKey.enter)) {
return KeyEventResult.handled; // prevent passing the event into the TextField
}
return KeyEventResult.ignored; // pass the event to the TextField
}),
onKey: (event) {
if (event.isKeyPressed(LogicalKeyboardKey.enter)) {
// Do something
}
},
child: TextField(controller: TextEditingController())
)
But, if you need to detect the keys combination, like ctrl+enter, then you can use CallbackShortcuts:
CallbackShortcuts(
bindings: {
const SingleActivator(LogicalKeyboardKey.enter, control: true): _doSomething(),
},
child: Focus(
autofocus: true,
child: TextField(controller: TextEditingController()),
),
);