Skip to content

Instantly share code, notes, and snippets.

@bizz84
Last active October 18, 2021 09:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bizz84/514e11090312994ae9aecab19dfe3f0f to your computer and use it in GitHub Desktop.
Save bizz84/514e11090312994ae9aecab19dfe3f0f to your computer and use it in GitHub Desktop.
Flutter TextField validation with TextEditingController and ValueListenableBuilder
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.indigo,
textTheme: const TextTheme(
button: TextStyle(color: Colors.white),
)),
home: const SubmitPage(),
);
}
}
class SubmitPage extends StatelessWidget {
const SubmitPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Validation')),
body: Padding(
padding: const EdgeInsets.all(24),
child: Center(
child: TextSubmitWidget(onSubmit: (value) => print(value)),
), //
),
);
}
}
class TextSubmitWidget extends StatefulWidget {
const TextSubmitWidget({Key? key, required this.onSubmit}) : super(key: key);
final ValueChanged<String> onSubmit;
@override
State<TextSubmitWidget> createState() => _TextSubmitWidgetState();
}
class _TextSubmitWidgetState extends State<TextSubmitWidget> {
final _controller = TextEditingController();
bool _submitted = false;
@override
void dispose() {
_controller.dispose();
super.dispose();
}
String? get _errorText {
final text = _controller.value.text;
if (text.isEmpty) {
return 'Can\'t be empty';
}
if (text.length < 4) {
return 'Too short';
}
return null;
}
void _submit() {
setState(() => _submitted = true);
if (_errorText == null) {
widget.onSubmit(_controller.value.text);
}
}
@override
Widget build(BuildContext context) {
return ValueListenableBuilder(
// Note: pass _controller to the animation argument
valueListenable: _controller,
builder: (context, TextEditingValue value, __) {
// this entire widget tree will rebuild every time
// the controller value changes
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(
height: 80,
child: TextField(
controller: _controller,
decoration: InputDecoration(
labelText: 'Enter your name',
// the errorText getter *depends* on _controller
errorText: _submitted ? _errorText : null,
),
),
),
SizedBox(
height: 40,
child: ElevatedButton(
// the errorText getter *depends* on _controller
onPressed: _controller.value.text.isNotEmpty ? _submit : null,
child: Text(
'Submit',
style: Theme.of(context)
.textTheme
.headline6!
.copyWith(color: Colors.white),
),
),
)
],
);
},
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment