I am developing a flutter e_commerce app, and in registration, the username should be unique, for that, we have an endpoint in API to check either the username is taken or not, my problem is with validation, I need to validate after user interaction, in flutter we have auto validate mode, but there is only(always, onUserInteraction) options, and I need the validation right after user interaction
The textFormField of the username input is
TextFormField(
cursorColor: Theme.of(context).primaryColor,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: InputDecoration(
suffixIcon: SuffixIcon(),
labelText:
'Choose suitable name and relevant to your products',
hintText: 'SweetCandies',
labelStyle: TextStyle(color: Colors.black),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
),
),
),
validator: (value) {
if(value!.isNotEmpty){}
Provider.of<Store>(context).usernameExistence(value, 'no');
if(Provider.of<Store>(context).nameExistence){
return 'The Chosen name is already taken';
}
if (value.isEmpty) {
return 'Required';
}
},
onSaved: (value) {
Provider.of<Store>(context, listen: false)
.storeInformation['name'] = value!;
},
)
is there any way to active validator after user interaction???
You can attach a focusNode to TextField so whenever focus changes you can make an api call and validate the text
add this code and initState to your code
TextEditingController controller = TextEditingController();
FocusNode focusNode;
bool _hasInputError;
String errorText = "";
String text;
#override
void initState() {
super.initState();
focusNode = new FocusNode();
focusNode.addListener(() {
if (!focusNode.hasFocus) {
setState(() {
if(Provider.of<Store>(context).nameExistence){// your condition
_hasInputErro = true;
errorText = 'The Chosen name is already taken';
}// <-- else if condition ...
else{
_hasInputErro = false;
}
});
}
});
}
in TextFormField :
TextFormField(
focusNode: focusNode,// <-- add focusNode here
controller: controller,// <-- add controller here
cursorColor: Theme.of(context).primaryColor,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: InputDecoration(
errorText: _hasInputError ? errorText : null, // <-- add this line to show errors
suffixIcon: SuffixIcon(),
labelText:
'Choose suitable name and relevant to your products',
hintText: 'SweetCandies',
labelStyle: TextStyle(color: Colors.black),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
),
),
),
// validator: ... , // <-- comment validator
onSaved: (value) {
Provider.of<Store>(context, listen: false)
.storeInformation['name'] = value!;
},
)
Related
This question already has answers here:
How to show/hide password in TextFormField?
(14 answers)
Closed 3 months ago.
I want to add eye to password field in flutter project
this is my code:
TextFormField(
decoration: const InputDecoration(
label: Text('PASSWORD'),
),
keyboardType: TextInputType.visiblePassword,
obscureText: true,
validator: (val) {
if (val!.length < 6) {
return "Please enter at least 6 characters";
}
return null;
},
onSaved: (val) => data['password'] = val!,
),
You can use this custom widget:
class CustomInput extends StatefulWidget {
final String? label;
final TextInputType? keyboardType;
final String? Function(String?)? validator;
final Function(String?)? onSaved;
final bool obscureText;
const CustomInput(
{Key? key,
this.label,
this.keyboardType,
this.validator,
this.onSaved,
this.obscureText = false})
: super(key: key);
#override
State<CustomInput> createState() => _CustomInputState();
}
class _CustomInputState extends State<CustomInput> {
bool showPassword = false;
#override
Widget build(BuildContext context) {
return TextFormField(
decoration: InputDecoration(
label: Text(widget.label ?? ''),
suffixIcon: InkWell(
onTap: () {
setState(() {
showPassword = !showPassword;
});
},
child: Icon(showPassword
? Icons.remove_red_eye
: Icons.remove_red_eye_outlined),
)),
keyboardType: widget.keyboardType,
obscureText: showPassword ? false : widget.obscureText,
validator: widget.validator,
onSaved: widget.onSaved,
);
}
}
and use it like this:
CustomInput(
label: 'PASSWORD',
keyboardType: TextInputType.visiblePassword,
onSaved: (val) => data['password'] = val!,
validator: (val) {
if (val!.length < 6) {
return "Please enter at least 6 characters";
}
return null;
},
obscureText: true,
)
Add a suffixIcon in the decoration part :
decoration: InputDecoration(
suffixIcon: IconButton(
onPressed: showHideText(),
icon: Icon(Icons.yourIcon),
),
),
Create a boolean variable which will hold the status of password of being shown or not.
bool hidePassword=true;
Now, add this TextFormField with obscureText property.
TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
obscureText: hidePassword,
decoration: InputDecoration(
prefixIcon: const Icon(
Icons.password,
),
suffixIcon: IconButton(
onPressed: () {
setState(() {
hidePassword = !hidePassword;
});
},
icon: (hidePassword == true)
? const Icon(Icons.visibility_off)
: const Icon(
Icons.visibility,
),
),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
hintText: 'Enter your password.',
),
validator: validatePassword,
),
I have 1 functionality of adding TextFormField in Container on Button press upto 4 TextFormField like below image and when there's no text in TextFormField i want to remove that TextFormField so i have put that login in onChange.
When i press the button 1s time and it will add TextFormField and without typing any character if i press delete button from keyboard onChange is not getting called.
Please see this video: https://drive.google.com/file/d/1Yln48d5JHvvYdb4LRDXxmlzPzlC__xYq/view?usp=sharing
Here is my code.
TextFormField(
controller: bullet2Controller,
focusNode: focusNode2,
maxLines: null,
minLines: 1,
textCapitalization:TextCapitalization.sentences,
cursorColor: Colors.black,
showCursor: true,
autofocus: true,
textAlign: TextAlign.start,
inputFormatters: [LengthLimitingTextInputFormatter(140),],
onChanged: (value) {
setState(() {
if (value.isEmpty) {
isBullet2Visible = false;
if (isBullet1Visible) {
focusNode1.requestFocus();
} else if (isBullet3Visible) {
focusNode3.requestFocus();
} else if (isBullet4Visible) {
focusNode4.requestFocus();
} else {
FocusScope.of(context).unfocus();
}
if (_counter > 0) {
_counter--;
}
}
if (kDebugMode) {
print("${value.length.toString()} character(s)");
}
});
},
decoration: const InputDecoration(disabledBorder:
InputBorder.none,
border:
InputBorder.none,
filled: true,
fillColor: Colors.white,
),
keyboardType:
TextInputType
.multiline,
textInputAction:
TextInputAction.done,
),
Is it default behaviour or do i need to do any extra step to make it work.
this is a default behaviour.
when your value = '' and you press delete it is still equal to '' and onChanged not getting called.
to achieve your goals you should use a listener like RawKeyboardListener
Thanks to Vladyslav Ulianytskyi suggestion.
I have done this with the use of RawKEyboardListner. Here is the sample code.
RawKeyboardListener(
autofocus: true,
onKey: (event) {
setState(() {
if (event.isKeyPressed(LogicalKeyboardKey.backspace)) {
print("Perform Your Action");
}
});
},
focusNode: FocusNode(),
child: TextFormField(controller: bullet2Controller,
focusNode: focusNode2,
maxLines: null,
minLines: 1,
textCapitalization: TextCapitalization.sentences,
cursorColor: Colors.black,
showCursor: true,
autofocus: true,
textAlign: TextAlign.start,
inputFormatters: [LengthLimitingTextInputFormatter(140),
],
decoration: const InputDecoration(
disabledBorder: InputBorder.none,
border: InputBorder.none,
filled: true,
fillColor: Colors.white,
),
keyboardType: TextInputType.multiline,
textInputAction: TextInputAction.done,
),
),
)
You can try it will below code hope it's work for you
TextEditingController bullet2Controller = TextEditingController();
int currentTextLength = 0;
TextFormField(
maxLines: null,
controller: bullet2Controller,
decoration: InputDecoration(
hintText: 'Type your observations'
),
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w300,
fontFamily: 'Roboto'
),
onChanged: (String newText){
if (newText != ''){
if(newText[0] != '•'){
newText = '• ' + newText;
bullet2Controller.text = newText;
bullet2Controller.selection = TextSelection.fromPosition(TextPosition(offset: bullet2Controller.text.length));
}
if(newText[newText.length - 1] == '\n' && newText.length > currentTextLength){
bullet2Controller.text = newText + '• ';
bullet2Controller.selection = TextSelection.fromPosition(TextPosition(offset: bullet2Controller.text.length));
}
currentTextLength = bullet2Controller.text.length;
}
}
)
let me know if it's work for you or let me know if there any question.
I have a TextFormField with a controller. In this controller the initial value is 0, but the user can add decrease the number. This is the code:
TextFormField(
controller: _controller,
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
onChanged: (value) {
_setQuantity();
setState(() {
quantidade = int.tryParse(_controller.text);
});
},
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(4),
],
style: TextStyle(
color: Colors.white,
fontSize: 22.0,
),
cursorColor: AppColorSecondary,
decoration: InputDecoration(
filled: true,
fillColor:
Colors.white,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide(color: Colors.transparent),
),
),
),
The Controller:
void _setQuantity() {
Provider.of<Product>(context, listen: false).setQuantity(
int.tryParse(_controller.text));
}
#override
void initState() {
_controller = TextEditingController(text: getSize().toString());
_controller.addListener(_setQuantity);
quantity = widget.size.quantity;
super.initState();
}
So, for example, the initial value of the TextFormField is 0, if I put 3 it keep the first zero:
// How it is now
// Initial State:
// 0
// I put a three:
// 03
//How I want:
// Initial State:
// 0
// I put a three:
// 3
How can I reach this?
onChanged:(value){
if (value[0] =="0") controller.text = value.substring(1);
}
I'm getting this error trying to apply the concept of reusable component.
can some one help please?
I need to make both the onFieldSubmitted and onChanged a optional functions.
also I tried just using Function to declear name of the function instead of VoidCallback but it didn't word.
this is the code
Widget defaultTextBox({
required TextEditingController inputController,
required String boxLapel,
VoidCallback? onSubmit,
VoidCallback? changed,
required VoidCallback pressed,
}) =>
TextFormField(
validator: (value) {
if (value!.isEmpty) {
return 'please enter password address';
}
return null;
},
controller: inputController,
decoration: InputDecoration(
labelText: boxLapel,
labelStyle: TextStyle(fontSize: 20, color: Colors.black),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(9.0))),
suffixIcon: IconButton(
onPressed: pressed,
icon: Icon(
Icons.visibility),
),
prefixIcon: Icon(
Icons.lock,
color: Colors.black,
)),
obscureText: true,
keyboardType: TextInputType.visiblePassword,
// error is here and here
onFieldSubmitted: onSubmit, // <-
onChanged: changed, // <-
);
I found a solution and I should declare the function as follow :
required String? Function(String?)? onSubmit,
I am trying to create custom textformfield so I can easily style only in one place. But currently I am stuck on how to pass validation and save process. Can someone give me a working example of custom widget textformfield that I can use? I have been searching it for whole day and cannot find one. Thank you for help.
Example here is on raised button:
import 'package:flutter/material.dart';
import 'package:wkndr/resources/constants.dart';
class CustomButton extends StatelessWidget {
CustomButton({#required this.text, #required this.onPressed});
final String text;
final GestureTapCallback onPressed;
#override
Widget build(BuildContext context) {
return RaisedButton(
color: colorPrimary,
child: Text(text, style: TextStyle(fontSize: 17.0, color: colorWhite)),
onPressed: onPressed,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
);
}
}
Calling custom raised button:
final _signUpButton = Container(
child: CustomButton(
text: sign_up,
onPressed: () {
_signUp();
}),
);
Instead of making custom textformfield you can make common InputDecoration for styling
class CommonStyle{
static InputDecoration textFieldStyle({String labelTextStr="",String hintTextStr=""}) {return InputDecoration(
contentPadding: EdgeInsets.all(12),
labelText: labelTextStr,
hintText:hintTextStr,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
);}
}
Example:-
TextFormField(
controller: usernameController,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
focusNode: userFocus,
onFieldSubmitted: (_) {
FocusScope.of(context).requestFocus(passFocus);
},
validator: (value) => emptyValidation(value),
decoration: CommonStyle.textFieldStyle(labelTextStr:"Username",hintTextStr:"Enter Username"),
)
You can define InputDecorationTheme in your app theme to set global style for text fields.
MaterialApp(
title: title,
theme: ThemeData(
brightness: Brightness.dark,
...
inputDecorationTheme: InputDecorationTheme(
fillColor: Colors.blue,
filled: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white)),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue)),
hintStyle: TextStyle(color: Colors.white.withAlpha(80)),
),
)
);
You can also change theme properties for a particular widget using Theme widget:
Theme(
data: Theme.of(context).copyWith(inputDecorationTheme: /*new decoration theme here*/),
child: Scaffold(
body: ...,
),
);
See more information about themes in Flutter docs.
You can try custom TextFormField.
You can make easily common TextFormField for customizing TextFormField.
You can try like this.
Step 1: First create one dart class i.e EditTextUtils
Step 2: Create a function or method i.e getCustomEditTextArea
class EditTextUtils {
TextFormField getCustomEditTextArea(
{String labelValue = "",
String hintValue = "",
bool validation,
TextEditingController controller,
TextInputType keyboardType = TextInputType.text,
TextStyle textStyle,
String validationErrorMsg}) {
TextFormField textFormField = TextFormField(
keyboardType: keyboardType,
style: textStyle,
controller: controller,
validator: (String value) {
if (validation) {
if (value.isEmpty) {
return validationErrorMsg;
}
}
},
decoration: InputDecoration(
labelText: labelValue,
hintText: hintValue,
labelStyle: textStyle,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(5.0))),
);
return textFormField;
}
}
Example: You can try like this
EditTextUtils().getCustomEditTextArea(
labelValue: 'label',
hintValue: 'hint',
validation: true,
controller: controller_name,
keyboardType: TextInputType.number,
textStyle: textStyle,
validationErrorMsg: 'error_msg')