-
Notifications
You must be signed in to change notification settings - Fork 207
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ability to provide TextEditingController #180
Comments
Did you manage to use "any" widget? |
Has anyone found a workaround for this? I also need this. |
@DuckMouse what are you trying to achieve? |
Hi @aaassseee, I have a screen that handles some editing. On this widget, I have multiple fields and a Focusnode that keeps track of which field currently has focus. One of those fields, is a Narration field. |
@DuckMouse Currently, TextFieldBlocBuilder doesn't expose TextEditingController to public due to prevent unpredictable behavior. If controller is exposed to public, weird things may happened. For example, although the text field bloc value is 'sample', programmer can change the value by controller instead of passing data by bloc without affecting the bloc value. We need to block this behavior in the library point of view. However, there is a way to fulfill your needs. Due to bloc and layout is separated in this library, you can actually implement text field bloc by your own widget. TextFieldBlocBuilder(
textFieldBloc: loginFormBloc.email,
keyboardType: TextInputType.emailAddress,
autofillHints: const [
AutofillHints.username,
],
decoration: const InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email),
),
), after BlocBuilder<TextFieldBloc, TextFieldBlocState>(
bloc: loginFormBloc.email,
builder: (context, state) {
return TextField(
controller: controller,
keyboardType: TextInputType.emailAddress,
autofillHints: const [
AutofillHints.username,
],
decoration: InputDecoration(
labelText: 'Email',
prefixIcon: const Icon(Icons.email),
errorText: state.canShowError
? FieldBlocBuilder.defaultErrorBuilder(
context,
state.error!,
loginFormBloc.email,
)
: null,
),
onChanged: (value) {
loginFormBloc.email.updateValue(value);
},
);
},
), Custom Textfield with bloc builder will let you get full control on TextEditingController but remember you need to know what you are doing. Full code: import 'package:flutter/material.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
void main() => runApp(const App());
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: LoginForm(),
);
}
}
class LoginFormBloc extends FormBloc<String, String> {
final email = TextFieldBloc(
validators: [
FieldBlocValidators.required,
FieldBlocValidators.email,
],
);
final password = TextFieldBloc(
validators: [
FieldBlocValidators.required,
],
);
final showSuccessResponse = BooleanFieldBloc();
LoginFormBloc() {
addFieldBlocs(
fieldBlocs: [
email,
password,
showSuccessResponse,
],
);
}
@override
void onSubmitting() async {
debugPrint(email.value);
debugPrint(password.value);
debugPrint(showSuccessResponse.value.toString());
await Future<void>.delayed(const Duration(seconds: 1));
if (showSuccessResponse.value) {
emitSuccess();
} else {
emitFailure(failureResponse: 'This is an awesome error!');
}
}
}
class LoginForm extends StatelessWidget {
LoginForm({Key? key}) : super(key: key);
final TextEditingController controller = TextEditingController();
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => LoginFormBloc(),
child: Builder(
builder: (context) {
final loginFormBloc = context.read<LoginFormBloc>();
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(title: const Text('Login')),
body: FormBlocListener<LoginFormBloc, String, String>(
onSubmitting: (context, state) {
LoadingDialog.show(context);
},
onSubmissionFailed: (context, state) {
LoadingDialog.hide(context);
},
onSuccess: (context, state) {
LoadingDialog.hide(context);
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (_) => const SuccessScreen()));
},
onFailure: (context, state) {
LoadingDialog.hide(context);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(state.failureResponse!)));
},
child: SingleChildScrollView(
physics: const ClampingScrollPhysics(),
child: AutofillGroup(
child: Column(
children: <Widget>[
BlocBuilder<TextFieldBloc, TextFieldBlocState>(
bloc: loginFormBloc.email,
builder: (context, state) {
return TextField(
controller: controller,
keyboardType: TextInputType.emailAddress,
autofillHints: const [
AutofillHints.username,
],
decoration: InputDecoration(
labelText: 'Email',
prefixIcon: const Icon(Icons.email),
errorText: state.canShowError
? FieldBlocBuilder.defaultErrorBuilder(
context,
state.error!,
loginFormBloc.email,
)
: null,
),
onChanged: (value) {
loginFormBloc.email.updateValue(value);
},
);
},
),
TextFieldBlocBuilder(
textFieldBloc: loginFormBloc.email,
keyboardType: TextInputType.emailAddress,
autofillHints: const [
AutofillHints.username,
],
decoration: const InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email),
),
),
TextFieldBlocBuilder(
textFieldBloc: loginFormBloc.password,
suffixButton: SuffixButton.obscureText,
autofillHints: const [AutofillHints.password],
decoration: const InputDecoration(
labelText: 'Password',
prefixIcon: Icon(Icons.lock),
),
),
SizedBox(
width: 250,
child: CheckboxFieldBlocBuilder(
booleanFieldBloc: loginFormBloc.showSuccessResponse,
body: Container(
alignment: Alignment.centerLeft,
child: const Text('Show success response'),
),
),
),
ElevatedButton(
onPressed: loginFormBloc.submit,
child: const Text('LOGIN'),
),
],
),
),
),
),
);
},
),
);
}
}
class LoadingDialog extends StatelessWidget {
static void show(BuildContext context, {Key? key}) => showDialog<void>(
context: context,
useRootNavigator: false,
barrierDismissible: false,
builder: (_) => LoadingDialog(key: key),
).then((_) => FocusScope.of(context).requestFocus(FocusNode()));
static void hide(BuildContext context) => Navigator.pop(context);
const LoadingDialog({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async => false,
child: Center(
child: Card(
child: Container(
width: 80,
height: 80,
padding: const EdgeInsets.all(12.0),
child: const CircularProgressIndicator(),
),
),
),
);
}
}
class SuccessScreen extends StatelessWidget {
const SuccessScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Icon(Icons.tag_faces, size: 100),
const SizedBox(height: 10),
const Text(
'Success',
style: TextStyle(fontSize: 54, color: Colors.black),
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
ElevatedButton.icon(
onPressed: () => Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (_) => LoginForm())),
icon: const Icon(Icons.replay),
label: const Text('AGAIN'),
),
],
),
),
);
}
}
|
@aaassseee Wow.. Thank you for the comprehensive response. I will get back to you on how I go with implementing this. |
Hi @GiancarloCode , nice Library 👍
Can we have ability to give custom
TextEditingController
to theTextFieldBlocBuilder
??Actually, I want to use some of the controller's functionalities like text selection on tap, etc.
EDIT:
On the page: https://giancarlocode.github.io/form_bloc/#/
(tutorial of
Simple
, step-9) it is mentioned that we can use any widget we want to use.Can you provide an example for that???
The text was updated successfully, but these errors were encountered: