I have an issue with a textfield in flutter.
I need to get a town or postal code to redirect the user to another page. But it seems like I keep old value even if the text inside textfield changes.
I tried to clear it, make conditions but I don't understand why the text does not keep the current value.
Here some code :
Check if it's Paris, for the borough
#override
void initState() {
editingController.addListener((){
setState(() {
if(editingController.text.isEmpty) {
editingController.clear();
isParis = false;
}
});
});
super.initState();
}
Button which redirect, the method getPcFromQuery (it's an async method) retrieve data relatives to a town name.
RaisedButton(
onPressed: (){
print(editingController.text);
getPCFromQuery(editingController.text)
.then((town) {city = town.featureName; postalCode = town.postalCode;});
setState(() {
if(city.toString().toLowerCase() == "paris")
isParis = true;
else
isParis = false;
});
print("postalCode : $postalCode");
postalCode != null && city.toString().toLowerCase() != "paris"?
Navigator.of(context).push(MaterialPageRoute(builder: (context) => PreferencesPage(postalCode: postalCode))) :
Container(child: Text(""));
})
But when I click on the next button (I need to click on it two times to make it work) and when I change the value inside my textfield, it keeps the previously entered value.
Do you know where it can come from?
This is TextField built:
class SearchBar extends StatelessWidget {
const SearchBar({
Key key,
#required this.editingController,
}) : super(key: key) ;
final TextEditingController editingController;
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(10.0)),
child: TextField(
controller: editingController,
decoration: InputDecoration(
hintText: AppStrings.searchTown,
hintStyle: GoogleFonts.notoSans(fontSize: 14.0),
border: InputBorder.none,
fillColor: Colors.grey.withOpacity(0.5),
prefixIcon: Icon(Icons.search, color: Colors.grey)
),
)
);
}
}
And method _getPcFromQuery :
_getPCFromQuery(String city) async {
var addresses = await Geocoder.local.findAddressesFromQuery(city);
var first = addresses.first;
print(first.featureName);
print(first.addressLine);
return first;
}
The weird thing is, when I try the first time, the prints inside _getPcFromQuery method get text, but the print "print("postalCode : $postalCode");" on the onPressed method button is null.
Specify the key parameter for TextField.
class SearchBar extends StatelessWidget {
const SearchBar({
Key key,
#required this.editingController,
}) : super(key: key) ;
final TextEditingController editingController;
final searchKey = GlobalKey(); // <-- create a global key
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(10.0)),
child: TextField(
key: searchKey, // <-- specify the declared key here
controller: editingController,
decoration: InputDecoration(
hintText: AppStrings.searchTown,
hintStyle: GoogleFonts.notoSans(fontSize: 14.0),
border: InputBorder.none,
fillColor: Colors.grey.withOpacity(0.5),
prefixIcon: Icon(Icons.search, color: Colors.grey)
),
)
);
}
}
Related
I'm making login and sign up page in my mobile application with flutter. I'm wondering how can I put the right data which is matched with the props.
For example, if I got the 'password' as a textValue, then I want to return the warningText which is 'Password must be at least 7 characters long.', the icon would be Icons.lock, and the hintText would be 'password'.
The textValue can be three options which are 'username', 'password' and 'email'.
textValue : username
warningText : 'Please enter at least 4 characters'
icon : Icons.account_circle,
hintText : username
textValue : email
warningText : 'Please enter a valid email address.'
icon : Icons.email,
hintText : email
Also, the reason why I want to use switch case syntax is because I want to make my codes shorter. I could just use multiple of textformfield, but I want to make my codes shorter and make them re-useable.
Because I'm using Provider for state management, I want to put the switch case codes into the Provider.
This is the textformfield widget code.
class LoginSignupTextFormField extends StatelessWidget {
const LoginSignupTextFormField({Key? key,
required this.valueKeyNumb,
required this.textValue})
: super(key: key);
final int valueKeyNumb;
final String textValue;
#override
Widget build(BuildContext context) {
return TextFormField(
obscureText: textValue == 'password' ? true : false,
key: const ValueKey(3),
validator: (value) {
if (value!.isEmpty || value.length < 6) {
return 'Password must be at least 7 characters long.';
}
return null;
},
onSaved: (value) {
context.watch<LoginSignupData>().userPassword = value!;
},
onChanged: (value) {
context.watch<LoginSignupData>().userPassword = value;
},
decoration: const InputDecoration(
prefixIcon: Icon(
Icons.lock,
color: Colors.red,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.blueGrey),
borderRadius: BorderRadius.all(
Radius.circular(35.0),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black),
borderRadius: BorderRadius.all(
Radius.circular(35.0),
),
),
hintText: 'password',
hintStyle: TextStyle(
fontSize: 14,
color: Colors.red),
contentPadding: EdgeInsets.all(10)),
);
}
}
This is my Provider code for the textformfield and I want to put the switch case codes in it.
class LoginSignupData extends ChangeNotifier{
final authentication = FirebaseAuth.instance;
bool isSignup = true;
final formKey = GlobalKey<FormState>();
String userName = '';
String userEmail = '';
String userPassword = '';
changeBool(status){
isSignup = status;
notifyListeners();
}
tryValidation() {
final isValid = formKey.currentState!.validate();
if (isValid) {
formKey.currentState!.save();
notifyListeners();
}
}
}
You may have to take three separate textfield for that and assign values to each.
If you want to make common textfield for all then you can take enum with three values and you have to pass that in constructor.
enum TextFieldType {EMAIL, PASSWORD, USERNAME};
Now you can check the value inside the validator and according to that you can show the error.
switch (enumValue) { // Your Enum Value which you have passed
case TextFieldType.PASSWORD:
//Your validations for password
break;
case TextFieldType.EMAIL:
//Your validations for email
break;
case TextFieldType.USERNAME:
//Your validations for username
break;
}
Hope it will help you.
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;
},
So, am having this page, where I can add multiple TextFormFiled that represent a text block. The thing is, it's generated dynamic so you never know how many Text Editing controllers you need.
void addTextBlock() {
state.blocks.add(
TextBlock(hint: 'Description', controler: state.descriptionController));
}
Here is the code that trigger when tapping Add Text Block, and as you can see it uses the same controller.
The TextBlock wiget :
class TextBlock extends Block {
TextBlock({required this.controler, required this.hint})
: super(BlockType.TextBlock);
final String hint;
final TextEditingController controler;
#override
Widget toWidget() {
return TextFormField(
controller: controler,
decoration: InputDecoration(
filled: true,
fillColor: AppColors.textFieldBackground,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide(color: AppColors.textFieldHintColor),
),
contentPadding:
const EdgeInsets.symmetric(vertical: 22.0, horizontal: 24.0),
hintText: hint,
hintStyle:
AppTextStyles.normalRoboto(color: AppColors.textFieldHintColor),
),
maxLines: null,
keyboardType: TextInputType.multiline,
style: AppTextStyles.normalRoboto(color: AppColors.textFieldHintColor),
);
}
}
Try out below code:
List<TextEditingController> textEditingControllers = [];
void addTextBlock() {
TextEditingController textEditingController = TextEditingController();
textEditingControllers.add(textEditingController)
state.blocks.add(
TextBlock(hint: 'Description', controler: textEditingControllers[textEditingControllers.length-1]));
}
I made a class and it has a controller and a widget that includes a padding within a textfield.
Now when I change the focus from the textfield to something else it lose the value.
this is my code.
`
class RxInput {
final String hindText;
final bool obscureText;
Widget widget;
final TextEditingController controller = new TextEditingController ();
String get value => controller.text;
RxInput (this.hindText,context,{this.obscureText = false}) {
widget = Padding (
padding: const EdgeInsets.all(20.0),
child: Material(
borderRadius: BorderRadius.circular(20.0),
shadowColor: Colors.blue.shade200,
elevation: 5.0,
child:TextField(
controller: controller,
decoration: InputDecoration(
hintText: hindText,
border: InputBorder.none,
alignLabelWithHint: true,
),
obscureText: obscureText,
)
),
);
}
}
`
I solved this question. You should initialize your variable in the initState instead of build.
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}');
},
)