formik_flutter 1.0.2 copy "formik_flutter: ^1.0.2" to clipboard
formik_flutter: ^1.0.2 copied to clipboard

A lightweight, declarative form state management solution for Flutter inspired by Formik.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:formik_flutter/formik_flutter.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: Colors.deepPurple,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Dynamic Form Array Example'),
          centerTitle: true,
        ),
        body: const SingleChildScrollView(
          padding: EdgeInsets.all(16.0),
          child: DynamicUsersForm(),
        ),
      ),
    );
  }
}

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

  @override
  State<DynamicUsersForm> createState() => _DynamicUsersFormState();
}

class _DynamicUsersFormState extends State<DynamicUsersForm> {
  late final FormikController _formik;

  @override
  void initState() {
    super.initState();

    _formik = FormikController(
      initialValues: {
        'users': [
          {
            'name': '',
            'email': '',
            'role': 'Developer',
            'isActive': true,
          }
        ]
      },
      onSubmit: (values) {
        debugPrint('Submitted Values: $values');
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content:
                Text('Successfully Submitted ${values['users'].length} Users!'),
            backgroundColor: Colors.green,
          ),
        );
      },
    );
  }

  @override
  void dispose() {
    _formik.dispose();
    super.dispose();
  }

  void _addUserCard() {
    final currentList = List<Map<String, dynamic>>.from(
      _formik.getFieldValue<List>('users') ?? [],
    );

    currentList.add({
      'name': '',
      'email': '',
      'role': 'Developer',
      'isActive': true,
    });

    _formik.setFieldValue('users', currentList);
  }

  void _removeUserCard(int index) {
    final currentList = List<Map<String, dynamic>>.from(
      _formik.getFieldValue<List>('users') ?? [],
    );

    if (currentList.length > 1) {
      currentList.removeAt(index);
      _formik.setFieldValue('users', currentList);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Formik(
      controller: _formik,
      child: AnimatedBuilder(
        animation: _formik,
        builder: (context, _) {
          final usersList = _formik.getFieldValue<List>('users') ?? [];

          return Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(
                    'Users Count (${usersList.length})',
                    style: const TextStyle(
                        fontSize: 18, fontWeight: FontWeight.bold),
                  ),
                  ElevatedButton.icon(
                    onPressed: _addUserCard,
                    icon: const Icon(Icons.add),
                    label: const Text('Add User'),
                  ),
                ],
              ),
              const SizedBox(height: 16),
              ListView.builder(
                shrinkWrap: true,
                physics: const NeverScrollableScrollPhysics(),
                itemCount: usersList.length,
                itemBuilder: (context, index) {
                  return Container(
                    key: ValueKey('user_container_$index'),
                    margin: const EdgeInsets.only(bottom: 16),
                    padding: const EdgeInsets.all(16),
                    decoration: BoxDecoration(
                      color: Colors.grey.shade50,
                      borderRadius: BorderRadius.circular(12),
                      border: Border.all(color: Colors.grey.shade300),
                    ),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: [
                            Text(
                              'User #${index + 1}',
                              style: const TextStyle(
                                fontWeight: FontWeight.bold,
                                fontSize: 16,
                              ),
                            ),
                            if (usersList.length > 1)
                              IconButton(
                                icon: const Icon(Icons.remove_circle_outline,
                                    color: Colors.red),
                                onPressed: () => _removeUserCard(index),
                              ),
                          ],
                        ),
                        const Divider(),
                        const SizedBox(height: 8),
                        FormikField<String>(
                          name: 'users.$index.name',
                          validator: FormikValidators.required(
                              message: 'Name is required'),
                          builder: (context, field) {
                            return TextFormField(
                              controller: field.controller,
                              onChanged: field.didChange,
                              decoration: InputDecoration(
                                labelText: 'Name',
                                border: const OutlineInputBorder(),
                                errorText: field.isTouched ? field.error : null,
                              ),
                            );
                          },
                        ),
                        const SizedBox(height: 12),
                        FormikField<String>(
                          name: 'users.$index.email',
                          validator: FormikValidators.compose([
                            FormikValidators.required(
                                message: 'Email is required'),
                            FormikValidators.email(message: 'Invalid email'),
                          ]),
                          builder: (context, field) {
                            return TextFormField(
                              controller: field.controller,
                              onChanged: field.didChange,
                              decoration: InputDecoration(
                                labelText: 'Email',
                                border: const OutlineInputBorder(),
                                errorText: field.isTouched ? field.error : null,
                              ),
                            );
                          },
                        ),
                        const SizedBox(height: 12),
                        FormikField<String>(
                          name: 'users.$index.role',
                          validator: FormikValidators.required(),
                          builder: (context, field) {
                            return DropdownButtonFormField<String>(
                              initialValue: field.value,
                              decoration: const InputDecoration(
                                labelText: 'Role',
                                border: OutlineInputBorder(),
                              ),
                              items: const [
                                DropdownMenuItem(
                                    value: 'Developer',
                                    child: Text('Developer')),
                                DropdownMenuItem(
                                    value: 'Designer', child: Text('Designer')),
                                DropdownMenuItem(
                                    value: 'Tester', child: Text('Tester')),
                              ],
                              onChanged: field.didChange,
                            );
                          },
                        ),
                        const SizedBox(height: 8),
                        FormikField<bool>(
                          name: 'users.$index.isActive',
                          builder: (context, field) {
                            return SwitchListTile(
                              title: const Text('Active Member'),
                              value: field.value ?? true,
                              onChanged: field.didChange,
                              contentPadding: EdgeInsets.zero,
                            );
                          },
                        ),
                      ],
                    ),
                  );
                },
              ),
              const SizedBox(height: 16),
              ElevatedButton(
                onPressed: (!_formik.isValid || _formik.isSubmitting)
                    ? null
                    : () => _formik.submitForm(),
                style: ElevatedButton.styleFrom(
                  padding: const EdgeInsets.symmetric(vertical: 16),
                ),
                child: const Text('Submit'),
              ),
            ],
          );
        },
      ),
    );
  }
}
0
likes
150
points
28
downloads

Documentation

API reference

Publisher

verified publishercodieszone.com

Weekly Downloads

A lightweight, declarative form state management solution for Flutter inspired by Formik.

Repository (GitHub)
View/report issues

Topics

#form #form-validation #formik #state-management

License

unknown (license)

Dependencies

flutter

More

Packages that depend on formik_flutter