Skip to content

Instantly share code, notes, and snippets.

@MelbourneDeveloper
Last active July 17, 2023 20:53
Show Gist options
  • Save MelbourneDeveloper/6f75cdb12f0a6a911c5e7e73bb7da7f5 to your computer and use it in GitHub Desktop.
Save MelbourneDeveloper/6f75cdb12f0a6a911c5e7e73bb7da7f5 to your computer and use it in GitHub Desktop.
Delayed Save On Text Edit
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(const MainApp());
}
class DelayedTextEditingController {
DelayedTextEditingController(
this.onValidated,
this.update,
this.validate,
String initialText,
) : textController = TextEditingController(text: initialText) {
textController.addListener(() async {
await doValidation();
_updateFuture ??= Future.delayed(
const Duration(seconds: 2),
() async {
_updateFuture = null;
if (_lastValidValue == null || _lastUpdatedValue == _lastValidValue) {
return;
}
_lastUpdatedValue = _lastValidValue;
await update(_lastValidValue!);
},
);
});
}
Future<void> doValidation() async {
var text = textController.text;
errorMessage = await validate(text);
onValidated();
if (errorMessage == null) {
_lastValidValue = text;
}
}
final TextEditingController textController;
Future<void> Function(String newValue) update;
Future<String?> Function(String value) validate;
final void Function() onValidated;
String? errorMessage;
Future<void>? _updateFuture;
String? _lastValidValue;
String? _lastUpdatedValue;
}
class ProfileRepo {
Future<void> updateName(String name) async {
await Future.delayed(
const Duration(milliseconds: 50), () => print('name updated to $name'));
}
Future<void> updateEmailAddress(String email) async {
await Future.delayed(const Duration(milliseconds: 50),
() => print('email updated to $email'));
}
}
class Controller extends ChangeNotifier {
Controller(this.profileRepo, String name, String emailAddress) {
nameController = DelayedTextEditingController(
notifyListeners,
(s) => profileRepo.updateName(s),
(s) async => s.isNotEmpty ? null : 'Ouch name is required',
name);
emailController = DelayedTextEditingController(
notifyListeners,
(s) => profileRepo.updateEmailAddress(s),
(s) async => s.isNotEmpty ? null : 'Ouch email is required',
emailAddress);
}
late final DelayedTextEditingController emailController;
late final DelayedTextEditingController nameController;
final ProfileRepo profileRepo;
}
class MainApp extends StatefulWidget {
const MainApp({super.key});
@override
State<MainApp> createState() => _MainAppState();
}
class _MainAppState extends State<MainApp> {
Controller controller =
Controller(ProfileRepo(), 'Bob Smith', '[email protected]');
@override
Widget build(BuildContext context) => MaterialApp(
home: Scaffold(
body: AnimatedBuilder(
animation: controller,
builder: (context, child) => Center(
child: Padding(
padding: const EdgeInsets.all(50),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: controller.nameController.textController,
decoration: InputDecoration(
errorText: controller.nameController.errorMessage),
),
TextField(
controller: controller.emailController.textController,
decoration: InputDecoration(
errorText: controller.emailController.errorMessage),
)
],
),
),
),
),
),
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment