app_forms 0.7.0 copy "app_forms: ^0.7.0" to clipboard
app_forms: ^0.7.0 copied to clipboard

App Forms Separate the logic from the user interface by use flutter_form_builder

App Forms #

Pub Version License

A powerful Flutter package that separates form logic from UI components using flutter_form_builder. Build maintainable, testable, and reusable forms with clean architecture principles.

โœจ Features #

  • ๐Ÿ—๏ธ Clean Architecture: Separate form logic from UI components
  • ๐Ÿ’‰ Dependency Injection: Global form management with singleton pattern
  • ๐Ÿ”„ Reactive State Management: Real-time form state updates and validation
  • โšก Auto-validation: Configurable automatic field validation with debouncing
  • ๐ŸŽฏ Type Safety: Generic type support for form fields
  • ๐Ÿ“‹ Field Management: Advanced field operations (setValue, reset, validation)
  • ๐Ÿ” Form State Tracking: Built-in loading, progress, error, and success states
  • ๐ŸŽญ Lifecycle Hooks: onInit, onSubmit, onValid, and onReset callbacks
  • ๐Ÿš€ Performance Optimized: Debounced field changes (250ms) for optimal performance
  • ๐Ÿ“ฆ Easy Integration: Works seamlessly with flutter_form_builder

๐Ÿš€ Quick Start #

Installation #

Add the package to your pubspec.yaml:

dependencies:
  app_forms: ^0.6.0
  flutter_form_builder: ^10.1.0
  form_builder_validators: ^11.2.0

Basic Usage #

1. Create Your Form Class

import 'package:app_forms/app_forms.dart';
import 'package:form_builder_validators/form_builder_validators.dart';

class LoginForm extends AppForm {
  // Configure auto-validation
  @override
  bool get autoValidate => true;

  // Define form fields with validation and callbacks
  final email = AppFormField<String>(
    name: 'email',
    initialValue: '[email protected]',
    validations: FormBuilderValidators.compose([
      FormBuilderValidators.required(),
      FormBuilderValidators.email(),
    ]),
    onChange: (field) {
      print('Email changed: ${field?.value}');
    },
    onValid: (field) {
      print('Email is valid: ${field?.value}');
    },
  );

  final password = AppFormField<String>(
    name: 'password',
    validations: FormBuilderValidators.compose([
      FormBuilderValidators.required(),
      FormBuilderValidators.minLength(6),
    ]),
  );

  LoginForm() {
    setFields([email, password]);
  }

  @override
  Future<void> onInit() async {
    // Initialize form data, API calls, etc.
    print('Form initialized');
  }

  @override
  Future<void> onSubmit(Map<String, dynamic>? values) async {
    // Handle form submission
    print('Submitting: $values');
    
    try {
      // Simulate API call
      await Future.delayed(const Duration(seconds: 2));
      setSuccess(true);
    } catch (e) {
      setHasErrors(true);
    }
  }

  @override
  Future<void> onValid(Map<String, dynamic>? values) async {
    // Called when form becomes valid
    print('Form is valid: $values');
  }

  @override
  void onReset() {
    // Handle form reset
    print('Form reset');
  }
}

2. Inject Forms in main.dart

import 'package:app_forms/app_forms.dart';

void main() {
  // Inject your forms globally
  AppForms.injectForms([
    LoginForm(),
    // Add other forms here
  ]);
  
  runApp(MyApp());
}

3. Build Your UI

class LoginPage extends StatelessWidget {
  const LoginPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Login')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            // Form Builder - handles form state and validation
            AppFormBuilder<LoginForm>(
              builder: (form) {
                return Column(
                  children: [
                    FormBuilderTextField(
                      name: form.email.name,
                      validator: form.email.validations,
                      decoration: const InputDecoration(
                        labelText: 'Email',
                        border: OutlineInputBorder(),
                      ),
                    ),
                    const SizedBox(height: 16),
                    FormBuilderTextField(
                      name: form.password.name,
                      validator: form.password.validations,
                      obscureText: true,
                      decoration: const InputDecoration(
                        labelText: 'Password',
                        border: OutlineInputBorder(),
                      ),
                    ),
                  ],
                );
              },
            ),
            const SizedBox(height: 24),
            
            // Form Listener - reacts to form state changes
            AppFormListener<LoginForm>(
              builder: (form) {
                return Column(
                  children: [
                    ElevatedButton(
                      onPressed: form.progressing ? null : form.submit,
                      child: form.progressing
                          ? const CircularProgressIndicator()
                          : const Text('Login'),
                    ),
                    if (form.hasErrors)
                      const Text(
                        'Please fix errors above',
                        style: TextStyle(color: Colors.red),
                      ),
                    if (form.success)
                      const Text(
                        'Login successful!',
                        style: TextStyle(color: Colors.green),
                      ),
                  ],
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

๐Ÿ“š Advanced Features #

Form State Management #

class MyForm extends AppForm {
  void customAction() {
    // Control form states
    setLoading(true);        // Show loading state
    setHasErrors(false);     // Clear errors
    setSuccess(false);       // Clear success state
    
    // Access form values
    final values = getValues();
    
    // Validate programmatically
    final isValid = saveAndValidate();
    
    // Reset form
    reset();
  }
}

Dynamic Field Updates #

class MyForm extends AppForm {
  void updateFieldValue() {
    // Update field value programmatically
    email.value = '[email protected]';
    updateFieldsValue(); // Sync with form builder
  }
  
  void setServerErrors(Map<String, dynamic> errors) {
    // Set validation errors from server
    setValidationErrors({
      'email': 'Email already exists',
      'password': 'Password too weak'
    });
  }
}

Custom Validation #

final customField = AppFormField<String>(
  name: 'username',
  validations: (value) {
    if (value == null || value.isEmpty) {
      return 'Username is required';
    }
    if (value.length < 3) {
      return 'Username must be at least 3 characters';
    }
    return null; // Valid
  },
);

๐Ÿ›๏ธ Architecture #

Core Components #

  • AppForm: Abstract base class for all forms
  • AppFormField: Type-safe field configuration
  • AppForms: Singleton service for dependency injection
  • AppFormBuilder: Widget wrapper connecting forms to UI
  • AppFormListener: Reactive widget for form state changes

Flow Diagram #

Form Definition โ†’ Dependency Injection โ†’ UI Binding โ†’ State Management
     โ†“                    โ†“                โ†“             โ†“
  AppForm           AppForms.inject    AppFormBuilder  AppFormListener

๐Ÿ”ง Configuration Options #

Auto-validation Control #

class MyForm extends AppForm {
  @override
  bool get autoValidate => false; // Disable auto-validation
}

Custom Debouncing #

The package uses a 250ms debouncer by default. This is configured internally but optimized for most use cases.

๐Ÿงช Testing #

void main() {
  group('LoginForm Tests', () {
    late LoginForm form;
    
    setUp(() {
      form = LoginForm();
      AppForms.injectForms([form]);
    });
    
    test('should validate email field', () {
      form.email.setValue('invalid-email');
      expect(form.saveAndValidate(), false);
      
      form.email.setValue('[email protected]');
      expect(form.saveAndValidate(), true);
    });
  });
}

๐Ÿ“– API Reference #

See the API documentation for detailed information about all available methods and properties.

๐Ÿค Contributing #

Contributions are welcome! Please read our contributing guidelines and submit pull requests to our GitHub repository.

๐Ÿ“„ License #

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ†˜ Support #

10
likes
140
points
20
downloads

Publisher

verified publisherm-it.dev

Weekly Downloads

App Forms Separate the logic from the user interface by use flutter_form_builder

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, flutter_form_builder

More

Packages that depend on app_forms