// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:meta/meta.dart'; import 'basic.dart'; import 'framework.dart'; /// A container for grouping together multiple form field widgets (e.g. /// [Input] widgets). class Form extends StatefulWidget { /// Creates a container for form fields. /// /// The [child] argument must not be null. Form({ Key key, @required this.child, this.onSubmitted }) : super(key: key) { assert(child != null); } /// Called when the input is accepted anywhere on the form. final VoidCallback onSubmitted; /// Root of the widget hierarchy that contains this form. final Widget child; @override _FormState createState() => new _FormState(); } class _FormState extends State<Form> { int generation = 0; void _onFieldChanged() { setState(() { ++generation; }); } @override Widget build(BuildContext context) { return new FormScope._( formState: this, generation: generation, child: config.child ); } } /// Signature for validating a form field. typedef String FormFieldValidator<T>(T value); /// Signature for being notified when a form field changes value. typedef void FormFieldSetter<T>(T newValue); /// Identifying information for form controls. class FormField<T> { /// Creates identifying information for form controls FormField({ this.setter, this.validator }); /// An optional method to call with the new value when the form field changes. final FormFieldSetter<T> setter; /// An optional method that validates an input. Returns an error string to /// display if the input is invalid, or null otherwise. final FormFieldValidator<T> validator; } /// A widget that establishes a scope for a [Form]. /// /// Cannot be created directly. Instead, create a [Form] widget, which builds /// a [FormScope]. /// /// Useful for locating the closest enclosing [Form]. class FormScope extends InheritedWidget { FormScope._({ Key key, Widget child, _FormState formState, int generation }) : _formState = formState, _generation = generation, super(key: key, child: child); final _FormState _formState; /// Incremented every time a form field has changed. This lets us know when /// to rebuild the form. final int _generation; /// The [Form] associated with this widget. Form get form => _formState.config; /// The closest [FormScope] encloses the given context. static FormScope of(BuildContext context) { return context.inheritFromWidgetOfExactType(FormScope); } /// Use this to notify the Form that a form field has changed. This will /// cause all form fields to rebuild, useful if form fields have /// interdependencies. void onFieldChanged() => _formState._onFieldChanged(); @override bool updateShouldNotify(FormScope old) => _generation != old._generation; }