My task was to add button Done to text keyboard which hides keyboard after CupertinoTextField is filled with value. I used keyboard_actions lib and it worked fine, but the area of FormKeyboardActions() widget became unscrollable - scrolling is broken after my implementation of
keyboard_actions lib.
I tried to add directly CupertinoTextField to FormKeyboardActions() as a child, but it is also not working.
The code of parent PageTemplate widget:
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: Scaffold(
body: FormKeyboardActions(
child: SafeArea( //child
child: Padding(
padding: DesignPadding.V16__X,
child: ListView(
shrinkWrap: true,
children: this.children
),
),
),
),
floatingActionButton: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 8),
child: this.floatingActionButton,
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
),
);
}
The widget with CupertinoTextField:
class _ProductEditCommentState extends State<ProductEditComment> {
final FocusNode focusNode = FocusNode(skipTraversal: true);
KeyboardActionsConfig _buildConfig(BuildContext context) {
return KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.ALL,
keyboardBarColor: Colors.grey[200],
nextFocus: false,
actions: [
KeyboardAction(
focusNode: focusNode,
closeWidget: Padding(
padding: DesignPadding.V8__X,
child: Text(
"Done",
style: TextStyle(
color: DesignColors.BLACK,
fontSize: DesignFonts.FONT_SIZE__16,
fontFamily: DesignFonts.FONT_FAMILY__MEDIUM,
),
),
),
),
],
);
}
#override
void initState() {
FormKeyboardActions.setKeyboardActions(context, _buildConfig(context));
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
ProductEditBloc bloc = BlocProvider.of(context);
return SingleChildScrollView(
child: CupertinoTextField(
focusNode: focusNode,
maxLines: null,
onChanged: this.widget.onChanged,
controller: this.widget.controller,
keyboardType: TextInputType.multiline,
decoration: BoxDecoration(border: null),
textCapitalization: TextCapitalization.sentences,
placeholder: bloc.productComment == null || bloc.productComment.isEmpty
? "Добавить заметку"
: bloc.productComment,
placeholderStyle: TextStyle(
color: DesignColors.GREY_CHROME,
fontSize: DesignFonts.FONT_SIZE__14,
fontFamily: DesignFonts.FONT_FAMILY__REGULAR),
style: TextStyle(
color: DesignColors.GREY_COAL,
fontSize: DesignFonts.FONT_SIZE__14,
fontFamily: DesignFonts.FONT_FAMILY__REGULAR),
padding: EdgeInsets.only(
left: DesignPadding.V10,
top: DesignPadding.V14,
bottom: DesignPadding.V20,
),
),
);
}
}
The implementation of ProductEditComment widget:
#override
Widget build(BuildContext context) {
return BlocProvider(
bloc: bloc,
child: PageTemplate(
children: <Widget>[
Heading(
title: "Заметка",
style: DesignFonts.STYLE_TITLE,
),
StreamBuilder<String>(
stream: bloc.outComment,
initialData: this.widget.product?.comment,
builder: (context, snapshot) {
return ProductEditComment(
name: snapshot.data,
onChanged: bloc.setComment,
controller: bloc.commentController,
);
}),
]
)
Related
My code includes FutureBuilder(), which get data from Firestore, and its child widgets include GridView.builder and TextField widgets etc.
When I click on a TexField(focus), the codes in FutureBuilder are rebuild.
The following is the test code for this.
Can you tell me the cause and solution of this problem?
class TestRoom extends StatefulWidget {
TestRoom({Key? key}) : super(key: key);
#override
State<TestRoom> createState() => _TestRoomState();
}
class _TestRoomState extends State<TestRoom> {
List<RoomModel> _roomModels = [];
TextEditingController _textEditingController = TextEditingController();
bool _isTablet = false;
#override
void dispose() {
_textEditingController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
if (size.width >= 800) {
_isTablet = true;
} else {
_isTablet = false;
}
return Scaffold(
appBar: AppBar(),
body: Padding(
padding: EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Test",
style: TextStyle(
fontSize: 35,
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 20,
),
FutureBuilder(
future: _getAllRoom(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Expanded(
child: TestList1(
isTablet: _isTablet,
roomModels: _roomModels,
isListStyle1: true,
));
},
),
],
),
),
);
}
// get user's models from firestore
Future _getAllRoom() async {
_roomModels.clear();
_roomModels.addAll(await RoomService().getAllRoomModel("userName"));
}
}
//
//
class TestList1 extends StatefulWidget {
final isTablet;
final List<RoomModel> roomModels;
final bool isListStyle1;
TestList1({
Key? key,
required this.isTablet,
required this.roomModels,
required this.isListStyle1,
}) : super(key: key);
#override
State<TestList1> createState() => _TestList1State();
}
class _TestList1State extends State<TestList1> {
TextEditingController _textEditingController = TextEditingController();
double _paddingSize = 40.0;
#override
void dispose() {
// _textEditingController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return GridView.builder(
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: widget.isTablet ? 6 : 3,
childAspectRatio: 1 / 1.5,
mainAxisSpacing: _paddingSize,
crossAxisSpacing: 10,
),
itemBuilder: (context, index) {
return _buildMyRooms(widget.roomModels[index], index);
},
itemCount: widget.roomModels.length,
);
}
Widget _buildMyRooms(RoomModel roomModel, int index) {
return Column(
children: [
InkWell(
onTap: () {},
child: Container(
width: 120,
height: 168,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.blue,
width: 2.0,
),
borderRadius: const BorderRadius.all(
Radius.circular(10),
),
),
),
),
SizedBox(
height: sm_padding,
),
PopupMenuButton<int>(
color: Colors.grey[100],
itemBuilder: (context) => _fileMenuItemLust(roomModel),
onSelected: _onSeletedFileMenu,
child: Column(
children: [
Container(
width: 130,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Flexible(
child: Text(
roomModel.roomName,
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: const TextStyle(
color: Colors.blue,
fontSize: 15,
),
),
),
const Icon(
Icons.arrow_drop_down_outlined,
color: Colors.blue,
),
],
),
),
],
),
)
],
);
}
// 파일 메뉴 아이템
List<PopupMenuEntry<int>> _fileMenuItemLust(RoomModel roomModel) {
_textEditingController.text = roomModel.roomName;
return [
// 파일명
PopupMenuItem(
enabled: false,
// TODO textfield
child: TextField(
controller: _textEditingController,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
maxLines: 1,
decoration: InputDecoration(
border: _textFieldBorder(),
enabledBorder: _textFieldBorder(),
disabledBorder: _textFieldBorder(),
focusedBorder: _textFieldBorder(),
focusColor: Colors.white60,
filled: true,
fillColor: Colors.grey.withOpacity(0.3),
isDense: true, // padding 조절을 위해 추가
contentPadding: EdgeInsets.all(sm_padding),
)),
),
const PopupMenuDivider(),
PopupMenuItem(
value: 0,
child: Row(
children: [
const Icon(
Icons.copy,
),
SizedBox(
width: sm_padding,
),
const Text(
"Menu Item1",
),
],
),
),
];
}
void _onSeletedFileMenu(value) {}
OutlineInputBorder _textFieldBorder() {
return OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
borderSide: BorderSide(
color: Colors.grey.withOpacity(0.3),
width: 1,
),
);
}
}
// ======================
I modified the code based on Yeasin Sheikh's answer.
The existing problem has been solved, but a new problem has arisen.
I'm going to update the Firestore using onSubmitted() of TextField and then update my list using stream builder and future builder.
This is a modified part of the code above to solve an existing problem
class _TestRoomState extends State<TestRoom> {
late final myFuture = _getAllRoom(); // new
FutureBuilder(
future: myFuture, //_getAllRoom(), // change
The problem of constantly rebuilding the text field according to the focus has disappeared, but there is a problem that getAllRoom() is called only at the first time and cannot be called afterwards, so the new room list cannot be updated.
Here future: _getAllRoom() calls the api on every state changes.
Create a state variable for future
late final myFuture = _getAllRoom();
#override
Widget build(BuildContext context) {
And use
FutureBuilder(
future:myFuture ,
You can check Fixing a common FutureBuilder and StreamBuilder problem
How can i show text fields based on user inputs when the button is pressed?
You can find in the screen shot i'm trying to do.
here is the code:
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
final textController = TextEditingController();
void showTextFields(){
TextField();
}
return Scaffold(
appBar: AppBar(
),
body: Center(
child: Column(
children: [
SizedBox(height: 50,),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20.0),
child: TextField(
controller: textController,
decoration: InputDecoration(
labelText: 'Text fields number'
),
),
),
SizedBox(height: 10,),
ElevatedButton(
onPressed: showTextFields,
child: Text('Press to show text field')
),
],
),
),
);
}
}
I hope my help will be of use to you, greetings
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey _parentKey = GlobalKey();
int countItems = 0;
late TextEditingController textController;
#override
void initState() {
super.initState();
textController = TextEditingController();
}
#override
Widget build(BuildContext context) {
void showTextFields() {
setState(() {
countItems = int.parse(textController.text);
});
}
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
children: [
const SizedBox(
height: 50,
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20.0),
child: TextField(
controller: textController,
decoration:
const InputDecoration(labelText: 'Text fields number'),
),
),
const SizedBox(
height: 10,
),
ElevatedButton(
onPressed: showTextFields,
child: const Text('Press to show text field')),
const SizedBox(
height: 10,
),
(countItems > 0)
? Flexible(
child: ListView.builder(
itemCount: countItems,
itemBuilder: (BuildContext context, int index) {
return TextField(
style: TextStyle(color: Colors.white),
cursorColor: Colors.white,
textAlign: TextAlign.center,
decoration: InputDecoration(
hintText: "TextField " + index.toString(),
hintStyle: TextStyle(color: Colors.grey[400]),
),
);
}),
)
: const SizedBox()
],
),
),
);
}
}
You can this code, Firstly you must to change stateless to StatefullWidget
and then examine to blow code
class ShowTextFieldValue extends StatefulWidget {
const ShowTextFieldValue({ Key? key }) : super(key: key);
#override
_ShowTextFieldValueState createState() => _ShowTextFieldValueState();
}
class _ShowTextFieldValueState extends State<ShowTextFieldValue> {
#override
Widget build(BuildContext context) {
final textController = TextEditingController();
String value = "";
return Scaffold(
appBar: AppBar(
),
body: Center(
child: Column(
children: [
SizedBox(height: 50,),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20.0),
child: TextField(
controller: textController,
decoration: InputDecoration(
labelText: 'Text fields number'
),
),
),
SizedBox(height: 200,width: 200,
child: Center( child: Text(value)),
),
ElevatedButton(
onPressed: (){
setState(() {
value= textController.text;
});
},
child: Text('Press to show text field')
),
],
),
),
);
}
}
I have a Single child scroll view with child container which I defined the height and width
The problem is when I click on textfield the button is hidden/does not go up. How do I make the height responsive?
#override
Widget build(BuildContext context) {
_width = MediaQuery.of(context).size.width;
_height = MediaQuery.of(context).size.height;
return SingleChildScrollView(
controller: _scrollController,
child: Container(
width: _width,
height: _height,
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: StreamBuilder(
stream: userBloc.user$,
builder: (BuildContext context, AsyncSnapshot snapshot) {
User user = snapshot?.data;
String maskedEmail = _getMaskedEmail(user);
return Column(
children: <Widget>[
widget.instruction != null
? Container(
padding: GenericAssets.paddingSymV10,
child: Text(
widget.instruction,
style: GenericAssets.defaultText,
textAlign: TextAlign.center,
))
: Container(),
(maskedEmail?.isNotEmpty ?? false)
? Column(
children: <Widget>[
Padding(
padding: GenericAssets.paddingSymV10,
child: Text(
S.of(context).strProvideMaskedEmail,
style: GenericAssets.defaultText,
textAlign: TextAlign.center),
),
Padding(
padding: GenericAssets.paddingSymV10,
child: Text(maskedEmail,
style: GenericAssets.defaultText,
textAlign: TextAlign.center),
)
],
)
: Container(),
Container(
child: TextFormField(
style: GenericAssets.defaultText18,
controller: _emailController,
focusNode: _emailFocusNode,
keyboardType: TextInputType.emailAddress,
inputFormatters: [LowerCaseTextFormatter()],
decoration: InputDecoration(
labelText:
S.of(context).fieldEmail.toUpperCase(),
labelStyle: GenericAssets.textFormLabel,
contentPadding:
GenericAssets.textFormFieldSpacing),
validator: (value) {
if (value.isEmpty) {
return S.of(context).msgTextFieldMandatory(
S.of(context).fieldEmail);
}
if (!isEmail(value) ||
!HelperFunctions.isPatternValid(
ProjectConstants.emailPattern, value)) {
return S.of(context).msgPleaseEnterAValidValue(
S.of(context).fieldEmail);
}
return null;
},
),
),
Padding(
padding: GenericAssets.paddingSymV5,
child: PasswordField(
_passwordController,
checkFormat: false,
showPassword: true,
focusNode: _passwordFocusNode,
),
)
],
);
},
),
),
FullWidthButton(
S.of(context).strLogin,
() async {
LoggerService.log(
LogEventType.ButtonPress,
LogDetails(
buttonName: 'Login', displayName: 'Login Screen'));
if (_formKey.currentState.validate()) {
widget.onSubmit(context, widget.authenticationManager,
_passwordController.text, _emailController.text);
}
},
),
InkWell(
onTap: onForgotPassword,
child: Padding(
padding: GenericAssets.padding10,
child: Text(
S.of(context).strForgotPassword,
style: GenericAssets.footNoteLink,
),
),
),
InkWell(
onTap: onResetApp,
child: Padding(
padding: GenericAssets.padding10,
child: Text(
S.of(context).btnResetApplication,
style: GenericAssets.footNoteLink,
),
),
)
],
),
),
),
);
}
I want to show the buttons and other widgets when keyboard is shown.
This is a widget I'm calling it from
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () => HelperFunctions.logBackpress('Login Screen'),
child: Scaffold(
appBar: AppBar(title: AppBarTitle(S.of(context).strLogin)),
body: StreamBuilder(
stream: manager.loginState$,
builder: (BuildContext context, AsyncSnapshot snapshot) {
bool isLoading = snapshot?.data?.isLoading ?? false;
return Stack(
children: <Widget>[
LoginForm(onSubmit, authenticationManager: manager),
LoadingIndicator(isLoading)
],
);
},
),
),
);
}
I'm working on flutter project and came across a problem. the textfield supposed to take a value from controller which work perfectly but onChanged function wont work. However it is not working.i must retype value to show results .
how can i get result from onchanged when my textfield brings the value ?
code:
// search function that call api
class _SearchPageTState extends State<SearchPageT> {
GlobalState _store = GlobalState.instance;
List<dynamic> searchResults = [];
searchT(value) async {
SearchServicet.searchApiT(value).then((responseBody) {
List<dynamic> data = jsonDecode(responseBody);
setState(() {
data.forEach((value) {
searchResults.add(value);
});
});
});
}
#override
///////
//code textfield search onchanged
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
centerTitle: true,
),
body: ListView(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10.0),
child: TextField(
autofocus: true,
controller: TextEditingController()
..text = '${_store.get('num')}',
onChanged: (value) {
searchResults.clear();
searchCodeighniterT(value);
},
textAlign: TextAlign.center,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 25.0),
labelText: 'number',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0),
),
suffixIcon: IconButton(
icon: Icon(Icons.search),
onPressed: null,
),
),
),
),
SizedBox(
height: 10.0,
),
ListView.builder(
physics: ScrollPhysics(),
shrinkWrap: true,
itemCount: searchResults.length,
itemBuilder: (BuildContext context, int index) {
return buildResultCard(context, searchResults[index]);
},
),
],
),
),
);
}
//here where shows the result
Widget buildResultCard(BuildContext context, data) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
new Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/bgwlgo.png"), fit: BoxFit.cover),
),
margin: EdgeInsets.all(5.0),
child: Column(
children: <Widget>[
new Card(
child: ListTile(
title: Text(
"DATE:",
),
subtitle: Text(
data['DATETIME'].toString(),
),
),
),
new Card(
child: ListTile(
title: Text(
"TRAITEMENT:",
),
subtitle: Text(
data['TRAITEMENT_DETAIL'].toString()
),
),
),
new Padding(
padding: EdgeInsets.all(9.0),
),
],
),
),
Divider(
color: Colors.black,
)
],
),
);
}
As discussed and understood in the comments, here are a couple of possible solutions for the issue.
If you are using a stateful Widget and need a controller for your TextFormField, you can use it to set the text on the TextFormField. Otherwise, you can just use the initialValue property:
class TextFieldIssue64061076 extends StatelessWidget {
final TextEditingController _textEditingController = TextEditingController();
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children:[
Text('Page 1'),
TextFormField(
controller: _textEditingController,
),
FlatButton(
child: Text('Submit'),
onPressed: () => Navigator.of(context).push(MaterialPageRoute(
builder: (context) {
return SecondPage64061076(text: _textEditingController.text);
}
)),
),
],
);
}
}
class SecondPage64061076 extends StatefulWidget {
final String text;
SecondPage64061076({
this.text
});
#override
_SecondPage64061076State createState() => _SecondPage64061076State();
}
class _SecondPage64061076State extends State<SecondPage64061076> {
final TextEditingController _textEditingController = TextEditingController();
#override
void initState() {
// You can either use a text controller to set the text on the text field
// or the initialValue below
if(widget.text != null && widget.text != ''){
_textEditingController.text = widget.text;
methodToCallOnChanged(widget.text);
}else{
_textEditingController.text = '';
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Page 2'),
TextFormField(
controller: _textEditingController,
onChanged: (value) => methodToCallOnChanged(value),
// As mentioned you could just use the initial value, it you don't need
// a Stateful Widget
// initialValue: widget.text ?? '',
),
]
),
);
}
void methodToCallOnChanged(data){
print('I was called onChange or when the view opened and there was data');
}
}
Widget build(BuildContext context) {
bool isRecording = false;
bool isShowSendButton = false;
/// make sure textcontroller and any variabloes or booleans are not defined
///in the build method
}
You can't be using the constructor of the TextEditingController and assign it to the controller.
The controller of the TextField only takes the variable assigned to the TextEditingController. Check the following code.
controller:theNameOfYourController
Expanded(
flex: 8,
child: Padding(
padding: const EdgeInsets.only(left: 8.0, right: 10),
child: TextFormField(
onChanged: (value){
messageFieldController.text=value;
},
//controller: messageFieldController,
minLines: 1,
maxLines: 2,
textCapitalization: TextCapitalization.sentences,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
prefixIcon: IconButton(
onPressed: () {},
icon: const Icon(Icons.add, color: Colors.blue),
),
suffixIcon: processing == true
? const CircularProgressIndicator()
: IconButton(
onPressed: () {
try {
/*for (int i = 0;
i < widget.selectedMembers.length;
i++) {
sendMessage(
widget.selectedMembers[i].number);
}*/
for (int i = 0;
i < widget.selectedGroups.length;
i++) {
if (widget.selectedGroups.isNotEmpty) {
sendMessageToGroup(
widget.selectedGroups[i].id,
widget.selectedGroups[i].groupName);
}
}
} catch (err) {
Fluttertoast.showToast(
msg: 'Unable to send Message');
setState(() {
processing = false;
});
}
},
icon:
const Icon(Icons.send, color: Colors.blue),
),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(50),
),
),
),
),
),
)
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Column(
children: <Widget>[
_myAppBar(context),
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height - 80,
child: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return Stack(children: <Widget>[
// The containers in the background
Column(children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 8.0, right: 8.0),
child: Container(
width: MediaQuery.of(context).size.width,
height: 80.0,
child: Padding(
padding: EdgeInsets.only(top: 8.0, bottom: 8.0),
child: Material(
color: Colors.white,
elevation: 14.0,
shadowColor: Color(0x802196F3),
child: Center(
child: GestureDetector(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'${items[index].name}',
style: TextStyle(
color: Colors.black,
fontSize: 20.0),
),
],
),
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => EditRetailer(items[index])));
},
),
),
),
),
),
),
]),
]);
}),
),
],
),
floatingActionButton: FloatingActionButton(
backgroundColor: Color(0xFFFA7397),
child: Icon(
FontAwesomeIcons.listUl,
color: Color(0xFFFDDE42),
),
onPressed: () {
//Navigator.push(context,MaterialPageRoute(builder: (context) => TaskScreen()),
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RetailerScreen(Retailer('', '', '', '')),
fullscreenDialog: true),
);
},
),
);
}
The problem occurred when i add this line of code into my above widget :
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => EditRetailer(items[index])));
},
My editRetailer.dart code
class EditRetailer extends StatefulWidget {
final Retailer retailer;
EditRetailer([this.retailer]);
#override
_EditRetailerState createState() => _EditRetailerState();
}
class _EditRetailerState extends State<EditRetailer> {
final nameController = TextEditingController();
final phoneController = TextEditingController();
final gstController = TextEditingController();
final addressController = TextEditingController();
#override
void dispose() {
nameController.dispose();
phoneController.dispose();
gstController.dispose();
addressController.dispose();
super.dispose();
}
#override
void initState() {
if (widget.retailer == null) {
//New Record
nameController.text = "";
phoneController.text = "";
gstController.text = "";
addressController.text = "";
new Future.delayed(Duration.zero, () {
final retailerProvider = Provider.of<RetailerProvider>(context,listen: false);
retailerProvider.loadValues(Retailer(null,null,null,null));
});
} else {
//Controller Update
nameController.text=widget.retailer.name;
phoneController.text=widget.retailer.phone;
gstController.text=widget.retailer.gst;
addressController.text=widget.retailer.address;
//State Update
new Future.delayed(Duration.zero, () {
final retailerProvider = Provider.of<RetailerProvider>(context,listen: false);
retailerProvider.loadValues(widget.retailer);
});
}
super.initState();
}
#override
Widget build(BuildContext context) {
final retailerProvider = Provider.of<RetailerProvider>(context);
return Scaffold(
appBar: AppBar(title: Text('Edit Retailer')),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
TextField(
controller: nameController,
decoration: InputDecoration(hintText: 'Retailer Name'),
onChanged: (value) {
retailerProvider.changeName(value);
},
),
TextField(
controller: phoneController,
decoration: InputDecoration(hintText: 'Retailer Phone'),
onChanged: (value) => retailerProvider.changePhone(value),
),
TextField(
controller: gstController,
decoration: InputDecoration(hintText: 'Retailer GST'),
onChanged: (value) => retailerProvider.changeGst(value),
),
TextField(
controller: addressController,
decoration: InputDecoration(hintText: 'Retailer Address'),
onChanged: (value) => retailerProvider.changeAddress(value),
),
SizedBox(
height: 20.0,
),
RaisedButton(
child: Text('Save'),
onPressed: () {
retailerProvider.saveRetailer();
Navigator.of(context).pop();
},
),
(widget.retailer !=null) ? RaisedButton(
color: Colors.red,
textColor: Colors.white,
child: Text('Delete'),
onPressed: () {
retailerProvider.removeProduct(widget.retailer.gst);
Navigator.of(context).pop();
},
): Container(),
],
),
),
);
}
}
This is the error im getting while running the app.
Error: Could not find the correct Provider<RetailerProvider> above this EditRetailer Widget
This likely happens because you used a `BuildContext` that does not include the provider
of your choice. There are a few common scenarios:
- The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
- You used a `BuildContext` that is an ancestor of the provider you are trying to read.
Make sure that EditRetailer is under your MultiProvider/Provider<RetailerProvider>.
This usually happen when you are creating a provider and trying to read it immediatly.