How to pass flutter textFormField onChange and onSubmitted as a parameter? - flutter

I'm trying to create a custom TextFormField that will accepts parameters that I needed like labelText, controller or prefixIcon etc. What I don't know is how to pass a function to an OnChange and onSubmitted events. Please check the sample code below.
utils.dart
class TextFieldTemplate extends StatelessWidget {
final String initialValue;
final String labelText;
final String hintText;
final IconData prefixIcon;
final TextEditingController controller;
final Function onTap;
TextFieldTemplate(
{this.initialValue,
this.labelText,
this.prefixIcon,
this.controller,
});
#override
Widget build(BuildContext context) {
return TextFormField(
onChanged: (){},
onSubmitted: (){},
controller: controller,
decoration: InputDecoration(
contentPadding: decorationPadding,
labelText: labelText,
prefixIcon: prefixIcon != null
? Icon(
prefixIcon,
)
: null,
),
);
}
}
Usage for the TextFieldTemplate:
var _personName = TextEditingController();
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
childtren[
TextFieldTemplate(
labelText: 'Person Name',
controller: _personName,
prefixIcon: Icons.person,
// onSubmitted : ???
// OnChange : ???
),
]
),
);
}

You can pass onChanged and onSubmitted parameter like this
Function(String) onChanged;
Function(String) onSubmitted;
And use like this
TextFieldTemplate(
labelText: 'Person Name',
controller: _personName,
prefixIcon: Icons.person,
onSubmitted: (value){},
onChanged: (value){},
),

Related

Flutter - GestureDetector function does not work with custom widget

I am trying to manage some gap between elements and update the gap using setState(). Unfortunately, it did not work with a custom widget TextFieldInput as child of GestureDetector.
GestureDetector(
onTap: () {
setState(() {
gap = 16.00;
});
},
child: TextFieldInput(
textEditingController: _passwordController,
hintText: 'Enter your password',
textInputType: TextInputType.text,
isPass: true,
),
),
But it did work with a Text widget.
GestureDetector(
onTap: () {
setState(() {
gap = smallGap;
});
},
child: Container(
child: Padding(
padding: EdgeInsets.all(5),
child: Text('Tap here'),
),
padding: const EdgeInsets.symmetric(
vertical: 8,
),
),
)
Here is the TextFieldInput widget structure:
import 'package:flutter/material.dart';
class TextFieldInput extends StatefulWidget {
final TextEditingController textEditingController;
final bool isPass;
final String hintText;
final TextInputType textInputType;
final VoidCallback onTap;
const TextFieldInput({
super.key,
required this.textEditingController,
this.isPass = false,
required this.hintText,
required this.textInputType,
required this.onTap,
this.child,
});
final Widget? child;
#override
State<TextFieldInput> createState() => _TextFieldInputState();
}
class _TextFieldInputState extends State<TextFieldInput> {
#override
Widget build(BuildContext context) {
final inputBorder = OutlineInputBorder(
borderSide: Divider.createBorderSide(context)
);
return TextField(
controller: widget.textEditingController,
decoration: InputDecoration(
hintText: widget.hintText,
border: inputBorder,
focusedBorder: inputBorder,
enabledBorder: inputBorder,
filled: true,
contentPadding: const EdgeInsets.all(8),
),
keyboardType: widget.textInputType,
obscureText: widget.isPass,
onTap: () {},
);
}
}
But "gap" does not change even on tapping on the TextFieldInput.
Can anyone help with this ?
Try with a below code snippet:
TextField(
onTap: () {
// To Do
},
// TextField Property
);
gesture detector doesn't work with textField try adding ignorePointer
GestureDetector(
child: new IgnorePointer (
child: new TextField(
.......
))),
onTap: () {
//do some thing
},
The TextField has its onTap property, I think this is the cause of your problem. You should you onTap property of TextField or use another suitable widget

I code a textformfield widget and add validator then I called it from another screen but validator doesn't work

I code a textformfield widget and add validator then I called it from another screen but validator doesn't work. how to add validator in widget and call it from another class?
Input Field widget(this is what I called from loginscreen)
import 'package:flutter/material.dart';
import 'constants.dart';
class InputField extends StatelessWidget {
final TextEditingController controller;
final IconData? icon;
final String? text;
final String? errorText;
final TextInputType textInputType;
final TextAlign textAlign;
final Function function;
const InputField({
Key? key,
required this.controller,
this.icon,
this.text,
required this.textInputType,
this.errorText,
required this.textAlign,
required this.function,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: TextFormField(
controller: controller,
keyboardType: textInputType,
textInputAction: TextInputAction.next,
validator: (value){
function(value);
},
textAlign: textAlign,
decoration: InputDecoration(
prefixIcon: Icon(icon,color: kPrimaryColor,),
contentPadding: const EdgeInsets.all(5),
hintStyle: TextStyle(
fontFamily: 'InriaSans',
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold
),
hintText: text,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),),
),
),
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 40),
);
}
}
LOGIN SCREEN
I called input field in this login screen.
Widget _buildEmail(){
return InputField(
controller: emailController,
icon: Icons.email,
text: 'User email',
textAlign: TextAlign.left,
textInputType: TextInputType.emailAddress,
function: (){
return Validator.emailValidate(emailController.text);
},
);
}

How to give focus to DateTimeFormField on Flutter?

I have a form with TextFormFields. I can give focus to next field using Tab key as usual. But, it skips DateTimeFormField. How can I make it show the Date picker instead of skipping it when it is its turn?
Did some search but couldn't find anything near it.
Here is my code samples. I simply use TextFormField's and DateTimeFormField inside a Column. But there is no focus option for DateTimeFormField.
class FormDialog extends ConsumerWidget {
const FormDialog({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(
height: 12,
),
CustomTextField(
labelText: firstName,
textInputAction: TextInputAction.next,
),
const SizedBox(
height: 12,
),
CustomTextField(
labelText: lastName,
textInputAction: TextInputAction.next,
),
const SizedBox(
height: 12,
),
CustomDateField(
labelText: dateOfBirth,
),
const SizedBox(
height: 12,
),
CustomTextField.email(
labelText: parentEmail,
),
],
);
}
}
class CustomDateField extends StatelessWidget {
const CustomDateField({
Key? key,
this.labelText,
this.hintText,
}) : super(key: key);
final String? labelText;
final String? hintText;
#override
Widget build(BuildContext context) {
return DateTimeFormField(
mode: DateTimeFieldPickerMode.date,
dateFormat: DateFormat.yMd(),
decoration: InputDecoration(
labelText: labelText,
hintText: hintText,
border: const OutlineInputBorder(),
helperText: ' ',
),
);
}
}
class CustomTextField extends StatelessWidget {
const CustomTextField({
Key? key,
this.labelText,
this.icon,
this.textInputAction,
}) : super(key: key);
final String? labelText;
final TextFieldIcon? icon;
final TextInputAction? textInputAction;
#override
Widget build(BuildContext context) {
return TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: InputDecoration(
hintText: labelText,
border: const OutlineInputBorder(),
prefixIcon: icon,
helperText: ' ',
),
textInputAction: textInputAction,
);
}
factory CustomTextField.email({
String? errorMessage,
String? labelText,
}) =>
CustomTextField(
labelText: labelText ?? email,
icon: const TextFieldIcon.email(),
textInputAction: TextInputAction.next,
);
}
According to the package's Github repository, it is built upon FormField, creating and initializing a FocusNode and passing the focus node to the widget might resolve the issue. If not you might need to implement your own form field.

how to create resuable textfield with validator in flutter

I am creating a login form which has username and password field, i want to add validation when user skip any field. I have created this reusable textfield.
class RoundedInputField extends StatelessWidget {
final String hintText;
final ValueChanged<String> onChanged;
final TextEditingController controller;
final FormFieldValidator validate;
const RoundedInputField({Key key, this.hintText,
this.onChanged,
this.controller,this.validate,
})
: super(key: key);
#override
Widget build(BuildContext context) {
return TextFieldContainer(
child: TextFormField(
onChanged: onChanged,
controller: TextEditingController(),
validator: validate,
decoration: InputDecoration(
hintText: hintText,
border: InputBorder.none,
),
),
);
}
}
and calling it like this
RoundedInputField(hintText: "Username",icon: Icons.email,fontsize: 20,
controller: TextEditingController(text: user.username),
onChanged: (value){
user.username=value;
},
validate: (value){
if(value.isEmpty){
return "This field is required";
}
},
),
but validator property is not working properly, here it is.
please help if anyone know how to fix it!
I have been using TextFormField in a reusable way like this , it has served me for all the purposes i needed , i think it works for your case too
class BoxTextField extends StatelessWidget {
final TextEditingController controller;
final FormFieldValidator<String> validator;
final bool obsecure;
final bool readOnly;
final VoidCallback onTap;
final VoidCallback onEditingCompleted;
final TextInputType keyboardType;
final ValueChanged<String> onChanged;
final bool isMulti;
final bool autofocus;
final bool enabled;
final String errorText;
final String label;
final Widget suffix;
final Widget prefix;
BoxTextField(
{Key key,
this.controller,
this.validator,
this.keyboardType = TextInputType.text,
this.obsecure = false,
this.onTap,
this.isMulti = false,
this.readOnly = false,
this.autofocus = false,
this.errorText,
#required this.label,
this.suffix,
this.prefix,
this.enabled = true,
this.onEditingCompleted,
this.onChanged})
: super(key: key);
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(vertical: 4),
child: TextFormField(
onChanged: onChanged,
onEditingComplete: onEditingCompleted,
autofocus: autofocus,
minLines: isMulti ? 4 : 1,
maxLines: isMulti ? null : 1,
onTap: onTap,
enabled: enabled,
readOnly: readOnly,
obscureText: obsecure,
keyboardType: keyboardType,
controller: controller,
decoration: InputDecoration(
errorText: errorText,
prefixIcon: prefix,
suffixIcon: suffix,
labelStyle: TextStyle(fontSize: lableFontSize()),
labelText: label,
hintStyle: TextStyle(color: Colors.blueGrey, fontSize: 15),
contentPadding: EdgeInsets.symmetric(vertical: 8, horizontal: 20),
enabledBorder: textFieldfocused(),
border: textFieldfocused(),
focusedBorder: textFieldfocused(),
errorBorder: errorrTextFieldBorder(),
focusedErrorBorder: errorrTextFieldBorder(),
),
validator: validator),
);
}
}
This is the Usage
class LoginScreen extends StatefulWidget {
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
TextEditingController _emailPhone = new TextEditingController();
TextEditingController _password = new TextEditingController();
GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
#override
void initState() {
super.initState();
}
String loginError;
bool loggingIn = false;
#override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverList(
delegate: SliverChildListDelegate([
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 50,
),
BoxTextField(
validator: (str) {
if (str.isEmpty) {
return tr('common.required');
}
return null;
},
controller: _emailPhone,
label: tr('login.username'),
),
SizedBox(
height: 10,
),
BoxTextField(
label: tr('login.password'),
controller: _password,
obsecure: true,
validator: (str) {
if (str.isEmpty) {
return tr('common.required');
}
return null;
},
),
Center(
child: BoxButton(
loading: loggingIn,
lable: tr('login.btn'),
onPressed: () {
},
)),
],
)),
)
]))
],
);
}
}
Replace your code and try this:
RoundedInputField(
hintText: "Username",
icon: Icons.email,
fontsize: 20,
controller: TextEditingController(text: user.username),
onChanged: (value) {
user.username = value;
},
validate: (value) {
if (value.isEmpty) {
return "This field is required";
}
return null;
},
),

Validate TextFomField from different widget in Flutter

I have 2 widgets, one is the main one with a bunch of other widgets loaded on it. The other is the TextFormField that I need to validate.
Main widget:
RoundedInputField(
onChanged: (value) {
_email = value;
},
),
RoundedButton(
text: "LOGIN",
press: () async {}, // This is the button that should validate the input
);
Field widget:
class RoundedInputField extends StatefulWidget {
final String hintText;
final IconData icon;
final ValueChanged<String> onChanged;
const RoundedInputField({
Key key,
this.hintText,
this.icon = Icons.alternate_email,
this.onChanged,
}) : super(key: key);
#override
_RoundedInputFieldState createState() => _RoundedInputFieldState();
}
class _RoundedInputFieldState extends State<RoundedInputField> {
TextEditingController email = new TextEditingController();
#override
Widget build(BuildContext context) {
return TextFieldContainer(
child: TextFormField(
controller: email,
keyboardType: TextInputType.emailAddress, //TextInputType.phone,
onChanged: widget.onChanged,
decoration: InputDecoration(
hintText: "Your Email",
icon: Icon(
widget.icon,
color: Theme.of(context).primaryColorDark,
),
border: InputBorder.none,
),
validator: (value) {
return Helpers.CheckInput(value);
},
),
);
}
}
How can I validate the input clicking on the other LOGIN widget?
final _formKey = GlobalKey<FormState>();
...
Form(
key: _formKey,
child: Column(children: <Widget>[
RoundedInputField(
onChanged: (value) {
_email = value;
},
),
RoundedPasswordField(
onChanged: (value) {
_password = value;
},
),
RoundedButton(
text: "LOGIN",
press: () async {}
),