flutter_form_bloc 0.2.1 flutter_form_bloc: ^0.2.1 copied to clipboard
Flutter widgets that make it easy to create forms with form_bloc.
flutter_form_bloc #
A Flutter package with flutter widgets that helps to create forms with form_bloc package.
To see complex examples check the example project.
Before to use this package you need to know the core concepts of bloc package and the basics of flutter_bloc
Widgets #
- TextFieldBlocBuilder
<Error>
- DropdownFieldBlocBuilder
<Value>
- RadioButtonGroupFieldBlocBuilder
<Value>
- CheckboxFieldBlocBuilder
- FormBlocListener
Note #
FormBloc
, TextFieldBloc
, SelectFieldBloc
, FileFieldBloc
and BooleanFieldBloc
are blocs, so you can use BlocBuilder
or BlocListener
of flutter_bloc for make any widget you want compatible with any FieldBloc
or FormBloc
.
If you want me to add other widgets please let me know, or make a pull request.
Example #
dependencies:
form_bloc: ^0.3.0
flutter_form_bloc: ^0.2.0
flutter_bloc: ^0.21.0
import 'package:form_bloc/form_bloc.dart';
class SimpleLoginFormBloc extends FormBloc<String, String> {
final emailField = TextFieldBloc<String>(
validators: [Validators.validEmail],
);
final passwordField = TextFieldBloc<String>(
validators: [Validators.notEmpty],
);
@override
List<FieldBloc> get fieldBlocs => [emailField, passwordField];
@override
Stream<FormBlocState<String, String>> onSubmitting() async* {
// Login logic...
await Future<void>.delayed(Duration(seconds: 2));
yield currentState.toSuccess();
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
import 'package:flutter_form_bloc_example/forms/simple_login_form_bloc.dart';
import 'package:flutter_form_bloc_example/widgets/widgets.dart';
class SimpleLoginForm extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider<SimpleLoginFormBloc>(
builder: (context) => SimpleLoginFormBloc(),
child: Builder(
builder: (context) {
final formBloc = BlocProvider.of<SimpleLoginFormBloc>(context);
return Scaffold(
appBar: AppBar(title: Text('Simple login')),
body: FormBlocListener<SimpleLoginFormBloc, String, String>(
onSubmitting: (context, state) => LoadingDialog.show(context),
onSuccess: (context, state) {
LoadingDialog.hide(context);
Navigator.of(context).pushReplacementNamed('success');
},
onFailure: (context, state) {
LoadingDialog.hide(context);
Notifications.showSnackBarWithError(
context, state.failureResponse);
},
child: ListView(
children: <Widget>[
TextFieldBlocBuilder<String>(
textFieldBloc: formBloc.emailField,
formBloc: formBloc,
errorBuilder: (context, error) => error,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email),
),
),
TextFieldBlocBuilder<String>(
textFieldBloc: formBloc.passwordField,
formBloc: formBloc,
errorBuilder: (context, error) => error,
suffixButton: SuffixButton.obscureText,
decoration: InputDecoration(
labelText: 'Password',
prefixIcon: Icon(Icons.lock),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: formBloc.submit,
child: Center(child: Text('LOGIN')),
),
),
],
),
),
);
},
),
);
}
}
Basic usage #
1. Import it #
import 'package:form_bloc/form_bloc.dart';
2. Create a class that extends FormBloc<SuccessResponse, FailureResponse> #
FormBloc<SuccessResponse, FailureResponse>
SuccessResponse
The type of the success response.
FailureResponse
The type of the failure response.
For example, the SuccessResponse
type and FailureResponse
type of SimpleLoginFormBloc
will be String
.
import 'package:form_bloc/form_bloc.dart';
class SimpleLoginFormBloc extends FormBloc<String, String> {}
2. Create Field Blocs #
You need to create field blocs, and these need to be final.
You can create:
For example the SimpleLoginFormBloc
will have two TextFieldBloc<String>
, so the Error
type will be String
, and the validators must return a error of String
type.
import 'package:form_bloc/form_bloc.dart';
class SimpleLoginFormBloc extends FormBloc<String, String> {
final emailField = TextFieldBloc<String>(
validators: [Validators.validEmail],
);
final passwordField = TextFieldBloc<String>(
validators: [Validators.notEmpty],
);
}
3. Implement the get method fieldBlocs #
You need to override the get method fieldBlocs and return a list with all FieldBlocs
.
For example the SimpleLoginFormBloc
must return a List with emailField
and passwordField
.
import 'package:form_bloc/form_bloc.dart';
class SimpleLoginFormBloc extends FormBloc<String, String> {
final emailField = TextFieldBloc<String>(
validators: [Validators.validEmail],
);
final passwordField = TextFieldBloc<String>(
validators: [Validators.notEmpty],
);
@override
List<FieldBloc> get fieldBlocs => [emailField, passwordField];
}
4. Implement onSubmitting method #
onSubmitting return a Stream<FormBlocState<SuccessResponse, FailureResponse>>
and will called when the form is submitting.
You must call all your business logic of this form here, and yield
the corresponding state.
You can yield a new state using:
- currentState.toFailure([FailureResponse failureResponse])
- currentState.toSuccess([SuccessResponse successResponse])
- currentState.toLoaded()
For example onSubmitting
of SimpleLoginFormBloc
will return a Stream<FormBlocState<String, String>>
and yield currentState.toSuccess()
.
import 'package:form_bloc/form_bloc.dart';
class SimpleLoginFormBloc extends FormBloc<String, String> {
final emailField = TextFieldBloc<String>(
validators: [Validators.validEmail],
);
final passwordField = TextFieldBloc<String>(
validators: [Validators.notEmpty],
);
@override
List<FieldBloc> get fieldBlocs => [emailField, passwordField];
@override
Stream<FormBlocState<String, String>> onSubmitting() async* {
// Login logic...
await Future<void>.delayed(Duration(seconds: 2));
yield currentState.toSuccess();
}
}
5. Create a Form Widget #
You need to create a widget with access to the FormBloc
.
In this case I will use BlocProvider
for do it.
class SimpleLoginForm extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider<SimpleLoginFormBloc>(
builder: (context) => SimpleLoginFormBloc(),
child: Builder(
builder: (context) {
final formBloc = BlocProvider.of<SimpleLoginFormBloc>(context);
return Scaffold();
},
),
);
}
}
6. Add FormBlocListener for manage form state changes #
You need to add a FormBlocListener
.
In this example:
- I will show a loading dialog when the state is loading.
- I will hide the dialog when the state is success, and navigate to success screen.
- I will hide the dialog when the state is failure, and show a snackBar with the error.
...
return Scaffold(
appBar: AppBar(title: Text('Simple login')),
body: FormBlocListener<SimpleLoginFormBloc, String, String>(
onSubmitting: (context, state) => LoadingDialog.show(context),
onSuccess: (context, state) {
LoadingDialog.hide(context);
Navigator.of(context).pushReplacementNamed('success');
},
onFailure: (context, state) {
LoadingDialog.hide(context);
Notifications.showSnackBarWithError(
context, state.failureResponse);
},
child:
),
),
);
...
6. Connect the Field Blocs with Field Blocs Builder #
In this example I will use TextFieldBlocBuilder<String>
for connect with emailField
and passwordField
of SimpleLoginFormBloc
.
...
child: ListView(
children: <Widget>[
TextFieldBlocBuilder<String>(
textFieldBloc: formBloc.emailField,
formBloc: formBloc,
errorBuilder: (context, error) => error,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email),
),
),
TextFieldBlocBuilder<String>(
textFieldBloc: formBloc.passwordField,
formBloc: formBloc,
errorBuilder: (context, error) => error,
suffixButton: SuffixButton.obscureText,
decoration: InputDecoration(
labelText: 'Password',
prefixIcon: Icon(Icons.lock),
),
),
],
),
...
7. Add a widget for submit the FormBloc #
In this example I will add a RaisedButton
and pass submit
method of FormBloc
to submit the form
...
child: ListView(
children: <Widget>[
...,
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: formBloc.submit,
child: Center(child: Text('LOGIN')),
),
),
],
),
...
Credits #
This package uses the following packages: