flutter - need to extends State and FormField - flutter

I neet to create a statefull class which create formFiled. for this I need to do something like this:
class SelectCategories extends StatefulWidget{
SelectCategories();
#override
_SelectCategoriesState createState() => new _SelectCategoriesState();
}
class _SelectCategoriesState extends State<SelectCategories> extends FormField<List<number>>{
}
So I need to extends 2 classed. What is the right way to do this?
I want create a list of categories and allow user to choose from. it should be part of a form. When user click on category, I need to change the state to indicate it

you can reference this package 's souce code https://pub.dev/packages/flutter_form_builder
dropdown look like what your need
https://github.com/danvick/flutter_form_builder/blob/master/lib/src/fields/form_builder_dropdown.dart
and also validator you can reference, this package provide more than 10 builin validator https://github.com/danvick/flutter_form_builder/blob/master/lib/src/form_builder_validators.dart
code snippet of form_builder_dropdown.dart
it return a FormField and in builder return DropdownButton
#override
Widget build(BuildContext context) {
return FormField(
key: _fieldKey,
enabled: !_readonly,
initialValue: widget.initialValue,
validator: (val) {
for (int i = 0; i < widget.validators.length; i++) {
if (widget.validators[i](val) != null)
return widget.validators[i](val);
}
},
onSaved: (val) {
if (widget.valueTransformer != null) {
var transformed = widget.valueTransformer(val);
FormBuilder.of(context)
?.setAttributeValue(widget.attribute, transformed);
} else
_formState?.setAttributeValue(widget.attribute, val);
},
builder: (FormFieldState<dynamic> field) {
return InputDecorator(
decoration: widget.decoration.copyWith(
errorText: field.errorText,
border: InputBorder.none,
),
child: DropdownButton(
isExpanded: widget.isExpanded,
hint: widget.hint,
items: widget.items,
value: field.value,
style: widget.style,
isDense: widget.isDense,
disabledHint: widget.disabledHint,
elevation: widget.elevation,
iconSize: widget.iconSize,
onChanged: _readonly
? null

Related

Flutter Checkbox value storage in Firebase

My setup is simple: i am making a landing page using Flutter web: users input their email add and tick a Checkbox if say they are over 18.
For the life of me I can not find a way to store both email add and the boolean value of the checkbox in the SAME RECORD in Firebase?
the UI and Firebase all setup and working ok, here the code snippets:
`child: TextFormField(
controller: _emailController,
// The validator receives the text that the user has entered.
validator: (val) => !EmailValidator.validate(val!, true)
? 'Please enter a valid email.'
: null,
onSaved: (email2save) => this.email2save = email2save,
decoration: InputDecoration(
icon: Icon(
Icons.email_outlined,
color: Color(0xFF0000CC),
),
hintText: "Please enter your email",
border: InputBorder.none),
),
.......
Column(
children: [
Text('Please tick here'),
MyStatefulWidget(),
Text(' if over 18'),
],
),
.......
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool isChecked = false;
#override
Widget build(BuildContext context) {
Color getColor(Set<MaterialState> states) {
const Set<MaterialState> interactiveStates = <MaterialState>{
MaterialState.pressed,
MaterialState.hovered,
MaterialState.focused,
};
if (states.any(interactiveStates.contains)) {
return Color(0xFF0000CC);
}
return Colors.black;
}
return Checkbox(
checkColor: Colors.white,
fillColor: MaterialStateProperty.resolveWith(getColor),
value: isChecked,
onChanged: (bool? value) {
setState(() {
isChecked = value!;
});
},
);
}
Hi I don't see any Firebase in the code you've provided above but it is actually pretty easy to add two or even many things at once to Cloud Firestore:
var collection = FirebaseFirestore.instance
.collection(collection_name)
.doc(document_name);
collection
.set({
'email': 'email2save',
'check': 'isChecked'
})
You can do this anywhere in your class and it will work like magic.

The error I get while saving the information entered in the Dart Flutter text input field

When watching the trainer's video, she doesn't get such an error, but while I'm typing.
Instructor:
My Code:
What is the problem?
My Related code:
userAdd.dart:
import 'dart:io';
import 'package:denemeleruygulamasi/personel.dart';
import 'package:flutter/material.dart';
class personelEkle extends StatefulWidget{
#override
State<StatefulWidget> createState() {
return personelEkleState();
}
}
class personelEkleState extends State{
var personel = personelBilgileri.bilgileri();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Personel Ekle"),
),
body: Container(
margin: EdgeInsets.all(15),
child: Form(
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
labelText: "Personel adı",
hintText: "Ad - soyad",
),
onSaved: (String? value) {
personel.ad = value;
},
),
TextFormField(
decoration: InputDecoration(
labelText: "Personel soyadı",
hintText: "Ad - soyad",
),
),
TextFormField(
decoration: InputDecoration(
labelText: "Personel kıdem yılı",
hintText: "Ad - soyad",
),
),
],
),
),
),
);
}
}
personel.dart:
class personelBilgileri{
late int? id;
late String ad;
late String soyad;
late int kidem;
late String unvan;
personelBilgileri.withId(this.id, this.ad, this.soyad, this.kidem, this.unvan);
personelBilgileri(this.ad, this.soyad, this.kidem, this.unvan);
personelBilgileri.bilgileri();
String get unvanGet{
String mesaj = "";
if (this.kidem <= 3){
mesaj = "Pro";
}
else if (this.kidem <= 5) {
mesaj = "Expert";
}
else {
mesaj = "Expert Pro";
}
return mesaj;
}
}
personel = staff.
Error:
String? value
A value of type 'String?' can't be assigned to a variable of type 'String'.
Try changing the type of the variable, or casting the right-hand type to 'String'.dartinvalid_assignment
I'm trying to make a staff application. I'm currently having a problem with adding staff. I created a separate dart file to add staff.
I guess you are using null safety and the video is old enough that it doesn't use it, please try the following:
onSaved: (String? value) {
personel.ad = value;
},

Best way to validate a form with flutter provider package?

I need separate logic with UI.
I used the following example:
1.- Use a class validation item to show a string value and error.
class ValidationItem {
final String value;
final String error;
ValidationItem(this.value, this.error);
}
2.- Use the next code for provider class.
class SignupValidation with ChangeNotifier {
ValidationItem _firstName = ValidationItem(null,null);
//Getters
ValidationItem get firstName => _firstName;
bool get isValid {
if (_firstName.value != null){
return true;
} else {
return false;
}
}
//Setters
void changeFirstName(String value){
if (value.length >= 3){
_firstName=ValidationItem(value,null);
} else {
_firstName=ValidationItem(null, "Must be at least 3 characters");
}
notifyListeners();
}
void submitData(){
print("FirstName: ${firstName.value}");
}
}
3.- Use the next widget to show text field and validate
class Signup extends StatelessWidget {
#override
Widget build(BuildContext context) {
final validationService = Provider.of<SignupValidation>(context);
return Scaffold(
appBar: AppBar(
title: Text('Signup'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
TextField(
decoration: InputDecoration(
labelText: "First Name",
errorText: validationService.firstName.error,
),
onChanged: (String value) {
validationService.changeFirstName(value);
},
),
RaisedButton(
child: Text('Submit'),
onPressed: (!validationService.isValid) ? null : validationService.submitData,
)
],
),
),
);
}
}
The problem is the performance for example every time the text is changed the notifyListener() Is calles.
My question: Is there a cost to performance?
you can use TextFormField instead of TextField.
Best way to validate fields is that you can use validator property TextFormField property as bellow
TextFormField(
decoration: InputDecoration(
labelText: "First Name",
errorText: validationService.firstName.error,
),
validator: (e){
if(e!.trim().isEmpty) return "String is empty";
return null;
},
onChanged: (String value) {
validationService.changeFirstName(value);
},
),
The TextField itself gives you the ability to validate the form, then why to make it complex by implementing notifier, instead you want to make it common you can make the validater global function for it. Nad user it in the validate function.
Void validateEmail(String value){ // your logic}
Use this function as follow
TextFormField(
decoration: InputDecoration(
labelText: "First Name",
errorText: validationService.firstName.error,
),
validator: validateEmail(),
onChanged: (String value) {
validationService.changeFirstName(value);
},
Secondly to get the value of inputted string you have a TextEditingController which directly give you the string you inputted.
Declare TextEditingController as follow
TextEditingController emailCont = TextEditingController();
Use this controller in TextField as follow
TextFormField(
controller: emailCont,
decoration: InputDecoration(
labelText: "First Name",
errorText: validationService.firstName.error,
),
validator: validateEmail(),
onChanged: (String value) {
validationService.changeFirstName(value);
},
Now to get the value from this controller you can get it this way.
emailCont.text
This way it will be easy to manage and less complexity.

Flutter: Adding a hyphen and brackets to a user's phone number entered in a textfield

I am trying to rearrange a user's entered phone number with brackets around the area code and a hyphen. For example, the user would enter 9991234567 and it would be rearranged to (999) 123-4567 inside the textfield.
I'm using a RegExp to separate the user's entry into the area code, and the 2 parts of the phone number. I am attempting to use a TextEditingController to edit the text field with brackets and a hyphen when the Save button is pressed but it does not seem to work.
_saveButtonPressed() async {
RegExp phone = RegExp(r'(\d{3})(\d{3})(\d{4})');
var matches = phone.allMatches(UserProfile.instance.phone);
var match = matches.elementAt(0);
setState(() {
phoneController.text = '(${match.group(1)}) ${match.group(2)}-${match.group(3)}';
});
}
This is the code for the phone number textfield.
_makeRowForAttribute(
imageAsset: "assets/images/phone.png",
title: "PHONE NUMBER",
keyboardType: TextInputType.phone,
placeholder: "6131110123",
charLimit: 10,
initialValue: UserProfile.instance.phone,
controller: phoneController,
onSave: (phone) {
UserProfile.instance.phone = phone.toString();
},
),
You can simply use flutter_masked_text package
It's just simple as following
import 'package:flutter_masked_text/flutter_masked_text.dart';
class MobileNumberTextField extends StatefulWidget {
createState() => MobileNumberTextFieldState();
}
class MobileNumberTextFieldState extends State<MobileNumberTextField> {
final controller =MaskedTextController(mask: "(000) 000-0000");
#override
Widget build(BuildContext context) {
return TextField(
controller: controller,
keyboardType: TextInputType.number,
autofocus: true,
);
}
}
Hope it will be helpful
I think this should do the trick.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class FormattedPhoneNumber extends StatefulWidget {
#override
_FormattedPhoneNumberState createState() => _FormattedPhoneNumberState();
}
class _FormattedPhoneNumberState extends State<FormattedPhoneNumber> {
String text = "";
convert(TextEditingValue oldValue, TextEditingValue newValue) {
print("OldValue: ${oldValue.text}, NewValue: ${newValue.text}");
String newText = newValue.text;
if (newText.length == 10) {
// The below code gives a range error if not 10.
RegExp phone = RegExp(r'(\d{3})(\d{3})(\d{4})');
var matches = phone.allMatches(newValue.text);
var match = matches.elementAt(0);
newText = '(${match.group(1)}) ${match.group(2)}-${match.group(3)}';
}
// TODO limit text to the length of a formatted phone number?
setState(() {
text = newText;
});
return TextEditingValue(
text: newText,
selection: TextSelection(
baseOffset: newValue.text.length,
extentOffset: newValue.text.length));
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
inputFormatters: [
TextInputFormatter.withFunction(
(oldValue, newValue) => convert(oldValue, newValue)),
],
keyboardType: TextInputType.phone,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: "input",
labelText: "Converts to phone number format"),
// Fixes a problem with text-caret only being at the start of the textfield.
controller: TextEditingController.fromValue(new TextEditingValue(
text: text,
selection: new TextSelection.collapsed(offset: text.length))),
),
),
],
);
}
}
Hope it helps :-)

Flutter update countertext

In Flutter, inputDecoration's countertext property does not change as the user is typing in the TextFormField. Is it possible to decrement the countertext as the user is typing?
TextFormField(
keyboardType: TextInputType.number,
decoration: new InputDecoration(
counterText: "9",
hintText: "Enter exact order number",
),
)
I edit this answer to work with your question
class StackEditText extends StatefulWidget {
#override
_StackEditTextState createState() => _StackEditTextState();
}
class _StackEditTextState extends State<StackEditText> {
TextEditingController _controller = new TextEditingController();
void onValueChange() {
setState(() {
_controller.text;
});
}
#override
void initState() {
super.initState();
_controller.addListener(onValueChange);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
child: TextFormField(
controller: _controller,
maxLength: 9,
decoration: InputDecoration(
counterText: "${9 - _controller.text.length}",
hintText: 'Enter exact order number',
),
),
),
);
}
}
I do not recommend using the decoration: InputDecoration::counterText. You have to use setState or whatever to manually update the counter that way.
Instead, I recommend the maxLength property, that automatically makes a counter and updates it:
TextField(maxLength: 8)
Result:
This might be what most people want.
You can even further customize it with the buildCounter parameter, to return whatever widget you want when the text length changes. For example, if you only want to display how many characters left, you can do this:
TextField(
maxLength: 8,
buildCounter: (
BuildContext context, {
int currentLength,
int maxLength,
bool isFocused,
}) {
return Text('${maxLength - currentLength}');
},
)