Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FormArray not rebuild when called markAsTouched() #470

Open
dmisiek opened this issue Dec 6, 2024 · 0 comments
Open

FormArray not rebuild when called markAsTouched() #470

dmisiek opened this issue Dec 6, 2024 · 0 comments
Labels
bug Something isn't working

Comments

@dmisiek
Copy link

dmisiek commented Dec 6, 2024

Environment

Package version: 17.0.1 (latest)

Flutter doctor
Code sample
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: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  static const arrKey = 'arr';

  final FormGroup fg = FormGroup({
    arrKey: FormArray<String>(
      [],
      validators: [
        Validators.minLength(1),
      ],
    ),
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('FormArray bug'),
      ),
      body: SafeArea(
        child: ReactiveForm(
          formGroup: fg,
          child: ReactiveFormArray(
            formArrayName: arrKey,
            builder: (context, formArray, _) {
              return Column(
                children: [
                  Padding(
                    padding: const EdgeInsets.all(16),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceAround,
                      children: [
                        Text(
                          formArray.invalid ? "INVALID" : "VALID",
                          style: Theme.of(context)
                              .textTheme
                              .bodyLarge!
                              .copyWith(
                                color: formArray.hasErrors ? Colors.red : null,
                              ),
                        ),
                        Text(
                          formArray.touched ? "TOUCHED" : "NOT TOUCHED",
                          style: Theme.of(context)
                              .textTheme
                              .bodyLarge!
                              .copyWith(
                                color: formArray.touched ? Colors.red : null,
                              ),
                        ),
                        Text(
                          formArray.dirty ? "DIRTY" : "NOT DIRTY",
                          style:
                              Theme.of(context).textTheme.bodyLarge!.copyWith(
                                    color: formArray.dirty ? Colors.red : null,
                                  ),
                        ),
                      ],
                    ),
                  ),
                  if (formArray.invalid && formArray.touched)
                    Padding(
                      padding: const EdgeInsets.all(8),
                      child: Text(
                        formArray.errors.toString(),
                      ),
                    ),
                  Expanded(
                    child: ListView.builder(
                      itemCount: formArray.controls.length,
                      itemBuilder: (context, index) {
                        return Row(
                          children: [
                            Expanded(
                              child: Padding(
                                padding: const EdgeInsets.all(8.0),
                                child: ReactiveTextField(
                                  formControlName: index.toString(),
                                ),
                              ),
                            ),
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: IconButton(
                                onPressed: () => formArray.removeAt(index),
                                icon: const Icon(Icons.delete),
                              ),
                            )
                          ],
                        );
                      },
                    ),
                  ),
                  Container(
                    padding: const EdgeInsets.all(8),
                    child: FilledButton.tonal(
                      onPressed: () {
                        if (!formArray.dirty) formArray.markAsDirty();
                        if (!formArray.touched) formArray.markAsTouched();
                        formArray.add(FormControl<String>());
                      },
                      child: const Text("Add new form control"),
                    ),
                  ),
                  Container(
                    padding: const EdgeInsets.all(8),
                    child: FilledButton(
                      onPressed: () {
                        fg.markAllAsTouched();
                        ScaffoldMessenger.of(context).showSnackBar(
                          const SnackBar(
                            content: Text(
                              'All controls marked as touched',
                            ),
                          ),
                        );
                      },
                      child: const Text("Submit"),
                    ),
                  ),
                  Container(
                    padding: const EdgeInsets.all(8),
                    child: FilledButton(
                      onPressed: () {
                        final touched = fg.control(arrKey).touched ? 'touched' : 'not touched';
                        ScaffoldMessenger.of(context).showSnackBar(
                          SnackBar(
                            content: Text(
                              'FormArray is actually $touched',
                            ),
                          ),
                        );
                      },
                      child: const Text("Is actually touched?"),
                    ),
                  ),
                  Container(
                    padding: const EdgeInsets.only(top: 8, bottom: 48),
                    child: FilledButton.tonal(
                      onPressed: () {
                        setState(() {});
                      },
                      child: const Text("Force rebuild"),
                    ),
                  ),
                ],
              );
            },
          ),
        ),
      ),
    );
  }
}

https://github.com/dmisiek/form_array_touched_bug/blob/master/lib/main.dart

Description

Expected behavior:

FormArray rebuilds when is marked as touched or dirty.

I initialize FormArray with no controls (empty array) and MinLengthValidator(0). User can call markAllAsTouched() by pressing submit button any time he want. Doing this with empty FormArray should display an error.

Current behavior:

FormArray not rebuild when is marked as touched or dirty without interaction with its length (adding / removing item).

Steps to reproduce

  1. Initialize form with empty FormArray and MinLengthValidator(0).
  2. Call markAsTouched() on array or just markAllAsTouched()

The effect is form will not be sent (thats expected), but as well no error will be displayed to user (that seems to be a bug)

Video

Nagrywanie.2024-12-06.221304.mp4
@dmisiek dmisiek added the bug Something isn't working label Dec 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant