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

FormBuilder and Tabbed/Paged forms #1426

Open
7 tasks done
divan opened this issue Sep 12, 2024 · 4 comments
Open
7 tasks done

FormBuilder and Tabbed/Paged forms #1426

divan opened this issue Sep 12, 2024 · 4 comments
Labels
bug Something isn't working

Comments

@divan
Copy link

divan commented Sep 12, 2024

Is there an existing issue for this?

  • I have searched the existing issues

Package/Plugin version

9.4.1

Platforms

  • Android
  • iOS
  • Linux
  • MacOS
  • Web
  • Windows

Flutter doctor

Flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.24.1, on macOS 14.5 23F79 darwin-arm64, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 15.4)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2023.1)
[✓] VS Code (version 1.86.1) - but I use vim

Minimal code example

FormBuilder(
      key: _formKey,
      initialValue: widget.initialValues,
      autovalidateMode: AutovalidateMode.disabled,
      child: DefaultTabController(
      length: 2,
      child: Scaffold(
        appBar: AppBar(
          bottom: const TabBar(
            tabs: myTabs,
          ),
        ),
        body: TabBarView(
          children: myTabs.map((Tab tab) {
            return _buildFieldsForTab(tab);
          }).toList(),
        ),
      ),
    );

Current Behavior

The issue is well described here: #462

As form grows, it's natural to split fields into few tabs/pages. As soon as it's happens (using default Flutter widgets), fields in the "hidden" tabs/pages aren't initialized. When form is submitted, these fields are absent, which is incorrect behavior.

Expected Behavior

There is a solution to use tabbed forms with FormBuilder.

It's more likely could be another way to initialize fields with initial values.

Steps To Reproduce

Run code as described

Aditional information

No response

@divan divan added the bug Something isn't working label Sep 12, 2024
@divan
Copy link
Author

divan commented Sep 12, 2024

Related: #1366

@divan
Copy link
Author

divan commented Sep 12, 2024

Basically, as soon as tabs/pages are added to form, it will stop working and submitting all fields (unless user clicked all tabs manually).

The problem is on intersection of two issues:

  1. How Tabs/Pages work in flutter (not building all tabs)
  2. How FormBuilder deals with initialization of the fields' state.

I could not find any decent solution for 1. What people seem to be doing is doing hacks with animating to each tab and showing it upon initialization. Even creating packages for that.

@divan
Copy link
Author

divan commented Sep 13, 2024

If anyone is interested for workaround for tabbed forms, here is a version of tabbar that works for me (it uses IndexedStack to show all the tabs):

class FormTabBar extends StatefulWidget {
  final List<String> keys;
  final List<Widget> pages;

  const FormTabBar({required this.keys, required this.pages, super.key})
      : assert(keys.length == pages.length,
            'keys and pages must have the same length');

  @override
  State<FormTabBar> createState() => _FormTabBarState();
}

class _FormTabBarState extends State<FormTabBar>
    with SingleTickerProviderStateMixin {
  TabController? _tabController;

  @override
  initState() {
    super.initState();
    _tabController = TabController(length: widget.keys.length, vsync: this);
  }

  @override
  dispose() {
    _tabController!.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TabBar(
          controller: _tabController,
          isScrollable: false,
          indicatorSize: TabBarIndicatorSize.tab,
          tabs: widget.keys.map((e) => Tab(text: e)).toList(growable: false),
          onTap: (index) {
            setState(() {
              _tabController!.index = index;
            });
          },
        ),
        Expanded(
          child: IndexedStack(
            index: _tabController!.index,
            children: widget.pages,
          ),
        ),
      ],
    );
  }
}

@RanjanKiran707
Copy link

Actually same goes while using the ListView.builder widget for form widgets.
If form is long, then not all widgets are rendered so submitting you will only get some field's value.

For this I added cacheExtent: 1000, so all the form widgets are rendered

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

2 participants