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.
Related
My application contains localizations (translation "en","ar"), in my translation JSON files there are cities that users will choose while registration process these cities appears in a DropDownButtonFormField widget as follows:
final provincesField = DropdownButtonFormField<String>(
value: dropDownValue,
onChanged: (String? newValue) {
setState(() {
dropDownValue = newValue!;
});
},
items: provinces.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: SizedBox(
width: 100.0,
child: Text(value, textAlign: TextAlign.center),
));
}).toList(),
elevation: 4,
decoration: InputDecoration(
prefixIcon: Icon(Icons.flag_circle),
labelText: AppLocalizations.of(context)!.chooseProvinence,
alignLabelWithHint: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
the cities are declared in this list:
List<String> provinces = [
'عمان',
'إربد',
'الزرقاء',
'المفرق',
'الطفيلة',
'عجلون',
'معان',
'الكرك',
'مادبا',
'العقبة',
'البلقاء',
'جرش'
];
String dropDownValue = 'عمان';
what am trying to achieve is that cities will appear to user based on the app language. I have tried to use AppLocalizations.of(context)!.city inside of the list but its not working so i believe there is some way to declare the list values based on localization, ill appreciate any help
Suppose below localizations data is your cities list
English:
"Dhaka" : "Dhaka",
"Chittagong" : "Chittagong",
"Cumilla" : "Cumilla",
"Rajshahi" : "Rajshahi",
"Bhola" : "Bhola",
Arabic:
"Dhaka" : "دكا",
"Chittagong" : "شيتاغونغ",
"Cumilla" : "كوميلا",
"Rajshahi" : "راجشاهي",
"Bhola" : "بولا",
initialize your the localization keys of your cities and dropDownValue
List<String> provinces = [
"Dhaka",
"Chittagong",
"Cumilla",
"Rajshahi",
"Bhola",
];
String dropDownValue = 'Dhaka';
here is the widget. I used getx localization. So I used 'tr' after the child text of DropdownMenuItem. I hope it's can help u.
Widget TestWidget() {
return DropdownButtonFormField<String>(
value: dropDownValue,
onChanged: (String? newValue) {
// To print the value with localization
print(newValue!.tr);
},
items: provinces.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(value: value, child: Text(value.tr));
}).toList(),
elevation: 4,
decoration: InputDecoration(
prefixIcon: Icon(Icons.flag_circle),
labelText: 'Select',
alignLabelWithHint: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
}
If you need to store the city in database or anywhere with localization then you can use it like [dropDownValue.tr]
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;
},
I have a Flutter Form with many dropdownformfield and textformfield widgets, validating these is trivial using the validate: method. Validation for visual fields is obvious.
However, in many forms a non-visible element may need to be validated. For instance, if taking a picture in a Form, there will only be a button to take the picture which will input the resulting filename into a String var. I would need to validate the String var in this case and return the validation result to the button (i.e. display a "Required field" below the button), but of course the String var is not held in any formfield widget.
This being said, how can I either "wrap" the button in a widget which contains a validator: method, or how can I add a validator to the button itself AND then display the appropriate validation message to the user in the UI?
Thank you!
You could create your own FormField:
class TakePictureFormField extends FormField<String> {
/// Creates a [FormField] that contains an [ElevatedButton] to take a picture
/// with the phone camera.
///
/// The [String] value corresponds to the path of the picture taken.
TakePictureFormField({
Key? key,
String? initialValue,
FormFieldSetter<String>? onSaved,
FormFieldValidator<String>? validator,
bool enabled = true,
AutovalidateMode? autovalidateMode,
ButtonStyle? buttonStyle,
void Function(String)? onChanged,
}) : super(
key: key,
initialValue: initialValue,
onSaved: onSaved,
validator: validator,
enabled: enabled,
autovalidateMode: autovalidateMode,
builder: (FormFieldState<String> field) {
final currentValue = field.value;
return InputDecorator(
decoration: InputDecoration(
border: InputBorder.none,
errorText: field.errorText,
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(field.context).errorColor,
),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
style: buttonStyle,
onPressed: () async {
// Fake implementation to take a picture.
final value = await Future<String>.delayed(
const Duration(microseconds: 300),
() => 'my_path/to/image');
field.didChange(value);
if (onChanged != null) {
onChanged(value);
}
},
child: const Text('Take a Picture'),
),
if (currentValue != null) Text(currentValue),
],
),
);
},
);
}
And then use it inside a Form like you would for any other FormField widget:
TakePictureFormField(
validator: (val) =>
val == null || val.isEmpty ? 'Error invalid picture' : null,
)
Try the complete example on DartPad
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.
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