mirror of
https://github.com/Iconica-Development/flutter_address_form.git
synced 2025-05-19 10:43:45 +02:00
WIP adresscontroller validator
This commit is contained in:
parent
1b4d920586
commit
affa510a5c
5 changed files with 187 additions and 145 deletions
|
@ -31,20 +31,16 @@ class MyApp extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class AddressFormExample extends StatelessWidget {
|
class AddressFormExample extends StatelessWidget {
|
||||||
AddressFormExample({Key? key}) : super(key: key);
|
AddressFormExample({super.key});
|
||||||
|
|
||||||
final RegExp zipcodeRegExp = RegExp(r'^[1-9][0-9]{3}\s?[a-zA-Z]{2}$');
|
// final RegExp zipcodeRegExp = RegExp(r'^[1-9][0-9]{3}\s?[a-zA-Z]{2}$');
|
||||||
|
|
||||||
@override
|
final _addressController = AddressController(
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(),
|
|
||||||
body: AddressForm(
|
|
||||||
zipCodeValidator: (text) {
|
zipCodeValidator: (text) {
|
||||||
if (text.isEmpty) {
|
if (text.isEmpty) {
|
||||||
return 'Can\'t be empty';
|
return 'Can\'t be empty';
|
||||||
}
|
}
|
||||||
if (!zipcodeRegExp.hasMatch(text)) {
|
if (!RegExp(r'^[1-9][0-9]{3}\s?[a-zA-Z]{2}$').hasMatch(text)) {
|
||||||
return 'Invalid zipcode';
|
return 'Invalid zipcode';
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -70,15 +66,31 @@ class AddressFormExample extends StatelessWidget {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
onAutoComplete: (address) {
|
||||||
|
return address;
|
||||||
|
},
|
||||||
cityValidator: (text) {
|
cityValidator: (text) {
|
||||||
if (text.isEmpty) {
|
if (text.isEmpty) {
|
||||||
return 'Can\'t be empty';
|
return 'Can\'t be empty';
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
controller: AddressController(onAutoComplete: (address) {
|
);
|
||||||
return address;
|
|
||||||
}),
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
AddressForm(
|
||||||
|
onSubmit: (value) => value, controller: _addressController),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
_addressController.validate;
|
||||||
|
},
|
||||||
|
child: Text('Test'))
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
library flutter_address_form;
|
library flutter_address_form;
|
||||||
|
|
||||||
export 'src/address_form.dart';
|
export 'src/address_form.dart';
|
||||||
|
export 'src/models/address_model.dart';
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:ffi';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
@ -6,74 +7,74 @@ import 'package:flutter_address_form/src/models/address_model.dart';
|
||||||
|
|
||||||
/// A widget that creates a form with different address fields widgets.
|
/// A widget that creates a form with different address fields widgets.
|
||||||
/// Returns a `AddressModel` Object from a `AddressController`.
|
/// Returns a `AddressModel` Object from a `AddressController`.
|
||||||
class AddressForm extends StatelessWidget {
|
class AddressForm extends StatefulWidget {
|
||||||
AddressForm({
|
AddressForm({
|
||||||
Key? key,
|
super.key,
|
||||||
this.zipCodeLabel = const Text('Zipcode'),
|
|
||||||
this.housenumberLabel = const Text('Housenumber'),
|
|
||||||
this.suffixLabel = const Text('Suffix'),
|
|
||||||
this.streetLabel = const Text('Street'),
|
|
||||||
this.cityLabel = const Text('City'),
|
|
||||||
required this.zipCodeValidator,
|
|
||||||
required this.housenumberValidator,
|
|
||||||
required this.suffixValidator,
|
|
||||||
required this.streetValidator,
|
|
||||||
required this.cityValidator,
|
|
||||||
AddressController? controller,
|
AddressController? controller,
|
||||||
|
this.zipCodeDecoration = const InputDecoration(label: Text('Zipcode')),
|
||||||
|
this.housenumberDecoration =
|
||||||
|
const InputDecoration(label: Text('Housenumber')),
|
||||||
|
this.suffixDecoration = const InputDecoration(label: Text('Suffix')),
|
||||||
|
this.streetDecoration = const InputDecoration(label: Text('Street')),
|
||||||
|
this.cityDecoration = const InputDecoration(label: Text('City')),
|
||||||
|
required this.onSubmit,
|
||||||
}) {
|
}) {
|
||||||
_addressController =
|
_addressController = controller ??
|
||||||
controller ?? AddressController(onAutoComplete: (model) => model);
|
AddressController(
|
||||||
|
onAutoComplete: (model) => model,
|
||||||
|
zipCodeValidator: (text) => null,
|
||||||
|
cityValidator: (text) => null,
|
||||||
|
housenumberValidator: (text) => null,
|
||||||
|
streetValidator: (text) => null,
|
||||||
|
suffixValidator: (text) => null,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Widget zipCodeLabel;
|
final InputDecoration zipCodeDecoration;
|
||||||
final Widget housenumberLabel;
|
final InputDecoration housenumberDecoration;
|
||||||
final Widget suffixLabel;
|
final InputDecoration suffixDecoration;
|
||||||
final Widget streetLabel;
|
final InputDecoration streetDecoration;
|
||||||
final Widget cityLabel;
|
final InputDecoration cityDecoration;
|
||||||
|
|
||||||
final String? Function(String) zipCodeValidator;
|
final ValueChanged<String> onSubmit;
|
||||||
final String? Function(String) housenumberValidator;
|
|
||||||
final String? Function(String) suffixValidator;
|
|
||||||
final String? Function(String) streetValidator;
|
|
||||||
final String? Function(String) cityValidator;
|
|
||||||
|
|
||||||
/// Controls the `AddressModel`
|
/// Controls the `AddressModel`
|
||||||
late final AddressController _addressController;
|
late final AddressController _addressController;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AddressForm> createState() => _AddressFormState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AddressFormState extends State<AddressForm> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
AddressFormTextField(
|
AddressFormTextField(
|
||||||
controller: _addressController._zipcodeController,
|
controller: widget._addressController._zipcodeController,
|
||||||
validator: zipCodeValidator,
|
fieldDecoration: widget.zipCodeDecoration,
|
||||||
label: zipCodeLabel,
|
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
AddressFormTextField(
|
AddressFormTextField(
|
||||||
controller: _addressController._housenumberController,
|
controller: widget._addressController._housenumberController,
|
||||||
validator: housenumberValidator,
|
fieldDecoration: widget.housenumberDecoration,
|
||||||
label: housenumberLabel,
|
|
||||||
),
|
),
|
||||||
AddressFormTextField(
|
AddressFormTextField(
|
||||||
controller: _addressController._suffixController,
|
controller: widget._addressController._suffixController,
|
||||||
validator: suffixValidator,
|
fieldDecoration: widget.suffixDecoration,
|
||||||
label: suffixLabel,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
AddressFormTextField(
|
AddressFormTextField(
|
||||||
controller: _addressController._streetController,
|
controller: widget._addressController._streetController,
|
||||||
validator: streetValidator,
|
fieldDecoration: widget.streetDecoration,
|
||||||
label: streetLabel,
|
|
||||||
),
|
),
|
||||||
AddressFormTextField(
|
AddressFormTextField(
|
||||||
controller: _addressController._cityController,
|
controller: widget._addressController._cityController,
|
||||||
validator: cityValidator,
|
fieldDecoration: widget.cityDecoration,
|
||||||
label: cityLabel,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -81,17 +82,18 @@ class AddressForm extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class AddressFormTextField extends StatelessWidget {
|
class AddressFormTextField extends StatelessWidget {
|
||||||
final Widget label;
|
AddressFormTextField({
|
||||||
final TextEditingController controller;
|
super.key,
|
||||||
final String? Function(String) validator;
|
required this.fieldDecoration,
|
||||||
const AddressFormTextField({
|
|
||||||
Key? key,
|
|
||||||
required this.label,
|
|
||||||
required this.controller,
|
required this.controller,
|
||||||
required this.validator,
|
}) {
|
||||||
}) : super(key: key);
|
_addressFieldDecoration = fieldDecoration;
|
||||||
|
}
|
||||||
|
|
||||||
String? get _errorText => validator(controller.value.text);
|
final TextEditingController controller;
|
||||||
|
final InputDecoration fieldDecoration;
|
||||||
|
|
||||||
|
late final InputDecoration _addressFieldDecoration;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -103,14 +105,12 @@ class AddressFormTextField extends StatelessWidget {
|
||||||
margin: const EdgeInsets.all(10),
|
margin: const EdgeInsets.all(10),
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
decoration: InputDecoration(
|
decoration: _addressFieldDecoration,
|
||||||
label: label,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
errorText: _errorText),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +121,14 @@ class AddressController extends ChangeNotifier {
|
||||||
/// When the form changes, the function passes the current `AddressModel` as an argument and gives the possibility to manipulate and return a `AddressModel`.
|
/// When the form changes, the function passes the current `AddressModel` as an argument and gives the possibility to manipulate and return a `AddressModel`.
|
||||||
final FutureOr<AddressModel> Function(AddressModel)? onAutoComplete;
|
final FutureOr<AddressModel> Function(AddressModel)? onAutoComplete;
|
||||||
|
|
||||||
AddressController({this.initialValue, this.onAutoComplete}) {
|
AddressController(
|
||||||
|
{this.initialValue,
|
||||||
|
this.onAutoComplete,
|
||||||
|
required this.zipCodeValidator,
|
||||||
|
required this.housenumberValidator,
|
||||||
|
required this.suffixValidator,
|
||||||
|
required this.streetValidator,
|
||||||
|
required this.cityValidator}) {
|
||||||
_model = initialValue ??
|
_model = initialValue ??
|
||||||
const AddressModel(
|
const AddressModel(
|
||||||
zipcode: null,
|
zipcode: null,
|
||||||
|
@ -140,6 +147,12 @@ class AddressController extends ChangeNotifier {
|
||||||
|
|
||||||
late AddressModel _model;
|
late AddressModel _model;
|
||||||
|
|
||||||
|
final String? Function(String) zipCodeValidator;
|
||||||
|
final String? Function(String) housenumberValidator;
|
||||||
|
final String? Function(String) suffixValidator;
|
||||||
|
final String? Function(String) streetValidator;
|
||||||
|
final String? Function(String) cityValidator;
|
||||||
|
|
||||||
late final _zipcodeController =
|
late final _zipcodeController =
|
||||||
TextEditingController(text: initialValue?.zipcode);
|
TextEditingController(text: initialValue?.zipcode);
|
||||||
late final _streetController =
|
late final _streetController =
|
||||||
|
@ -152,6 +165,20 @@ class AddressController extends ChangeNotifier {
|
||||||
|
|
||||||
AddressModel get model => _model;
|
AddressModel get model => _model;
|
||||||
|
|
||||||
|
bool get validate => _validate();
|
||||||
|
|
||||||
|
bool _validate() {
|
||||||
|
if (zipCodeValidator.call(_zipcodeController.text) == null &&
|
||||||
|
streetValidator.call(_streetController.text) == null &&
|
||||||
|
housenumberValidator.call(_housenumberController.text) == null &&
|
||||||
|
suffixValidator.call(_suffixController.text) == null &&
|
||||||
|
cityValidator.call(_cityController.text) == null) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _update() async {
|
void _update() async {
|
||||||
AddressModel updatedModel = _model.copyWith(
|
AddressModel updatedModel = _model.copyWith(
|
||||||
zipcode: _zipcodeController.text,
|
zipcode: _zipcodeController.text,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
name: flutter_address_form
|
name: flutter_address_form
|
||||||
description: A new Flutter package project.
|
description: A new Flutter package project.
|
||||||
version: 0.0.1
|
version: 0.0.1
|
||||||
homepage:
|
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.18.2 <3.0.0'
|
sdk: '>=2.18.2 <3.0.0'
|
||||||
|
|
|
@ -11,6 +11,8 @@ void main() {
|
||||||
home: Scaffold(
|
home: Scaffold(
|
||||||
appBar: AppBar(),
|
appBar: AppBar(),
|
||||||
body: AddressForm(
|
body: AddressForm(
|
||||||
|
onSubmit: (value) => value,
|
||||||
|
controller: AddressController(
|
||||||
zipCodeValidator: (text) {
|
zipCodeValidator: (text) {
|
||||||
if (text.isEmpty) {
|
if (text.isEmpty) {
|
||||||
return 'Can\'t be empty';
|
return 'Can\'t be empty';
|
||||||
|
@ -41,15 +43,16 @@ void main() {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
onAutoComplete: (address) {
|
||||||
|
return address;
|
||||||
|
},
|
||||||
cityValidator: (text) {
|
cityValidator: (text) {
|
||||||
if (text.isEmpty) {
|
if (text.isEmpty) {
|
||||||
return 'Can\'t be empty';
|
return 'Can\'t be empty';
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
controller: AddressController(onAutoComplete: (address) {
|
),
|
||||||
return address;
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in a new issue