Repository: joanpablo/reactive_forms

Issue:
Reset to default value
 How can I reset my form to its default values?
 If I call reset() all is set to null.



Fix patch:
diff --git a/example/main.dart b/example/main.dart
new file mode 100644
index 0000000..2f7948e
--- /dev/null
+++ b/example/main.dart
@@ -0,0 +1,132 @@
+import 'package:flutter/material.dart';
+import 'package:reactive_forms/reactive_forms.dart';
+
+void main() {
+  runApp(const MyApp());
+}
+
+class MyApp extends StatelessWidget {
+  const MyApp({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return MaterialApp(
+      title: 'Reactive Forms Login',
+      theme: ThemeData(
+        primarySwatch: Colors.blue,
+      ),
+      home: const LoginPage(),
+    );
+  }
+}
+
+class LoginPage extends StatefulWidget {
+  const LoginPage({super.key});
+
+  @override
+  State<LoginPage> createState() => _LoginPageState();
+}
+
+class _LoginPageState extends State<LoginPage> {
+  // Define the form group
+  final FormGroup form = FormGroup({
+    'email': FormControl<String>(
+      validators: [Validators.required, Validators.email],
+    ),
+    'password': FormControl<String>(
+      validators: [Validators.required, Validators.minLength(8)],
+    ),
+  });
+
+  void _login() {
+    if (form.valid) {
+      // Handle successful login
+      print('Login successful!');
+      print('Email: ${form.control('email').value}');
+      print('Password: ${form.control('password').value}');
+      // You would typically navigate to another screen here
+      // or make an API call.
+      ScaffoldMessenger.of(context).showSnackBar(
+        const SnackBar(content: Text('Login Successful!')),
+      );
+    } else {
+      // Mark fields as touched to show errors if not already shown
+      form.markAllAsTouched();
+      ScaffoldMessenger.of(context).showSnackBar(
+        const SnackBar(content: Text('Please correct the errors.')),
+      );
+    }
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        title: const Text('Login'),
+      ),
+      body: Padding(
+        padding: const EdgeInsets.all(16.0),
+        // Use ReactiveForm widget to bind the FormGroup
+        child: ReactiveForm(
+          formGroup: form,
+          child: Column(
+            mainAxisAlignment: MainAxisAlignment.center,
+            children: <Widget>[
+              // Email Field
+              ReactiveTextField<String>(
+                formControlName: 'email',
+                decoration: const InputDecoration(
+                  labelText: 'Email',
+                  border: OutlineInputBorder(),
+                ),
+                validationMessages: {
+                  ValidationMessage.required: (_) =>
+                      'The email must not be empty',
+                  ValidationMessage.email: (_) =>
+                      'The email value must be a valid email',
+                },
+                keyboardType: TextInputType.emailAddress,
+              ),
+              const SizedBox(height: 16.0),
+
+              // Password Field
+              ReactiveTextField<String>(
+                formControlName: 'password',
+                decoration: const InputDecoration(
+                  labelText: 'Password',
+                  border: OutlineInputBorder(),
+                ),
+                obscureText: true,
+                validationMessages: {
+                  ValidationMessage.required: (_) =>
+                      'The password must not be empty',
+                  ValidationMessage.minLength: (error) =>
+                      'The password must be at least ${(error as Map)['requiredLength']} characters long',
+                },
+              ),
+              const SizedBox(height: 24.0),
+
+              // Login Button
+              ElevatedButton(
+                onPressed: _login, // Call _login method on press
+                child: const Text('Login'),
+              ),
+
+              const SizedBox(height: 20),
+
+              // Example of disabling button based on form validity
+              ReactiveFormConsumer(
+                builder: (context, formGroup, child) {
+                  return ElevatedButton(
+                    onPressed: formGroup.valid ? _login : null,
+                    child: const Text('Login (Enabled when valid)'),
+                  );
+                },
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/src/models/models.dart b/lib/src/models/models.dart
index 916211f..3b2610c 100644
--- a/lib/src/models/models.dart
+++ b/lib/src/models/models.dart
@@ -44,6 +44,7 @@ abstract class AbstractControl<T> {
   final int _asyncValidatorsDebounceTime;
 
   bool _touched;
+  final bool _initialDisabled;
 
   /// Constructor of the [AbstractControl].
   AbstractControl({
@@ -55,6 +56,7 @@ abstract class AbstractControl<T> {
   }) : assert(asyncValidatorsDebounceTime >= 0),
        _asyncValidatorsDebounceTime = asyncValidatorsDebounceTime,
        _touched = touched,
+       _initialDisabled = disabled,
        _status = disabled ? ControlStatus.disabled : ControlStatus.valid {
     setValidators(validators);
     setAsyncValidators(asyncValidators);
@@ -552,8 +554,12 @@ abstract class AbstractControl<T> {
 
     if (disabled != null) {
       disabled
-          ? markAsDisabled(updateParent: true, emitEvent: false)
-          : markAsEnabled(updateParent: true, emitEvent: false);
+          ? markAsDisabled(updateParent: updateParent, emitEvent: false)
+          : markAsEnabled(updateParent: updateParent, emitEvent: false);
+    } else if (_initialDisabled) {
+      markAsDisabled(updateParent: updateParent, emitEvent: emitEvent);
+    } else {
+      markAsEnabled(updateParent: updateParent, emitEvent: emitEvent);
     }
 
     if (removeFocus) {


Test patch:
diff --git a/test/src/models/form_control_test.dart b/test/src/models/form_control_test.dart
index bdcd504..b2bfd79 100644
--- a/test/src/models/form_control_test.dart
+++ b/test/src/models/form_control_test.dart
@@ -377,6 +377,21 @@ void main() {
       // Then: the status is PENDING.
       expect(control.pending, true);
     });
+
+    test(
+      'Given a disabled control, when enabled and then reset, it is disabled',
+      () {
+        // Arrange
+        final control = FormControl<String>(disabled: true);
+
+        // Act
+        control.markAsEnabled();
+        control.reset();
+
+        // Assert
+        expect(control.disabled, true);
+      },
+    );
   });
 
   group('FormControl reset with initial value', () {