I'm new at Provider package. and Just making demo app for learning purpose.
Here is my code of simple Form Widget.
1) RegistrationPage (Where my app is start)
class RegistrationPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("Title"),
),
body: MultiProvider(providers: [
ChangeNotifierProvider<UserProfileProvider>.value(value: UserProfileProvider()),
ChangeNotifierProvider<RegiFormProvider>.value(value: RegiFormProvider()),
], child: AllRegistrationWidgets()),
);
}
}
class AllRegistrationWidgets extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
SetProfilePicWidget(),
RegistrationForm(),
],
),
),
),
BottomSaveButtonWidget()
],
),
),
);
}
}
class BottomSaveButtonWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final _userPicProvider =
Provider.of<UserProfileProvider>(context, listen: false);
final _formProvider =
Provider.of<RegiFormProvider>(context, listen: false);
return SafeArea(
bottom: true,
child: Container(
margin: EdgeInsets.all(15),
child: FloatingActionButton.extended(
heroTag: 'saveform',
icon: null,
label: Text('SUBMIT',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
)),
onPressed: () {
print(_userPicProvider.strImageFileName);
_formProvider.globalFormKey.currentState.validate();
print(_formProvider.firstName);
print(_formProvider.lastName);
},
)),
);
}
}
2) RegistrationForm
class RegistrationForm extends StatefulWidget {
@override
_RegistrationFormState createState() => _RegistrationFormState();
}
class _RegistrationFormState extends State<RegistrationForm> {
TextEditingController _editingControllerFname;
TextEditingController _editingControllerLname;
@override
void initState() {
_editingControllerFname = TextEditingController();
_editingControllerLname = TextEditingController();
super.initState();
}
@override
Widget build(BuildContext context) {
final formProvider = Provider.of<RegiFormProvider>(context);
return _setupOtherWidget(formProvider);
}
_setupOtherWidget(RegiFormProvider _formProvider) {
return Container(
padding: EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
SizedBox(height: 20),
Text(
'Fields with (*) are required.',
style: TextStyle(fontStyle: FontStyle.italic),
textAlign: TextAlign.left,
),
SizedBox(height: 20),
_formSetup(_formProvider)
],
),
);
}
_formSetup(RegiFormProvider _formProvider) {
return Form(
key: _formProvider.globalFormKey,
child: Container(
child: Column(
children: <Widget>[
TextFormField(
controller: _editingControllerFname,
textCapitalization: TextCapitalization.sentences,
decoration: InputDecoration(
labelText: "First Name *",
hintText: "First Name *",
),
onSaved: (value) {},
validator: (String value) =>
_formProvider.validateFirstName(value)),
SizedBox(height: 15),
TextFormField(
controller: _editingControllerLname,
textCapitalization: TextCapitalization.sentences,
validator: (String value) =>
_formProvider.validateLastName(value),
onSaved: (value) {},
decoration: InputDecoration(
labelText: "Last Name *",
hintText: "Last Name *",
),
)
],
),
),
);
}
@override
void dispose() {
_editingControllerFname.dispose();
_editingControllerLname.dispose();
super.dispose();
}
}
3) RegiFormProvider
class RegiFormProvider with ChangeNotifier {
final GlobalKey<FormState> globalFormKey = GlobalKey<FormState>();
String _strFirstName;
String _strLasttName;
String get firstName => _strFirstName;
String get lastName => _strLasttName;
String validateFirstName(String value) {
if (value.trim().length == 0)
return 'Please enter first name';
else {
_strFirstName = value;
return null;
}
}
String validateLastName(String value) {
if (value.trim().length == 0)
return 'Please enter last name';
else {
_strLasttName = value;
return null;
}
}
}
Here you can see, RegiFormProvider
is my first page where other is children widgets in widget tree. I'm using final GlobalKey<FormState> globalFormKey = GlobalKey<FormState>();
in the RegiFormProvider
provider, Because I want to access this in the 1st RegistrationPage
to check my firstName and lastName is valid or not.
I'm using a builder widget to get form level context like below , and then easily we can get the form instance by using that context. by this way we don't need global key anymore.
Form(
child: Builder(
builder: (ctx) {
return ListView(
padding: EdgeInsets.all(12),
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: "Title"),
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
initialValue: formProduct.title,
validator: validateTitle,
onSaved: (value) {
formProduct.title = value;
},
),
TextFormField(
decoration: InputDecoration(labelText: "Price"),
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
initialValue: formProduct.price == null
? ""
: formProduct.price.toString(),
keyboardType: TextInputType.number,
validator: validatePrice,
onSaved: (value) {
formProduct.price = double.parse(value);
},
),
TextFormField(
decoration: InputDecoration(labelText: "Description"),
textInputAction: TextInputAction.next,
initialValue: formProduct.description,
maxLines: 3,
validator: validateDescription,
onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
onSaved: (value) {
formProduct.description = value;
},
),
TextFormField(
decoration: InputDecoration(labelText: "Image Url"),
textInputAction: TextInputAction.done,
onFieldSubmitted: (_) => FocusScope.of(context).unfocus(),
initialValue: formProduct.imageUrl,
validator: validateImageUrl,
onSaved: (value) {
formProduct.imageUrl = value;
},
),
Padding(
padding: EdgeInsets.all(10),
child: FlatButton(
color: Colors.amberAccent,
onPressed: () {
if (Form.of(ctx).validate()) {
Form.of(ctx).save();
formProduct.id =
Random.secure().nextDouble().toString();
ProductsProvider provider =
Provider.of<ProductsProvider>(context,
listen: false);
editing
? provider.setProduct(formProduct)
: provider.addProduct(formProduct);
Router.back(context);
}
},
child: Text("Save"),
),
)
],
);
},
),
)
you can see the Form.of(ctx)
gives us the current level form.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With