Show/Hide data inside the dialog box in flutter - flutter

I have a dialog box, which has a TextField(), and a Button. On press of it, I'm calling my API, but before that, I need to put a check on the text. Since everything works fine, I was wondering to find some way out to show the error text inside the dialog box only.
After all the research and work, the dialog box is not recreating itself hence no message is showing even if the boolean case becomes true.
CODE:
class ListViewElements extends StatefulWidget {
#override
_ListViewElementsState createState() => _ListViewElementsState();
}
class _ListViewElementsState extends State<ListViewElements> {
bool isError = false;
bool errorText = false;
final TextEditingController _code = new TextEditingController();
onSubmit(BuildContext context){
if(this._code.text.isEmpty){
setState(
(){
isError = true;
errorText = 'Empty space';
}
);
}
}
void registerDialog(BuildContext context){
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context){
return AlertDialog(
content: Column(
children: <Widget>[
Container(
margin: EdgeInsets.fromLTRB(40.0, 0.0, 40.0, 10.0),
child: TextField(
textAlign: TextAlign.center,
controller: this._code,
maxLength: 4,
textInputAction: TextInputAction.done,
cursorColor: Theme.of(context).primaryColor,
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: 'Enter here',
counterText: '',
)
)
),
isError == true ? Text(this.erroText) : Container()
]
),
actions: <Widget>[
FlatButton(
child: new Text("Done", style: TextStyle(color: Theme.of(context).primaryColor, fontSize: 17.0)),
onPressed: () {onSubmit(context);}
)
]
);
}
);
I thought of showing a SnackBar(), but for dialog box, Scaffold.of() is not working out, since the builder is creating the new instance of the box, hence cannot recall. Any help would be appreciated. Thanks :)

Related

How to update state with each change on text field flutter

I am building a search bar which brings some resuts from algolia. everything is working fine, except that the results listview view doesn't show the new resuts until I close the keyboard. but I need to update automatically with every new letter I write in the text field (while the keyboard is opened), same like auto complete function. what is mimssing here?
(note that all of this is inside a buttomsheet)
I also tried to replace the controller listner with onChange (){}, same issue is there.
the list view doesn't rebuild untill I close the keyboard.
The Funcion and the listner Code:
class _CategoriesPageState extends State<CategoriesPage> {
String _searchTerm = "";
List<AlgoliaObjectSnapshot> _results = [];
bool _searching = false;
TextEditingController _searchText = TextEditingController(text: "");
_search() async {
setState(() {
_searching = true;
});
Algolia algolia = const Algolia.init(
applicationId: 'XP6QXPHMDJ',
apiKey: '283351eb9d0a111a8fb4f2fdb7b8450a',
);
AlgoliaQuery query = algolia.instance.index('BusinessProfilesCollection');
query = query.query(_searchText.text);
_results = (await query.getObjects()).hits;
setState(() {
_searching = false;
});
}
#override
void initState() {
_searchText.addListener(() {
setState(() {
_search();
});
});
super.initState();
}
the Text Field Code:
TextField(
controller: _searchText,
style: GoogleFonts.lato(
fontStyle: FontStyle.normal,
color: Colors.grey[850],
fontSize: 14.sp,
),
decoration: const InputDecoration(
border: InputBorder.none,
hintText: 'Search ...',
hintStyle:
TextStyle(color: Colors.black),
)),
The Results Widget:
Container(
height: 300.h,
child: _searching == true
? Center(
child: Text("Searching, please wait..."),
)
: _results.length == 0
? Center(
child: Text("No results found."),
)
: ListView.builder(
itemCount: _results.length,
itemBuilder:
(BuildContext ctx, int index) {return ...}))
A bottom sheet doesnt update state by default. Wrap the content of the bottom sheet with a statefulbuilder
showModalBottomSheet(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState /*You can rename this!*/) {
return Container(
child: TextField(onChanged: (val) {
setState(() {
//This will rebuild the bottom sheet
});
}),
);
});
});
TextField(
onChanged: (value) {
setState(() {
//This will refresh the page
});
},
controller: _searchText,
style: GoogleFonts.lato(
fontStyle: FontStyle.normal,
color: Colors.grey[850],
fontSize: 14.sp,
),
decoration: const InputDecoration(
border: InputBorder.none,
hintText: 'Search ...',
hintStyle:
TextStyle(color: Colors.black),
),
),

Flutter: How to change variables through TextFormField in a AlertDialog?

I want to implement a function as following:
There is a button named 自定义. In this page, there is a variable named money. When I click the button, an AlertDialog with a TextFormField inside will occur. I hope that after inputting a number X into the TextFormField and clicking button ok to exit the AlertDialog, money would be changed to X. I have used onSaved to save the variable, and used _formkey.currentState.save(), but money didn't change. What's wrong with my codes? Here are my codes:
void _showMessageDialog() {
//int addMoney = 0;
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
key: _formKey,
title: new Text('INPUT'),
content: TextFormField(
maxLines: 1,
keyboardType: TextInputType.emailAddress,
autofocus: false,
style: TextStyle(fontSize: 15),
decoration: new InputDecoration(
border: InputBorder.none,
hintText: 'input',
),
onSaved: (value) {
money = int.parse(value?.trim() ?? '0') as double;
print(money);
}
),
actions: <Widget>[
new TextButton(
key: _formKey,
child: new Text("ok"),
onPressed: () {
_formKey.currentState?.save();
Navigator.of(context).pop();
},
),
],
);
},
);
}
Here are the codes relative to the button 自定义
OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(
width: 1,
color: Colors.blueAccent
)
),
onPressed: () {
// Navigator.of(context).push(
// _showMessageDialog()
// );
_showMessageDialog();
},
child: Text(
"自定义",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700,
color: Colors.blueAccent
),
),
),
I know maybe I have made a big mistake, but it is my first Flutter project. Thanks for your advices.
I would use ValueNotifier for this. But first you need to add a controller to your TextFormField so you can get the text user typed in.
//initialize it
final myController = TextEditingController();
TextFormField(
controller: myController, //pass it to the TextFormField
),
TextButton(
child: new Text("ok"),
onPressed: () {
String input = myController.text; //this is how you get the text input
_formKey.currentState?.save();
Navigator.of(context).pop();
},
),
As I said you also need to initialize ValueNotifier and pass it to _showMessageDialog
ValueNotifier<int> money = ValueNotifier(0);
_showMessageDialog(money); //and pass it to your function
void _showMessageDialog(ValueNotifier<int> money) {
TextButton(
child: new Text("ok"),
onPressed: () {
String input = myController.text; //this is how you get the text input
money.value = int.parse(input); //and then update your money variable
_formKey.currentState?.save();
Navigator.of(context).pop();
},
),
}

Flutter Flatbutton onpressend not working

I have a register page in which there are 3 input fields and on next button i need to change the input field and show the other so i have simply use boolean to show/hide input. But when i click on button its not changing the fields (Mean change the boolean to false/true) And even i try to simply add print so i can check but its not even printing the value. But if i use navigator to change page its working fine in button.
My code
class Body extends StatefulWidget {
#override
_BodyState createState() => _BodyState();
}
class _BodyState extends State<Body> {
bool first = true;
bool second = false;
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Background(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"SIGNUP",
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(height: size.height * 0.03),
SvgPicture.asset(
"assets/icons/signup.svg",
height: size.height * 0.35,
),
first ? RoundedInputField(
hintText: "Your Name",
icon: Icons.person,
onChanged: (value) {},
) : Container(),
first ? RoundedInputField(
hintText: "Your Email",
icon: Icons.mail,
onChanged: (value) {
print(value);
},
) : Container() ,
first ? RoundedPasswordField(
onChanged: (value) {},
) : Container() ,
second ? RoundedInputField(
hintText: "Your Number",
icon: Icons.phone,
onChanged: (value) {
print(value);
},
) : Container() ,
first ? Container(
margin: EdgeInsets.symmetric(vertical: 10),
width: size.width * 0.8,
child: ClipRRect(
borderRadius: BorderRadius.circular(29),
child: FlatButton(
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 40),
color: kPrimaryColor,
onPressed: (){
print('working');
setState(){
first = false;
second = true;
}
},
child: Text(
'NEXT',
style: TextStyle(color: Colors.white),
),
),
),
): Container(),
second ? RoundedButton(
text: "REGISTER",
press: () {
print('working');
},
) : Container() ,
SizedBox(height: size.height * 0.03),
AlreadyHaveAnAccountCheck(
login: false,
press: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
},
),
],
),
),
);
}
}
i am using setState to change the boolean value which isn't working also try to simply print the string but its also not working. If i use navigator in this to change page its working fine
You should declare first and second at instance level, otherwise they will created again with default values after setStateis executed.
class Body extends StatelessWidget {
bool first = true;
bool second = false;
#override
Widget build(BuildContext context) {
....
}
}
setState is used incorrectly. You need to have
setState((){
first = false;
second = true;
});
Your code is calling setState without any action and after that, you change first and second variables (but outside setState).
Your code is equivalent to
setState();
first = false;
second = true;
You should not declare again first and second inside onPressed, otherwise you'll be dealing with new variables which only scope is this method
setState((){
first = false;
second = true;
});
Your widget needs to be stateful and not stateless, otherwise it can't change the state.

How to start something automatically in flutter

I have the following code that initially displays a blank page, but I'd like an rAlert dialog to display automatically. Once the user clicks 'Request' or 'Cancel', some text will be displayed on the screen.
But I can't get the code to run that displays the Alert. I had it working by showing a button and clicking the button, but i need the Alert to display automatically when the page is displayed. I tried putting it in the initState. I didn't get any errors, but it didn't work either.
Anyone know what I need to do? Thanks?
import 'package:flutter/material.dart';
import 'package:rflutter_alert/rflutter_alert.dart';
import 'dart:async';
import 'package:rostermeon/cwidgets/general_widgets.dart';
import 'package:rostermeon/rmo_constants.dart';
class ForgotPassword extends StatefulWidget {
static const String id = 'forgot_password_screen';
#override
_ForgotPasswordState createState() => _ForgotPasswordState();
}
class _ForgotPasswordState extends State<ForgotPassword> {
StreamController<bool> _events;
#override
initState() {
super.initState();
_events = new StreamController<bool>();
doRequest(context: context);
}
Future<bool> doSaveRequest({String pReason}) async {
await Future.delayed(const Duration(seconds: 3), () {});
return false;
}
Future<bool> doRequest({context}) {
String _reason = '';
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
TextEditingController reasonController = TextEditingController();
TextStyle _style = TextStyle(fontFamily: 'Montserrat', fontSize: 18.0, fontWeight: FontWeight.normal);
InputDecoration _textFormFieldDecoration({String hintText, double padding}) => InputDecoration(
//contentPadding: EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 8.0),
contentPadding: EdgeInsets.all(padding),
isDense: true,
hintText: hintText,
hintStyle: TextStyle(color: kHintText),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(5)),
),
);
return Alert(
context: context,
title: 'Request New Password',
content: StreamBuilder<bool>(
initialData: false,
stream: _events.stream,
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
print(" ${snapshot.data.toString()}");
return snapshot.data
? CircularProgressIndicator()
: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 20.0),
Text('Email', textAlign: TextAlign.left, style: _style),
SizedBox(height: 10.0),
TextFormField(
validator: (value) {
if (value.isEmpty) {
return "please enter email";
}
return null;
},
onSaved: (value) {
_reason = value;
},
decoration: _textFormFieldDecoration(
hintText: 'your email address',
padding: 8.0,
),
controller: reasonController,
),
SizedBox(height: 10.0),
],
),
);
}),
buttons: [
DialogButton(
child: Text('Request', style: TextStyle(color: Colors.white, fontSize: 20)),
color: kMainColor,
onPressed: () async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
print(_reason);
_events.add(true);
var saved = await doSaveRequest(pReason: _reason);
if (saved) {
Navigator.pop(context, false);
} else {
_events.add(false);
}
Navigator.of(context).pop();
// Navigator.pop(context, false);
}
},
),
DialogButton(
child: Text('Cancel', style: TextStyle(color: Colors.white, fontSize: 20)),
color: kMainColor,
onPressed: () {
Navigator.pop(context, false);
},
),
],
).show();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: rmoAppBar(subText: 'Request New Password', hideBackButton: false),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[],
),
),
);
}
}
Dialogs/Alerts need the buildContext in order to work, You can't have the buildContext before build() method is called, that's why you can't just call it in initstate() before the build is called.
To make it work use addPostFrameCallback to make sure it delays until widget is built:
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => yourMethod(context));
}
https://www.didierboelens.com/2019/04/addpostframecallback/

How to disable mobile keyboard action key using Flutter?

I just need to disable the action button while the search query is empty. I'm not sure if this is possible with native Flutter.
Does this need to be done with each platform specifically? (iOS / Android)
You have a couple of options.
You can create a new focus:
FocusScope.of(context).requestFocus(new FocusNode())
Example:
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: ....,
)
)
)
}
The other option is to release the existing focus:
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
There is also a package: keyboard_dismisser
You just need to add a FocusNode to your TextFormField and request focus for it if the user presses the submit button on the keyboard when the field is empty. Here is a complete example:
class KeyboardKeeper60943209 extends StatefulWidget {
#override
_KeyboardKeeper60943209State createState() => _KeyboardKeeper60943209State();
}
class _KeyboardKeeper60943209State extends State<KeyboardKeeper60943209> {
List<String> items = List.generate(20, (index) => 'item $index');
TextEditingController _textEditingController = TextEditingController();
FocusNode _focusNode = FocusNode();
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: TextFormField(
focusNode: _focusNode,
controller: _textEditingController,
decoration: InputDecoration(
prefixIcon: Icon(Icons.search),
labelText: 'Search',
hasFloatingPlaceholder: false,
),
// This is the key part
onFieldSubmitted: (value) {
if(value == ''){
_focusNode.requestFocus();
}
},
),
),
FlatButton(onPressed: search, child: Text('Search'))
],
),
Expanded(
child: Container(
child: ListView.builder(
itemBuilder: (context, index){
return ListTile(
title: Text(items[index]),
subtitle: Text(items[index]),
);
}
),
),
),
],
);
}
void search(){
print('search');
}
}
TextFormField(
readOnly: true,
showCursor: false,
controller: consName,
decoration: InputDecoration(
hintText: 'Enter Name',
labelText: 'Username',
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.deepPurple,
width: 2,
),
),
),
),
Very Simple & Easy Use "readOnly: true" for disabling keyboard and if you don't want pointer or cursor then "showCursor: false". That's it, hope this'll work. Eat Sleep Workout Code Repeat. Happy Coding😊.
You can simply use textInputAction: TextInputAction.none on the TextField.