Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ FormBuilder(
),
```

For a complete example that enables or disables the submit button from form
state and validates an email field conditionally, see
[Submit Button State](example/lib/sources/submit_button.dart).

#### Building your own custom field

To build your own field within a `FormBuilder`, we use `FormBuilderField` which will require that you define your own field.
Expand Down
2 changes: 2 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This example showcases various form building patterns and use cases:
- **Sign Up Form** - A practical sign-up form example
- **Dynamic Fields** - Forms with fields that can be added/removed at runtime
- **Conditional Fields** - Fields that show/hide based on other field values
- **Submit Button State** - Submit button enabled from form state with conditional validation
- **Related Fields** - Forms with interdependent field values
- **Grouped Radio/Checkbox** - Selection inputs with grouping
- **Decorated Radio/Checkbox** - Custom styling for selection fields
Expand Down Expand Up @@ -48,6 +49,7 @@ lib/
│ ├── signup_form.dart # Sign up form
│ ├── dynamic_fields.dart # Dynamic field management
│ ├── conditional_fields.dart # Conditional visibility
│ ├── submit_button.dart # Submit button state and validation
│ ├── related_fields.dart # Field dependencies
│ ├── grouped_radio_checkbox.dart # Grouped selections
│ ├── decorated_radio_checkbox.dart # Styled selections
Expand Down
18 changes: 18 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:example/sources/decorated_radio_checkbox.dart';
import 'package:example/sources/dynamic_fields.dart';
import 'package:example/sources/grouped_radio_checkbox.dart';
import 'package:example/sources/related_fields.dart';
import 'package:example/sources/submit_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
Expand Down Expand Up @@ -132,6 +133,23 @@ class _HomePage extends StatelessWidget {
},
),
const Divider(),
ListTile(
title: const Text('Submit Button State'),
trailing: const Icon(Icons.arrow_right_sharp),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return const CodePage(
title: 'Submit Button State',
child: SubmitButtonForm(),
);
},
),
);
},
),
const Divider(),
ListTile(
title: const Text('Related Fields'),
trailing: const Icon(Icons.arrow_right_sharp),
Expand Down
102 changes: 102 additions & 0 deletions example/lib/sources/submit_button.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:form_builder_validators/form_builder_validators.dart';

class SubmitButtonForm extends StatefulWidget {
const SubmitButtonForm({super.key});

@override
State<SubmitButtonForm> createState() => _SubmitButtonFormState();
}

class _SubmitButtonFormState extends State<SubmitButtonForm> {
final _formKey = GlobalKey<FormBuilderState>();
bool _canSubmit = false;
bool _subscribe = false;
bool _submitted = false;

void _updateSubmitButton() {
final formState = _formKey.currentState;
if (formState == null) {
return;
}
Comment thread
deandreamatias marked this conversation as resolved.
Outdated

final isSubscribed = formState.instantValue['subscribe'] == true;
final isValid = formState.validate(focusOnInvalid: false);

setState(() {
_canSubmit = isValid;
_subscribe = isSubscribed;
_submitted = false;
});
}

String? _validateEmail(String? value) {
final emailRequired =
_formKey.currentState?.instantValue['subscribe'] == true;
final hasEmail = value?.isNotEmpty ?? false;

if (!emailRequired && !hasEmail) {
return null;
}
Comment thread
deandreamatias marked this conversation as resolved.
Outdated

return FormBuilderValidators.compose([
FormBuilderValidators.required(),
FormBuilderValidators.email(),
])(value);
}

void _submit() {
if (_formKey.currentState?.saveAndValidate() ?? false) {
debugPrint(_formKey.currentState?.value.toString());
setState(() {
_submitted = true;
});
}
}

@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: FormBuilder(
key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
initialValue: const {'subscribe': false},
onChanged: _updateSubmitButton,
child: Column(
children: [
FormBuilderTextField(
name: 'name',
decoration: const InputDecoration(labelText: 'Name'),
validator: FormBuilderValidators.required(),
),
const SizedBox(height: 10),
FormBuilderSwitch(
name: 'subscribe',
title: const Text('Receive product updates'),
),
const SizedBox(height: 10),
FormBuilderTextField(
name: 'email',
enabled: _subscribe,
decoration: InputDecoration(
labelText: _subscribe ? 'Email' : 'Email (optional)',
),
keyboardType: TextInputType.emailAddress,
validator: _validateEmail,
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: _canSubmit ? _submit : null,
child: const Text('Submit'),
),
if (_submitted) ...[
const SizedBox(height: 10),
Text('Submitted values: ${_formKey.currentState?.value}'),
],
],
),
),
);
}
}
Loading