Skip to content

Instantly share code, notes, and snippets.

@zs-dima
Last active November 2, 2020 19:13
Show Gist options
  • Save zs-dima/1a131d5dc06839655aadcd0a9526b028 to your computer and use it in GitHub Desktop.
Save zs-dima/1a131d5dc06839655aadcd0a9526b028 to your computer and use it in GitHub Desktop.
form_data
import 'package:flutter/widgets.dart';
class FormData<FormDataType> {
FormDataType data;
final List<FormEntry> _fields = <FormEntry>[];
FormData({@required this.data});
FormEntry add<FieldType>(
FieldType value, {
FormDataType Function(FieldType value) onSaved,
String Function(FieldType value) validator,
FocusNode focusNode,
}) {
final field = FormEntry(
initialValue: value,
onSaved: (v) {
if (onSaved != null) data = onSaved(v);
},
validator: validator,
);
_fields.add(field);
return field;
}
void nextEmpty() {
final fieldNode = _fields.firstWhere((field) => !field.filled, orElse: () => null)?.focusNode;
if (fieldNode == null) {
unfocusAll();
//_buttonFocusNode.requestFocus();
} else {
fieldNode.requestFocus();
}
}
void valid() => _fields.every((field) => field.validator(field.value) == null);
void unfocusAll() => _fields.map<FocusNode>((field) => field.focusNode).forEach((node) => node.unfocus());
void setValidationStatus() => _fields.every((field) => field.filled);
FormDataType submit(BuildContext context) {
unfocusAll();
final form = Form.of(context)..save();
if (!form.validate()) {
nextEmpty();
return null;
}
return data;
}
void dispose() {
for (final field in _fields) {
field.dispose();
}
}
}
/// Form field proxy
@immutable
class FormEntry<FieldType> {
final FieldType initialValue;
FieldType get value => FieldType == String ? (_controller as TextEditingController).value.text : _controller.value;
set value(FieldType newValue) => _controller.value = newValue;
final FocusNode focusNode;
/// Check if field filled
bool get filled => !hasValidator || _onSaved == null || validator(value) == null;
/// On Form saved
ValueChanged<FieldType> get onSaved => _onSaved;
final ValueChanged<FieldType> _onSaved;
/// On field change
ValueChanged<FieldType> get onChanged => (dynamic value) => _controller.value = value;
/// Field validation
FormFieldValidator<FieldType> get validator => (dynamic value) => hasValidator ? _validator(value) : null;
final String Function(FieldType value) _validator;
/// If validator set
final bool hasValidator;
final ValueNotifier _controller;
ValueNotifier<T> controller<T>() => _controller as ValueNotifier<T>;
void addListener(VoidCallback listener) => _controller.addListener(listener);
void removeListener(VoidCallback listener) => _controller.removeListener(listener);
void dispose() {
_controller.dispose();
}
FormEntry({
@required this.initialValue,
@required ValueChanged<FieldType> onSaved,
String Function(FieldType value) validator,
FocusNode focusNode,
}) : focusNode = focusNode ?? FocusNode(),
_onSaved = onSaved,
_validator = validator,
hasValidator = validator != null,
_controller = FieldType == String ? TextEditingController(text: initialValue as String) : ValueNotifier<FieldType>(initialValue);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment