flutter_smart_forms 1.0.0 copy "flutter_smart_forms: ^1.0.0" to clipboard
flutter_smart_forms: ^1.0.0 copied to clipboard

A powerful, reactive, and dynamic form builder for Flutter supporting JSON-driven forms, conditional fields, validation, and custom UI components.

example/lib/main.dart

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'SmartForms Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const SmartFormFullDemo(),
    );
  }
}

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

  @override
  State<SmartFormFullDemo> createState() => _SmartFormFullDemoState();
}

class _SmartFormFullDemoState extends State<SmartFormFullDemo> {
  late SmartFormController controller;
  late List<FieldModel> fields;

  // ------------------ JSON Form ------------------
  final jsonForm = [
    {
      "type": "text",
      "key": "firstName",
      "label": "First Name",
      "placeholder": "Enter first name",
      "default": "Johna",
      "validators": "required|min:2",
    },
    {
      "type": "text",
      "key": "lastName",
      "label": "Last Name",
      "placeholder": "Enter last name",
      "visibleIf": {"firstName": "Johna"},
      "validators": "required",
    },
    {
      "type": "text",
      "key": "nickName",
      "label": "Nick Name",
      "placeholder": "Enter nick name",
      "validators": "required",
      "extra": {"disabled": true}
    },
    {
      "key": "email",
      "label": "Email Address",
      "placeholder": "Enter your email",
      "type": "text",
      "validators": "required|email",
      "extra": {
        "prefixIconAsset": null,
        "prefixIcon": "email",
        "prefixIconColor": "#1976D2",
        "suffixIconAsset": "assets/icons/refresh.svg",
        "suffixIconColor": "#1976D2",
        "fillColor": "0xFFFFFFFF",
        "borderColor": "#1976D2",
        "borderRadius": 12,
        "padding": {"left": 16, "top": 12, "right": 16, "bottom": 12},
        "disabled": false
      }
    },
    {
      "key": "password",
      "label": "Password",
      "placeholder": "Enter your password",
      "type": "password",
      "validators": "required|min:6",
      "extra": {
        "suffixIconAsset": null,
        "fillColor": "0xFFFFFFFF",
        "borderColor": "#1976D2",
        "borderRadius": 12,
        "padding": {"left": 16, "top": 12, "right": 16, "bottom": 12},
        "disabled": false
      }
    },
    {
      "type": "password",
      "key": "confirmPassword",
      "label": "Confirm Password",
      "validators": "required|match:password"
    },
    {
      "key": "phone",
      "label": "Phone Number",
      "placeholder": "Enter phone number",
      "type": "text",
      "validators": "required|phone",
      "extra": {
        "prefixIcon": "phone",
        "prefixIconColor": "#1976D2",
        "fillColor": "0xFFFFFFFF",
        "borderColor": "#1976D2",
        "borderRadius": 12,
        "padding": {"left": 16, "top": 12, "right": 16, "bottom": 12},
        "margin": {"left": 0, "top": 8, "right": 0, "bottom": 16},
        "disabled": false
      }
    },
    {
      "type": "barcode",
      "key": "barcode",
      "label": "Scan Product",
      "placeholder": "Scan or enter barcode",
      "validators": "required",
      "extra": {
        "prefixIcon": null,
        "prefixIconAsset": null,
        "prefixIconColor": "#1976D2",
        "suffixIconAsset": null,
        "suffixIcon": null,
        "suffixIconColor": null,
        "scannerTitle": "Barcode Scan",
        "scannerCenterTitle": true,
        "scannerAppBarColor": "#1976D2",
        "showClearIcon": true,
        "clearIcon": "close",
        "clearIconColor": "#1976D2",
        "readOnly": false,
        "disabled": false,
        "autoValidateBarcode": false,
        "barcodePattern": r"^[0-9]{8,14}$",
        "multiScan": false,
        "multiScanLimit": 10,
        "multiScanDelay": 800,
        "chipColorValid": "#4CAF50",
        "chipColorInvalid": "#F44336",
        "chipTextColor": "#FFFFFF",
        "showChipDelete": true,
        "scanButtonText": "Scan Products",
        "scanButtonHeight": 50,
        "scanButtonWidth": null,
        "scanButtonIcon": "qr_code_scanner",
        "scanButtonColor": "#1976D2",
        "scanButtonTextColor": "#FFFFFF",
        "scanButtonIconColor": "#FFFFFF",
        "scanButtonAlignment": "center", // or "start"
        "scanButtonPadding": {"left": 16, "top": 12, "right": 16, "bottom": 12},
        "fillColor": "0xFFFFFFFF",
        "borderColor": "#1976D2",
        "borderRadius": 12,
        "padding": {"left": 16, "top": 12, "right": 16, "bottom": 12},
        "margin": {"left": 0, "top": 8, "right": 0, "bottom": 16},
      },
    },
    {
      "type": "date",
      "key": "birthday",
      "label": "Select Birthday",
      "default": null,
      "extra": {
        "placeholder": "Pick a date",
        "format": "dd/MM/yyyy",
        "fillColor": "0xFFFFFFFF",
        "textColor": "#333333",
        "borderRadius": 10,
        "showClearIcon": true,
        "clearIcon": "close",
        "clearIconColor": "#1976D2",
        "readOnly": false,
        "disabled": false,
        "borderColor": "#AAAAAA",
        "padding": {"left": 12, "top": 10, "right": 12, "bottom": 10},
        "margin": {"left": 0, "top": 8, "right": 0, "bottom": 8},
        "suffixIconAsset": "assets/icons/calendar.png",
        "suffixIconColor": "#1976D2"
      }
    },
    {
      "type": "dropdown",
      "key": "country",
      "label": "Country",
      "default": "US",
      "valueKey": "id",
      "labelKey": "label",
      "extra": {
        "options": [
          {"id": 1, "value": "US", "label": "USA"},
          {"id": 2, "value": "CA", "label": "Canada"},
          {"id": 3, "value": "UK", "label": "United Kingdom"},
          {"id": 4, "value": "IN", "label": "India"},
          {"id": 5, "value": "IN2", "label": "Indi2"},
        ],
        "showClearIcon": true,
        "clearIcon": "close",
        "clearIconColor": "#1976D2",
        "readOnly": false,
        "disabled": false,
        "suffixIconAsset": "assets/icons/arrow_down.png",
        "fillColor": "0xFFFFFFFF",
        "textColor": "#333333",
        "borderColor": "#AAAAAA",
        "borderRadius": 12,
        "padding": {"left": 12, "top": 10, "right": 12, "bottom": 10},
        "margin": {"left": 0, "top": 8, "right": 0, "bottom": 8}
      }
    },
    {
      "type": "dropdown",
      "key": "state",
      "label": "State",
      "watchFields": ["country"],
      "visibleIf": {"country": "US"},
    },
    {
      "type": "dropdown",
      "key": "languages",
      "label": "Languages",
      "default": [1, 2],
      "extra": {
        "multiSelect": true,
        "nullable": false,
        "valueKey": "id",
        "labelKey": "label",
        "options": [
          {"id": 1, "value": "en", "label": "English"},
          {"id": 2, "value": "fr", "label": "French"},
          {"id": 3, "value": "es", "label": "Spanish"},
          {"id": 4, "value": "tam", "label": "Tamil"},
          {"id": 5, "value": "tam2", "label": "Tamil2"}
        ],
        'selectedChipColor': '#CCE5FF',
        'selectedChipTextColor': '#003366',
        "prefixIconAsset": null,
        "suffixIconAsset": null,
        "fillColor": "0xFFFFFFFF",
        "textColor": "#333333",
        "borderColor": "#AAAAAA",
        "borderRadius": 12,
        "padding": {"left": 12, "top": 10, "right": 12, "bottom": 10},
        "margin": {"left": 0, "top": 8, "right": 0, "bottom": 8}
      }
    },
    {
      "type": "suggestion",
      "key": "suggestion",
      "name": "country",
      "label": "Select Country",
      "placeholder": "Type or select",
      "isBarcode": false,
      "showAll": true,
      "valueKey": "id",
      "labelKey": "label",
      "extra": {
        "options": [
          {"id": 1, "value": "US", "label": "USA"},
          {"id": 2, "value": "CA", "label": "Canada"},
          {"id": 3, "value": "UK", "label": "United Kingdom"},
          {"id": 4, "value": "IN", "label": "India"},
          {"id": 5, "value": "IN2", "label": "Indi2"}
        ]
      }
    },
    {
      "type": "otp",
      "key": "otp",
      "label": "OTP",
      "validators": "required|min:6",
      "extra": {
        "length": 6,
        "boxSize": 50,
        "spacing": 10,
        "autoFocus": false,
        "obscure": false,
        "borderRadius": 8
      }
    },
    {
      "type": "checkbox",
      "key": "subscribe",
      "label": "Subscribe to newsletter",
      "default": true,
      "extra": {
        "readOnly": false,
        "disabled": false,
        "activeColor": "0xFF4CAF50",
        "checkColor": "0xFFFFFFFF",
        "borderColor": "0xFF888888",
        "iconColor": "0xFFFFFFFF",
        "borderRadius": 12,
        "size": 24,
        "padding": {"left": 0, "top": 8, "right": 0, "bottom": 16},
        "iconPosition": "prefix",
        "iconAsset": "assets/icons/custom_tick.svg",
        "icon": "check_circle_outline",
        "allowClear": true,
        "watchFields": ["subscribe"]
      }
    },
    {
      "type": "text",
      "key": "hiddenField",
      "label": "Hidden Field",
      "visibleIf": {"subscribe": true},
      "default": "This is hidden"
    },
    {
      "type": "array",
      "key": "addresses",
      "label": "Addresses",
      "extra": {
        "minItems": 1,
        "maxItems": 5,
        "reorderable": true,
        "animated": true,
        "addButtonText": "Add Address",
        "disabled": false,
        "readOnly": false,
        "padding": {"left": 16, "right": 16, "top": 10, "bottom": 10},
        "margin": {"top": 12, "bottom": 12}
      },
      "fields": [
        {"type": "text", "key": "street", "label": "Street"},
        {"type": "text", "key": "city", "label": "City"}
      ]
    },
    {
      "type": "array",
      "key": "orders",
      "label": "Orders (Nested Array)",
      "fields": [
        {"type": "text", "key": "product", "label": "Product"},
        {
          "type": "array",
          "key": "items",
          "label": "Items",
          "fields": [
            {"type": "text", "key": "name", "label": "Item Name"},
            {"type": "number", "key": "qty", "label": "Qty"}
          ]
        }
      ]
    },
    {
      "type": "signature",
      "key": "signature",
      "label": "Signature",
      "extra": {
        "height": 180,
        "strokeWidth": 2,
        "borderRadius": 10,
        "grid": true,
        "undo": true,
        "preview": true,
        "fullscreen": true,
        "save": true,
        "showClearButton": true,
        "borderColor": "#E0E0E0",
        "backgroundColor": "#FFFFFF",
        "penColor": "#000000"
      }
    },
    {
      "type": "file",
      "key": "resume",
      "label": "Upload Resume",
      "extra": {
        "uploadText": "Upload Resume",
        "uploadIcon": "cloud",
        "multiple": true,
        "preview": true,
        "removable": true,
        "extensions": ["pdf", "doc", "docx", "png", "jpg"],
        "maxSize": 5000000,
        "padding": {"left": 16, "top": 12, "right": 16, "bottom": 12},
        "align": "start",
        "maxFiles": 5,
        "compress": true,
        "compressQuality": 75,
        "uploadHeight": 50,
        "uploadWidth": null,
        "previewHeight": 60,
        "previewWidth": 60,
        "borderRadius": 16,
        "gradient": true,
        "buttonColorStart": "0xFF888888",
        "buttonColorEnd": "#00f2fe"
      }
    },
    {
      "type": "image",
      "key": "profile",
      "label": "Upload Profile Image",
      "extra": {
        "uploadText": "Upload Image",
        "uploadIcon": "cloud",
        "camera": true,
        "gallery": true,
        "multiple": true,
        "maxFiles": 2,
        "preview": true,
        "removable": true,
        "compress": true,
        "compressQuality": 75,
        "extensions": ["jpg", "jpeg", "png", "webp"],
        "maxSize": 5000000,
        "crop": true,
        "cropStyle": "rectangle",
        "cropAspectRatio": {"x": 1, "y": 1},
        "cropBaseColor": "#000000",
        "cropMaskColor": "#00000088",
        "returnType": "file",
        "align": "center",
        "uploadHeight": 50,
        "uploadWidth": null,
        "previewHeight": 60,
        "previewWidth": 60,
        "borderRadius": 16,
        "gradient": true,
        "buttonColorStart": "0xFF888888",
        "buttonColorEnd": "#00f2fe"
      }
    },
  ];

  // ---------------- Direct FieldModel list ----------------
  final directFields = [
    FieldModel(
      type: 'text',
      key: 'firstName2',
      label: 'First Name',
      placeholder: 'Enter first name',
      defaultValue: 'Alice',
      extra: {'disabled': true},
    ),
    FieldModel(
      type: 'text',
      key: 'lastName2',
      label: 'Last Name',
      defaultValue: 'R',
      placeholder: 'Enter last name',
    ),
    FieldModel(
      type: 'text',
      key: 'fullName',
      label: 'Full Name',
      defaultValueCallback: (values) {
        // dynamically combine first & last name
        final first = values['firstName2'] ?? '';
        final last = values['lastName2'] ?? '';
        return '$first $last';
      },
    ),
    FieldModel(
      key: "email",
      label: "Email Address",
      placeholder: "Enter your email",
      type: "text",
      validators: "required|email",
      extra: {
        "prefixIconAsset": null,
        "prefixIcon": "email",
        "prefixIconColor": "#1976D2",
        "suffixIconAsset": null,
        "suffixIcon": null,
        "suffixIconColor": "#1976D2",
        "fillColor": "#E3F2FD",
        "borderColor": "#1976D2",
        "borderRadius": 12,
        "padding": {"left": 16, "top": 12, "right": 16, "bottom": 12},
        "disabled": false
      },
    ),
    FieldModel(
      key: "password",
      label: "Password",
      placeholder: "Enter your password",
      type: "password",
      validators: "required|min:6",
      extra: {
        "prefixIcon": "lock",
        "prefixIconColor": "#1976D2",
        "suffixIconAsset": null,
        "fillColor": "#E3F2FD",
        "borderColor": "#1976D2",
        "borderRadius": 12,
        "padding": {"left": 16, "top": 12, "right": 16, "bottom": 12},
        "disabled": false
      },
    ),
    FieldModel(
      key: "phone",
      label: "Phone Number",
      placeholder: "Enter phone number",
      type: "text",
      validators: "required|phone",
      extra: {
        "prefixIcon": "phone",
        "prefixIconColor": "#1976D2",
        "fillColor": "#E3F2FD",
        "borderColor": "#1976D2",
        "borderRadius": 12,
        "padding": {"left": 16, "top": 12, "right": 16, "bottom": 12},
        "disabled": false
      },
    ),
    FieldModel(
      type: "barcode",
      key: "barcode",
      label: "Scan Product",
      placeholder: "Scan or enter barcode",
      validators: "required",
      extra: {
        "prefixIcon": null,
        "prefixIconAsset": null,
        "prefixIconColor": "#1976D2",
        "suffixIconAsset": null,
        "suffixIcon": "qr_code",
        "suffixIconColor": "#1976D2",
        "scannerTitle": "Barcode Scan",
        "scannerCenterTitle": true,
        "scannerAppBarColor": "#FF5722",
        "fillColor": "0xFFFFFFFF",
        "borderColor": "#1976D2",
        "borderRadius": 12,
        "padding": {"left": 16, "top": 12, "right": 16, "bottom": 12},
        "disabled": false
      },
    ),
    FieldModel(
      type: 'dropdown',
      key: 'country',
      label: 'Country',
      defaultValue: 'US',
      extra: {
        "options": [
          {"value": "US", "label": "USA"},
          {"value": "CA", "label": "Canada"},
          {"value": "UK", "label": "United Kingdom"}
        ],
        "suffixIconAsset": "assets/icons/arrow_down.png",
        "fillColor": "0xFFFFFFFF",
        "textColor": "#333333",
        "borderColor": "#AAAAAA",
        "borderRadius": 12,
        "padding": {"left": 12, "top": 10, "right": 12, "bottom": 10},
        "margin": {"left": 0, "top": 8, "right": 0, "bottom": 8}
      },
    ),
    FieldModel(
      type: 'text',
      key: 'state2',
      label: 'State',
      placeholder: 'Enter your state',
      visibleIf: {'country2': 'US'},
    ),
    FieldModel(
      type: 'dropdown',
      key: 'languages2',
      label: 'Languages',
      defaultValue: ['en', 'fr'],
      extra: {
        'multiSelect': true,
        'nullable': false,
        'valueKey': 'value',
        'labelKey': 'label',
        'options': [
          {'value': 'en', 'label': 'English'},
          {'value': 'fr', 'label': 'French'},
          {'value': 'es', 'label': 'Spanish'}
        ],
        // Modern UI extras
        'selectedChipColor': '#CCE5FF',
        'selectedChipTextColor': '#003366',
        'prefixIconAsset': null, // optional, default null
        'suffixIconAsset': null, // optional, default null
        'fillColor': '0xFFFFFFFF',
        'textColor': '#333333',
        'borderColor': '#AAAAAA',
        'borderRadius': 12,
        'padding': {'left': 12, 'top': 10, 'right': 12, 'bottom': 10},
        'margin': {'left': 0, 'top': 8, 'right': 0, 'bottom': 8},
      },
    ),
    FieldModel(
      type: 'checkbox',
      key: 'subscribe2',
      label: 'Subscribe to newsletter',
      defaultValue: true,
      extra: {
        "activeColor": "0xFF4CAF50",
        "checkColor": "0xFFFFFFFF",
        "borderColor": "0xFF888888",
        "iconColor": "0xFFFFFFFF",
        "borderRadius": 12,
        "size": 24,
        "padding": {"left": 0, "top": 8, "right": 0, "bottom": 16},
        "iconPosition": "suffix",
        "iconAsset": "assets/icons/custom_tick.svg",
      },
    ),
    FieldModel(
      type: 'otp',
      key: 'otpCode2',
      label: 'OTP Code',
      defaultValue: '',
    ),
    FieldModel(
      type: 'date',
      key: 'dob2',
      label: 'Date of Birth',
      defaultValue: '2000-01-01',
      extra: {
        "placeholder": "Pick a date",
        "format": "dd/MM/yyyy",
        "fillColor": "0xFFFFFFFF",
        "textColor": "#333333",
        "borderRadius": 10,
        "borderColor": "#AAAAAA",
        "padding": {"left": 12, "top": 10, "right": 12, "bottom": 10},
        "margin": {"left": 0, "top": 8, "right": 0, "bottom": 8},
        "suffixIconAsset": "assets/icons/calendar.png",
        "suffixIconColor": "#FF0000",
      },
    ),
    FieldModel(
      type: 'signature',
      key: 'signature2',
      label: 'Signature',
    ),
    FieldModel(
      type: 'file',
      key: 'upload2',
      label: 'Upload Document',
    ),
    FieldModel(
      type: 'text',
      key: 'hidden2',
      label: 'Hidden Field',
      visibleIf: {'subscribe2': true},
      defaultValue: 'This is hidden',
    ),
  ];

  // ---------------- Nested Conditional Fields ----------------
  final nestedFields = [
    FieldModel(
      type: 'dropdown',
      key: 'vehicle',
      label: 'Select Vehicle',
      defaultValue: 'car',
      extra: {
        'options': [
          {'value': 'car', 'label': 'Car'},
          {'value': 'bike', 'label': 'Bike'},
          {'value': 'truck', 'label': 'Truck'}
        ],
        'valueKey': 'value',
        'labelKey': 'label',
      },
    ),
    FieldModel(
      type: 'dropdown',
      key: 'carBrand',
      label: 'Car Brand',
      visibleIf: {'vehicle': 'car'},
      extra: {
        'options': [
          {'value': 'bmw', 'label': 'BMW'},
          {'value': 'audi', 'label': 'Audi'},
          {'value': 'tesla', 'label': 'Tesla'}
        ],
        'valueKey': 'value',
        'labelKey': 'label',
      },
    ),
    FieldModel(
      type: 'dropdown',
      key: 'bikeBrand',
      label: 'Bike Brand',
      visibleIf: {'vehicle': 'bike'},
      extra: {
        'options': [
          {'value': 'yamaha', 'label': 'Yamaha'},
          {'value': 'honda', 'label': 'Honda'},
          {'value': 'ducati', 'label': 'Ducati'}
        ],
        'valueKey': 'value',
        'labelKey': 'label',
      },
    ),
    FieldModel(
      type: 'dropdown',
      key: 'truckBrand',
      label: 'Truck Brand',
      visibleIf: {'vehicle': 'truck'},
      extra: {
        'options': [
          {'value': 'volvo', 'label': 'Volvo'},
          {'value': 'scania', 'label': 'Scania'},
          {'value': 'man', 'label': 'MAN'}
        ],
        'valueKey': 'value',
        'labelKey': 'label',
      },
    ),
    FieldModel(
      type: 'dropdown',
      key: 'carOptions',
      label: 'Car Options',
      visibleIf: {
        'vehicle': 'car',
        'carBrand': 'tesla',
      },
      extra: {
        'multiSelect': true,
        'nullable': true,
        'options': [
          {'value': 'autopilot', 'label': 'Autopilot'},
          {'value': 'full_self', 'label': 'Full Self Driving'},
          {'value': 'premium', 'label': 'Premium Interior'}
        ],
        'valueKey': 'value',
        'labelKey': 'label',
      },
    ),
  ];

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

    controller = SmartFormController(
      formTheme: FormTheme(
        inputDecoration: InputDecoration(fillColor: Colors.grey[100]),
        labelStyle: const TextStyle(fontWeight: FontWeight.bold),
        hintStyle: const TextStyle(fontWeight: FontWeight.normal, fontSize: 12),
        inputTextStyle: const TextStyle(fontSize: 16),
        padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
      ),
      commonFieldTheme: const FieldTheme(
        borderColor: Colors.grey,
        borderRadius: 8,
        fillColor: Colors.white,
      ),
      fieldThemes: {
        "firstName": const FieldTheme(
          borderColor: Colors.blue,
          borderRadius: 12,
          fillColor: Colors.white,
        ),
      },
    );

    fields = JsonFormBuilder.fromJson(jsonForm);
  }

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

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 5,
      child: Scaffold(
        appBar: AppBar(
          title: const Text("SmartForms Demo"),
          bottom: const TabBar(
            tabs: [
              Tab(text: "JSON Form"),
              Tab(text: "Fields + Children"),
              Tab(text: "Direct Widgets"),
              Tab(text: "Nested Conditional"),
              Tab(text: "RealTime Example"),
            ],
          ),
        ),
        body: TabBarView(
          children: [
            // Tab 1: JSON Form
            buildFormTab(controller, jsonForm),
            // Tab 2: Fields + Children
            buildFormTab(controller, fields),
            // Tab 3: Direct Widgets
            buildFormTab(controller, directFields),
            // Tab 4: Nested Conditional
            buildFormTab(controller, nestedFields),
            // Tab 5: RealTime Example
            SmartFormRealtimeExample(),
          ],
        ),
      ),
    );
  }

  /// Helper to build SmartForm
  Widget buildFormTab(SmartFormController ctrl, dynamic formData) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: SingleChildScrollView(
        child: Column(
          children: [
            SmartForm(
              controller: ctrl,
              fields: formData is List<FieldModel> ? formData : null,
              json: formData is List<Map<String, dynamic>> ? formData : null,
              submitButton: Container(
                padding: const EdgeInsets.all(16),
                decoration: BoxDecoration(
                  color: Colors.black,
                  borderRadius: BorderRadius.circular(10),
                ),
                child: const Center(
                  child: Text(
                    "Save",
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              ),
              onSubmit: (values) {
                if (ctrl.validate()) {
                  showDialog(
                    context: context,
                    builder: (_) => AlertDialog(
                      title: const Text("Form Values"),
                      content:
                          SingleChildScrollView(child: Text(values.toString())),
                      actions: [
                        TextButton(
                          onPressed: () => Navigator.pop(context),
                          child: const Text("Close"),
                        )
                      ],
                    ),
                  );
                }
              },
            ),
            const SizedBox(height: 16),
            // Reset Button
            ElevatedButton.icon(
              onPressed: () {
                // Reset the form
                ctrl.reset(
                  preserveKeys: [
                    // Add any system fields here you want to preserve
                    //'token',
                  ],
                );
                ScaffoldMessenger.of(context).showSnackBar(
                  const SnackBar(content: Text("Form Reset!")),
                );
              },
              icon: const Icon(Icons.refresh),
              label: const Text("Reset Form"),
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.redAccent,
                padding:
                    const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

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

  @override
  State<SmartFormRealtimeExample> createState() =>
      _SmartFormRealtimeExampleState();
}

class _SmartFormRealtimeExampleState extends State<SmartFormRealtimeExample> {
  final controller = SmartFormController();

  final jsonForm = [
    {
      "type": "text",
      "key": "productName",
      "label": "Product Name",
      "placeholder": "Auto filled from barcode"
    },
    {
      "type": "barcode",
      "key": "barcode",
      "label": "Scan Product",
      "placeholder": "Scan barcode",
    },
    {
      "type": "dropdown",
      "key": "country",
      "label": "Country",
      "default": "US",
      "extra": {
        "options": [
          {"value": "US", "label": "USA"},
          {"value": "IN", "label": "India"},
          {"value": "CA", "label": "Canada"}
        ]
      }
    },
    {
      "type": "dropdown",
      "key": "state",
      "label": "State",
      "watchFields": ["country"],
      "extra": {"options": []}
    },
    {"type": "checkbox", "key": "subscribe", "label": "Subscribe"}
  ];

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

    WidgetsBinding.instance.addPostFrameCallback((_) {
      controller.getNotifier("country")?.addListener(() {
        final country = controller.getValue("country");
        if (country != null) _handleCountry(country);
      });
    });
  }

  void _handleCountry(String country) {
    List states = [];
    if (country == "US") {
      states = [
        {"value": "CA", "label": "California"},
        {"value": "TX", "label": "Texas"}
      ];
    } else if (country == "IN") {
      states = [
        {"value": "TN", "label": "Tamil Nadu"},
        {"value": "KL", "label": "Kerala"}
      ];
    }

    // 1️⃣ Reset the value first
    controller.setValue("state", null, validate: false);

    // 2️⃣ Update the options (this triggers the dropdown rebuild)
    controller.updateFieldExtra("state", {"options": states});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("SmartForm Realtime Example")),
      body: SmartForm(
        controller: controller,
        json: jsonForm,
        onSubmit: (values) {
          showDialog(
            context: context,
            builder: (_) => AlertDialog(
              title: const Text("Form Data"),
              content: Text(values.toString()),
            ),
          );
        },
      ),
    );
  }
}
1
likes
0
points
279
downloads

Documentation

Documentation

Publisher

unverified uploader

Weekly Downloads

A powerful, reactive, and dynamic form builder for Flutter supporting JSON-driven forms, conditional fields, validation, and custom UI components.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

crop_your_image, file_picker, flutter, flutter_image_compress, flutter_svg, flutter_typeahead, image_picker, intl, mobile_scanner, multi_select_flutter, path_provider, pinput, signature

More

Packages that depend on flutter_smart_forms