# फ़ॉर्म्स

<div id="introduction"></div>

## परिचय

Nylo v7 `NyFormWidget` के इर्द-गिर्द बना एक फ़ॉर्म सिस्टम प्रदान करता है। आपकी फ़ॉर्म क्लास `NyFormWidget` को एक्सटेंड करती है और **स्वयं** विजेट है -- किसी अलग रैपर की आवश्यकता नहीं। फ़ॉर्म्स बिल्ट-इन वैलिडेशन, कई फ़ील्ड प्रकार, स्टाइलिंग और डेटा प्रबंधन को सपोर्ट करते हैं।

``` dart
import 'package:nylo_framework/nylo_framework.dart';

// 1. Define a form
class LoginForm extends NyFormWidget {
  LoginForm({super.key, super.submitButton, super.onSubmit, super.onFailure});

  @override
  fields() => [
    Field.email("Email", validator: FormValidator.email()),
    Field.password("Password", validator: FormValidator.password()),
  ];

  static NyFormActions get actions => const NyFormActions('LoginForm');
}

// 2. Display and submit it
LoginForm(
  submitButton: Button.primary(text: "Login"),
  onSubmit: (data) {
    print(data); // {email: "...", password: "..."}
  },
)
```


<div id="creating-forms"></div>

## फ़ॉर्म बनाना

नया फ़ॉर्म बनाने के लिए Metro CLI का उपयोग करें:

``` bash
metro make:form LoginForm
```

यह `lib/app/forms/login_form.dart` बनाता है:

``` dart
import 'package:nylo_framework/nylo_framework.dart';

class LoginForm extends NyFormWidget {
  LoginForm({super.key, super.submitButton, super.onSubmit, super.onFailure});

  @override
  fields() => [
    Field.email("Email", validator: FormValidator.email()),
    Field.password("Password", validator: FormValidator.password()),
  ];

  static NyFormActions get actions => const NyFormActions('LoginForm');
}
```

फ़ॉर्म्स `NyFormWidget` को एक्सटेंड करते हैं और फ़ॉर्म फ़ील्ड्स डिफ़ाइन करने के लिए `fields()` मेथड को ओवरराइड करते हैं। प्रत्येक फ़ील्ड `Field.text()`, `Field.email()`, या `Field.password()` जैसे नेम्ड कंस्ट्रक्टर का उपयोग करता है। `static NyFormActions get actions` गेटर आपके ऐप में कहीं से भी फ़ॉर्म के साथ इंटरैक्ट करने का एक सुविधाजनक तरीका प्रदान करता है।


<div id="displaying-a-form"></div>

## फ़ॉर्म प्रदर्शित करना

चूँकि आपकी फ़ॉर्म क्लास `NyFormWidget` को एक्सटेंड करती है, यह **स्वयं** विजेट है। इसे सीधे अपने विजेट ट्री में उपयोग करें:

``` dart
@override
Widget view(BuildContext context) {
  return Scaffold(
    body: SafeArea(
      child: LoginForm(
        submitButton: Button.primary(text: "Submit"),
        onSubmit: (data) {
          print(data);
        },
      ),
    ),
  );
}
```


<div id="submitting-a-form"></div>

## फ़ॉर्म सबमिट करना

फ़ॉर्म सबमिट करने के तीन तरीके हैं:

### onSubmit और submitButton का उपयोग करना

फ़ॉर्म बनाते समय `onSubmit` और एक `submitButton` पास करें। Nylo प्री-बिल्ट बटन प्रदान करता है जो सबमिट बटन के रूप में काम करते हैं:

``` dart
LoginForm(
  submitButton: Button.primary(text: "Submit"),
  onSubmit: (data) {
    print(data); // {email: "...", password: "..."}
  },
  onFailure: (errors) {
    print(errors.first.rule.getMessage());
  },
)
```

उपलब्ध बटन स्टाइल: `Button.primary`, `Button.secondary`, `Button.outlined`, `Button.textOnly`, `Button.icon`, `Button.gradient`, `Button.rounded`, `Button.transparency`।

### NyFormActions का उपयोग करना

कहीं से भी सबमिट करने के लिए `actions` गेटर का उपयोग करें:

``` dart
LoginForm.actions.submit(
  onSuccess: (data) {
    print(data);
  },
  onFailure: (errors) {
    print(errors.first.rule.getMessage());
  },
  showToastError: true,
);
```

### NyFormWidget.submit() स्टैटिक मेथड का उपयोग करना

कहीं से भी नाम से फ़ॉर्म सबमिट करें:

``` dart
NyFormWidget.submit("LoginForm",
  onSuccess: (data) {
    print(data);
  },
  onFailure: (errors) {
    print(errors.first.rule.getMessage());
  },
  showToastError: true,
);
```

सबमिट करने पर, फ़ॉर्म सभी फ़ील्ड्स को वैलिडेट करता है। यदि मान्य है, तो `onSuccess` को फ़ील्ड डेटा के `Map<String, dynamic>` के साथ कॉल किया जाता है (कीज़ फ़ील्ड नामों के snake_case वर्ज़न हैं)। यदि अमान्य है, तो डिफ़ॉल्ट रूप से टोस्ट एरर दिखाया जाता है और यदि प्रदान किया गया हो तो `onFailure` कॉल किया जाता है।


<div id="field-types"></div>

## फ़ील्ड प्रकार

Nylo v7 `Field` क्लास पर नेम्ड कंस्ट्रक्टर्स के माध्यम से 22 फ़ील्ड प्रकार प्रदान करता है। सभी फ़ील्ड कंस्ट्रक्टर्स ये सामान्य पैरामीटर्स साझा करते हैं:

| पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण |
|-----------|------|---------|-------------|
| `key` | `String` | आवश्यक | फ़ील्ड पहचानकर्ता (पोज़िशनल) |
| `label` | `String?` | `null` | कस्टम डिस्प्ले लेबल (डिफ़ॉल्ट रूप से टाइटल केस में कुंजी) |
| `value` | `dynamic` | `null` | इनिशियल वैल्यू |
| `validator` | `FormValidator?` | `null` | वैलिडेशन नियम |
| `autofocus` | `bool` | `false` | लोड पर ऑटो-फ़ोकस |
| `dummyData` | `String?` | `null` | टेस्ट/डेवलपमेंट डेटा |
| `header` | `Widget?` | `null` | फ़ील्ड के ऊपर प्रदर्शित विजेट |
| `footer` | `Widget?` | `null` | फ़ील्ड के नीचे प्रदर्शित विजेट |
| `titleStyle` | `TextStyle?` | `null` | कस्टम लेबल टेक्स्ट स्टाइल |
| `hidden` | `bool` | `false` | फ़ील्ड छुपाएँ |
| `readOnly` | `bool?` | `null` | फ़ील्ड को रीड-ओनली बनाएँ |
| `style` | `FieldStyle?` | भिन्न | फ़ील्ड-विशिष्ट स्टाइल कॉन्फ़िगरेशन |
| `onChanged` | `Function(dynamic)?` | `null` | वैल्यू बदलने पर कॉलबैक |

<div id="text-fields"></div>

### टेक्स्ट फ़ील्ड्स

``` dart
Field.text("Name")

Field.text("Name",
  value: "John",
  validator: FormValidator.notEmpty(),
  autofocus: true,
)
```

स्टाइल प्रकार: `FieldStyleTextField`

<div id="number-fields"></div>

### नंबर फ़ील्ड्स

``` dart
Field.number("Age")

// दशमलव संख्याएँ
Field.number("Score", decimal: true)
```

`decimal` पैरामीटर यह नियंत्रित करता है कि दशमलव इनपुट की अनुमति है या नहीं। स्टाइल प्रकार: `FieldStyleTextField`

<div id="password-fields"></div>

### पासवर्ड फ़ील्ड्स

``` dart
Field.password("Password")

// विज़िबिलिटी टॉगल के साथ
Field.password("Password", viewable: true)
```

`viewable` पैरामीटर दिखाने/छुपाने का टॉगल जोड़ता है। स्टाइल प्रकार: `FieldStyleTextField`

<div id="email-fields"></div>

### ईमेल फ़ील्ड्स

``` dart
Field.email("Email", validator: FormValidator.email())
```

स्वचालित रूप से ईमेल कीबोर्ड प्रकार सेट करता है और व्हाइटस्पेस फ़िल्टर करता है। स्टाइल प्रकार: `FieldStyleTextField`

<div id="url-fields"></div>

### URL फ़ील्ड्स

``` dart
Field.url("Website", validator: FormValidator.url())
```

URL कीबोर्ड प्रकार सेट करता है। स्टाइल प्रकार: `FieldStyleTextField`

<div id="text-area-fields"></div>

### टेक्स्ट एरिया फ़ील्ड्स

``` dart
Field.textArea("Description")
```

मल्टी-लाइन टेक्स्ट इनपुट। स्टाइल प्रकार: `FieldStyleTextField`

<div id="phone-number-fields"></div>

### फ़ोन नंबर फ़ील्ड्स

``` dart
Field.phoneNumber("Mobile Phone")
```

स्वचालित रूप से फ़ोन नंबर इनपुट को फ़ॉर्मेट करता है। स्टाइल प्रकार: `FieldStyleTextField`

<div id="capitalize-words-fields"></div>

### शब्द कैपिटलाइज़

``` dart
Field.capitalizeWords("Full Name")
```

प्रत्येक शब्द के पहले अक्षर को कैपिटलाइज़ करता है। स्टाइल प्रकार: `FieldStyleTextField`

<div id="capitalize-sentences-fields"></div>

### वाक्य कैपिटलाइज़

``` dart
Field.capitalizeSentences("Bio")
```

प्रत्येक वाक्य के पहले अक्षर को कैपिटलाइज़ करता है। स्टाइल प्रकार: `FieldStyleTextField`

<div id="date-fields"></div>

### डेट फ़ील्ड्स

``` dart
Field.date("Birthday")

Field.date("Birthday",
  dummyData: "1990-01-01",
  style: FieldStyleDateTimePicker(
    firstDate: DateTime(1900),
    lastDate: DateTime.now(),
  ),
)

// क्लियर बटन निष्क्रिय करें
Field.date("Birthday",
  style: FieldStyleDateTimePicker(
    canClear: false,
  ),
)

// कस्टम क्लियर आइकन
Field.date("Birthday",
  style: FieldStyleDateTimePicker(
    clearIconData: Icons.close,
  ),
)
```

डेट पिकर खोलता है। डिफ़ॉल्ट रूप से, फ़ील्ड एक क्लियर बटन दिखाता है जो उपयोगकर्ताओं को मान रीसेट करने देता है। इसे छिपाने के लिए `canClear: false` सेट करें, या आइकन बदलने के लिए `clearIconData` का उपयोग करें। स्टाइल प्रकार: `FieldStyleDateTimePicker`

<div id="datetime-fields"></div>

### DateTime फ़ील्ड्स

``` dart
Field.datetime("Check in Date")

Field.datetime("Appointment",
  firstDate: DateTime(2025),
  lastDate: DateTime(2030),
  dateFormat: DateFormat('yyyy-MM-dd HH:mm'),
  initialPickerDateTime: DateTime.now(),
)
```

डेट और टाइम पिकर खोलता है। आप `firstDate`, `lastDate`, `dateFormat` और `initialPickerDateTime` को सीधे टॉप-लेवल पैरामीटर के रूप में सेट कर सकते हैं। स्टाइल प्रकार: `FieldStyleDateTimePicker`

<div id="masked-input-fields"></div>

### मास्क्ड इनपुट फ़ील्ड्स

``` dart
Field.mask("Phone", mask: "(###) ###-####")

Field.mask("Credit Card", mask: "#### #### #### ####")

Field.mask("Custom Code",
  mask: "AA-####",
  match: r'[\w\d]',
  maskReturnValue: true, // फ़ॉर्मेट की गई वैल्यू रिटर्न करता है
)
```

मास्क में `#` कैरेक्टर यूज़र इनपुट द्वारा बदल दिया जाता है। अनुमत कैरेक्टर्स को नियंत्रित करने के लिए `match` का उपयोग करें। जब `maskReturnValue` `true` है, तो रिटर्न की गई वैल्यू में मास्क फ़ॉर्मेटिंग शामिल होती है।

<div id="currency-fields"></div>

### करेंसी फ़ील्ड्स

``` dart
Field.currency("Price", currency: "usd")
```

`currency` पैरामीटर आवश्यक है और करेंसी फ़ॉर्मेट निर्धारित करता है। स्टाइल प्रकार: `FieldStyleTextField`

<div id="checkbox-fields"></div>

### चेकबॉक्स फ़ील्ड्स

``` dart
Field.checkbox("Accept Terms")

Field.checkbox("Agree to terms",
  header: Text("Terms and conditions"),
  footer: Text("You must agree to continue."),
  validator: FormValidator.booleanTrue(message: "You must accept the terms"),
)
```

स्टाइल प्रकार: `FieldStyleCheckbox`

<div id="switch-box-fields"></div>

### स्विच बॉक्स फ़ील्ड्स

``` dart
Field.switchBox("Enable Notifications")
```

स्टाइल प्रकार: `FieldStyleSwitchBox`

<div id="picker-fields"></div>

### पिकर फ़ील्ड्स

``` dart
Field.picker("Category",
  options: FormCollection.from(["Electronics", "Clothing", "Books"]),
)

// की-वैल्यू जोड़ों के साथ
Field.picker("Country",
  options: FormCollection.fromMap({
    "us": "United States",
    "ca": "Canada",
    "uk": "United Kingdom",
  }),
)
```

`options` पैरामीटर के लिए `FormCollection` आवश्यक है (रॉ लिस्ट नहीं)। विवरण के लिए [FormCollection](#form-collection) देखें। स्टाइल प्रकार: `FieldStylePicker`

#### लिस्ट टाइल स्टाइल

आप `PickerListTileStyle` का उपयोग करके पिकर के बॉटम शीट में आइटम्स की दिखावट को कस्टमाइज़ कर सकते हैं। डिफ़ॉल्ट रूप से, बॉटम शीट सादे टेक्स्ट टाइल्स दिखाता है। सिलेक्शन इंडिकेटर जोड़ने के लिए बिल्ट-इन प्रीसेट्स का उपयोग करें, या पूरी तरह से कस्टम बिल्डर प्रदान करें।

**रेडियो स्टाइल** — लीडिंग विजेट के रूप में रेडियो बटन आइकन दिखाता है:

``` dart
Field.picker("Country",
  options: FormCollection.from(["United States", "Canada", "United Kingdom"]),
  style: FieldStylePicker(
    listTileStyle: PickerListTileStyle.radio(),
  ),
)

// कस्टम एक्टिव कलर के साथ
FieldStylePicker(
  listTileStyle: PickerListTileStyle.radio(activeColor: Colors.blue),
)
```

**चेकमार्क स्टाइल** — सिलेक्ट होने पर ट्रेलिंग विजेट के रूप में चेक आइकन दिखाता है:

``` dart
Field.picker("Category",
  options: FormCollection.from(["Electronics", "Clothing", "Books"]),
  style: FieldStylePicker(
    listTileStyle: PickerListTileStyle.checkmark(activeColor: Colors.green),
  ),
)
```

**कस्टम बिल्डर** — प्रत्येक टाइल के विजेट पर पूर्ण नियंत्रण:

``` dart
Field.picker("Color",
  options: FormCollection.from(["Red", "Green", "Blue"]),
  style: FieldStylePicker(
    listTileStyle: PickerListTileStyle.custom(
      builder: (option, isSelected, onTap) {
        return ListTile(
          title: Text(option.label,
            style: TextStyle(
              fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
            ),
          ),
          trailing: isSelected ? Icon(Icons.check_circle) : null,
          onTap: onTap,
        );
      },
    ),
  ),
)
```

दोनों प्रीसेट स्टाइल `textStyle`, `selectedTextStyle`, `contentPadding`, `tileColor` और `selectedTileColor` को भी सपोर्ट करते हैं:

``` dart
FieldStylePicker(
  listTileStyle: PickerListTileStyle.radio(
    activeColor: Colors.blue,
    textStyle: TextStyle(fontSize: 16),
    selectedTextStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
    selectedTileColor: Colors.blue.shade50,
  ),
)
```

<div id="radio-fields"></div>

### रेडियो फ़ील्ड्स

``` dart
Field.radio("Newsletter",
  options: FormCollection.fromMap({
    "Yes": "Yes, I want to receive newsletters",
    "No": "No, I do not want to receive newsletters",
  }),
)
```

`options` पैरामीटर के लिए `FormCollection` आवश्यक है। स्टाइल प्रकार: `FieldStyleRadio`

<div id="chip-fields"></div>

### चिप फ़ील्ड्स

``` dart
Field.chips("Tags",
  options: FormCollection.from(["Featured", "Sale", "New"]),
)

// की-वैल्यू जोड़ों के साथ
Field.chips("Engine Size",
  options: FormCollection.fromMap({
    "125": "125cc",
    "250": "250cc",
    "500": "500cc",
  }),
)
```

चिप विजेट्स के माध्यम से मल्टी-सिलेक्शन की अनुमति देता है। `options` पैरामीटर के लिए `FormCollection` आवश्यक है। स्टाइल प्रकार: `FieldStyleChip`

<div id="slider-fields"></div>

### स्लाइडर फ़ील्ड्स

``` dart
Field.slider("Rating",
  label: "Rate us",
  validator: FormValidator.minValue(4, message: "Rating must be at least 4"),
  style: FieldStyleSlider(
    min: 0,
    max: 10,
    divisions: 10,
    activeColor: Colors.blue,
    inactiveColor: Colors.grey,
  ),
)
```

स्टाइल प्रकार: `FieldStyleSlider` -- `min`, `max`, `divisions`, रंग, वैल्यू डिस्प्ले, और अधिक कॉन्फ़िगर करें।

<div id="range-slider-fields"></div>

### रेंज स्लाइडर फ़ील्ड्स

``` dart
Field.rangeSlider("Price Range",
  style: FieldStyleRangeSlider(
    min: 0,
    max: 1000,
    divisions: 20,
    activeColor: Colors.blue,
    inactiveColor: Colors.grey,
  ),
)
```

`RangeValues` ऑब्जेक्ट रिटर्न करता है। स्टाइल प्रकार: `FieldStyleRangeSlider`

<div id="custom-fields"></div>

### कस्टम फ़ील्ड्स

अपना स्वयं का स्टेटफुल विजेट प्रदान करने के लिए `Field.custom()` का उपयोग करें:

``` dart
Field.custom("My Field",
  child: MyCustomFieldWidget(),
)
```

`child` पैरामीटर के लिए `NyFieldStatefulWidget` को एक्सटेंड करने वाला विजेट आवश्यक है। यह आपको फ़ील्ड की रेंडरिंग और व्यवहार पर पूर्ण नियंत्रण देता है।

<div id="builder-fields"></div>

### बिल्डर फ़ील्ड्स

`NyFieldStatefulWidget` को सबक्लास किए बिना कस्टम इनलाइन फ़ॉर्म फ़ील्ड बनाने के लिए `Field.builder()` का उपयोग करें। builder फ़ंक्शन को वर्तमान वैल्यू, फ़ॉर्म को वैल्यू परिवर्तन रिपोर्ट करने के लिए एक `onChanged` कॉलबैक, और UI रीबिल्ड ट्रिगर करने के लिए एक `setState` कॉलबैक मिलता है।

``` dart
Field.builder(
  "Favorite Color",
  builder: (context, onChanged, value, setState) {
    return ColorPicker(
      selected: value,
      onColorChanged: (color) {
        onChanged(color);
        setState(); // field widget को रीबिल्ड करें
      },
    );
  },
  value: Colors.blue,
)
```

तीसरा पैरामीटर वर्तमान फ़ील्ड वैल्यू है और चौथा `setState` है। यदि आपके builder को `setState` की आवश्यकता नहीं है, तो आप लीगेसी 3-आर्गुमेंट सिग्नेचर (`NyFieldBuilderLegacy`) का उपयोग कर सकते हैं, जो अभी भी समर्थित है:

``` dart
Field.builder(
  "Rating",
  builder: (context, onChanged, value) {
    return StarRatingWidget(
      rating: value ?? 0,
      onRatingChanged: onChanged,
    );
  },
)
```

<div id="widget-fields"></div>

### विजेट फ़ील्ड्स

फ़ॉर्म के अंदर कोई भी विजेट एम्बेड करने के लिए `Field.widget()` का उपयोग करें बिना इसे फ़ॉर्म फ़ील्ड बनाए:

``` dart
Field.widget(child: Divider())

Field.widget(child: Text("Section Header", style: TextStyle(fontSize: 18)))
```

विजेट फ़ील्ड्स वैलिडेशन या डेटा कलेक्शन में भाग नहीं लेते। वे पूरी तरह से लेआउट के लिए हैं।


<div id="form-collection"></div>

## FormCollection

पिकर, रेडियो, और चिप फ़ील्ड्स को अपने ऑप्शन्स के लिए `FormCollection` की आवश्यकता होती है। `FormCollection` विभिन्न ऑप्शन फ़ॉर्मेट्स को हैंडल करने के लिए एक एकीकृत इंटरफ़ेस प्रदान करता है।

### FormCollection बनाना

``` dart
// स्ट्रिंग्स की लिस्ट से (वैल्यू और लेबल एक ही हैं)
FormCollection.from(["Red", "Green", "Blue"])

// ऊपर जैसा ही, स्पष्ट रूप से
FormCollection.fromArray(["Red", "Green", "Blue"])

// मैप से (key = value, value = label)
FormCollection.fromMap({
  "us": "United States",
  "ca": "Canada",
})

// स्ट्रक्चर्ड डेटा से (API रिस्पॉन्स के लिए उपयोगी)
FormCollection.fromKeyValue([
  {"value": "en", "label": "English"},
  {"value": "es", "label": "Spanish"},
])
```

`FormCollection.from()` डेटा फ़ॉर्मेट को स्वचालित रूप से पहचानता है और उचित कंस्ट्रक्टर को डेलीगेट करता है।

### FormOption

`FormCollection` में प्रत्येक ऑप्शन एक `FormOption` है जिसमें `value` और `label` प्रॉपर्टीज़ होती हैं:

``` dart
FormOption option = FormOption(value: "us", label: "United States");
print(option.value); // "us"
print(option.label); // "United States"
```

### ऑप्शन्स क्वेरी करना

``` dart
FormCollection options = FormCollection.fromMap({"us": "United States", "ca": "Canada"});

options.getByValue("us");          // FormOption(value: us, label: United States)
options.getLabelByValue("us");     // "United States"
options.containsValue("ca");      // true
options.searchByLabel("can");      // [FormOption(value: ca, label: Canada)]
options.values;                    // ["us", "ca"]
options.labels;                    // ["United States", "Canada"]
```


<div id="form-validation"></div>

## फ़ॉर्म वैलिडेशन

`FormValidator` के साथ `validator` पैरामीटर का उपयोग करके किसी भी फ़ील्ड में वैलिडेशन जोड़ें:

``` dart
// नेम्ड कंस्ट्रक्टर
Field.email("Email", validator: FormValidator.email())

// चेन किए गए नियम
Field.text("Username",
  validator: FormValidator()
    .notEmpty()
    .minLength(3)
    .maxLength(20)
)

// स्ट्रेंथ लेवल के साथ पासवर्ड
Field.password("Password",
  validator: FormValidator.password(strength: 2)
)

// बूलियन वैलिडेशन
Field.checkbox("Terms",
  validator: FormValidator.booleanTrue(message: "You must accept the terms")
)

// कस्टम इनलाइन वैलिडेशन
Field.number("Age",
  validator: FormValidator.custom(
    message: "Age must be between 18 and 100",
    validate: (data) {
      int? age = int.tryParse(data.toString());
      return age != null && age >= 18 && age <= 100;
    },
  )
)

// Nullable — जब फ़ील्ड खाली हो तो वैलिडेशन पास हो जाता है
Field.text("Nickname",
  validator: FormValidator().minLength(3).nullable(),
)
```

`nullable()` एक वैलिडेटर को वैकल्पिक के रूप में चिह्नित करता है। जब फ़ील्ड वैल्यू null या खाली होती है, तो सभी वैलिडेशन नियम स्किप हो जाते हैं और फ़ील्ड पास हो जाती है। जब फ़ील्ड में वैल्यू होती है, तो सभी नियम सामान्य रूप से लागू होते हैं। किसी भी `FormValidator` के अंत में इसे चेन करें।

जब फ़ॉर्म सबमिट किया जाता है, तो सभी वैलिडेटर्स जाँचे जाते हैं। यदि कोई विफल होता है, तो पहले एरर संदेश के साथ टोस्ट एरर दिखाया जाता है और `onFailure` कॉलबैक कॉल किया जाता है।

**यह भी देखें:** उपलब्ध वैलिडेटर्स की पूरी सूची के लिए [वैलिडेशन](/docs/7.x/validation#validation-rules) पेज देखें।


<div id="managing-form-data"></div>

## फ़ॉर्म डेटा प्रबंधन

<div id="initial-data"></div>

### इनिशियल डेटा

फ़ॉर्म पर इनिशियल डेटा सेट करने के दो तरीके हैं।

**ऑप्शन 1: अपनी फ़ॉर्म क्लास में `init` गेटर को ओवरराइड करें**

``` dart
class EditAccountForm extends NyFormWidget {
  EditAccountForm({super.key, super.submitButton, super.onSubmit, super.onFailure});

  @override
  Function()? get init => () async {
    final user = await api<ApiService>((request) => request.getUserData());

    return {
      "First Name": user?.firstName,
      "Last Name": user?.lastName,
    };
  };

  @override
  fields() => [
    Field.text("First Name"),
    Field.text("Last Name"),
  ];

  static NyFormActions get actions => const NyFormActions('EditAccountForm');
}
```

`init` गेटर सिंक्रोनस `Map` या एसिंक `Future<Map>` रिटर्न कर सकता है। कीज़ को snake_case नॉर्मलाइज़ेशन का उपयोग करके फ़ील्ड नामों से मैच किया जाता है, इसलिए `"First Name"` कुंजी `"First Name"` वाले फ़ील्ड से मैप होती है।

#### init में `define()` का उपयोग

`define()` हेल्पर का उपयोग तब करें जब आपको `init` में किसी फ़ील्ड के लिए **ऑप्शंस** (या वैल्यू और ऑप्शंस दोनों) सेट करने की आवश्यकता हो। यह पिकर, चिप और रेडियो फ़ील्ड्स के लिए उपयोगी है जहां ऑप्शंस API या अन्य एसिंक्रोनस स्रोत से आते हैं।

``` dart
class CreatePostForm extends NyFormWidget {
  CreatePostForm({super.key, super.submitButton, super.onSubmit, super.onFailure});

  @override
  Function()? get init => () async {
    final categories = await api<ApiService>((request) => request.getCategories());

    return {
      "Title": "My Post",
      "Category": define(options: categories),
    };
  };

  @override
  fields() => [
    Field.text("Title"),
    Field.picker("Category", options: FormCollection.from([])),
  ];

  static NyFormActions get actions => const NyFormActions('CreatePostForm');
}
```

`define()` दो नामित पैरामीटर स्वीकार करता है:

| पैरामीटर | विवरण |
|-----------|-------------|
| `value` | फ़ील्ड का प्रारंभिक मान |
| `options` | पिकर, चिप या रेडियो फ़ील्ड्स के लिए ऑप्शंस |

``` dart
// केवल ऑप्शन सेट करें (कोई इनिशियल वैल्यू नहीं)
"Category": define(options: categories),

// केवल इनिशियल वैल्यू सेट करें
"Price": define(value: "100"),

// वैल्यू और ऑप्शन दोनों सेट करें
"Country": define(value: "us", options: countries),

// सरल फ़ील्ड्स के लिए सादे मान भी काम करते हैं
"Name": "John",
```

`define()` को पास किए गए ऑप्शंस `List`, `Map` या `FormCollection` हो सकते हैं। अप्लाई करते समय ये स्वचालित रूप से `FormCollection` में परिवर्तित हो जाते हैं।

**ऑप्शन 2: फ़ॉर्म विजेट में `initialData` पास करें**

``` dart
EditAccountForm(
  initialData: {
    "first_name": "John",
    "last_name": "Doe",
  },
)
```

<div id="setting-field-values"></div>

### फ़ील्ड वैल्यू सेट करना

कहीं से भी फ़ील्ड वैल्यू सेट करने के लिए `NyFormActions` का उपयोग करें:

``` dart
// एकल फ़ील्ड वैल्यू सेट करें
EditAccountForm.actions.updateField("First Name", "Jane");
```

<div id="setting-field-options"></div>

### फ़ील्ड ऑप्शन्स सेट करना

पिकर, चिप, या रेडियो फ़ील्ड्स पर ऑप्शन्स को डायनामिक रूप से अपडेट करें:

``` dart
EditAccountForm.actions.setOptions("Category", FormCollection.from(["New Option 1", "New Option 2"]));
```

<div id="reading-form-data"></div>

### फ़ॉर्म डेटा पढ़ना

फ़ॉर्म डेटा `onSubmit` कॉलबैक के माध्यम से फ़ॉर्म सबमिट होने पर एक्सेस किया जाता है, या रियल-टाइम अपडेट के लिए `onChanged` कॉलबैक के माध्यम से:

``` dart
EditAccountForm(
  onSubmit: (data) {
    // data एक Map<String, dynamic> है
    // {first_name: "Jane", last_name: "Doe", email: "jane@example.com"}
    print(data);
  },
  onChanged: (Field field, dynamic value) {
    print("${field.key} changed to: $value");
  },
)
```

<div id="clearing-data"></div>

### डेटा क्लियर करना

``` dart
// सभी फ़ील्ड्स क्लियर करें
EditAccountForm.actions.clear();

// एक विशिष्ट फ़ील्ड क्लियर करें
EditAccountForm.actions.clearField("First Name");
```


<div id="finding-and-updating-fields"></div>

### फ़ील्ड्स अपडेट करना

``` dart
// फ़ील्ड वैल्यू अपडेट करें
EditAccountForm.actions.updateField("First Name", "Jane");

// फ़ॉर्म UI रिफ्रेश करें
EditAccountForm.actions.refresh();

// फ़ॉर्म फ़ील्ड्स रिफ्रेश करें (fields() को फिर से कॉल करता है)
EditAccountForm.actions.refreshForm();
```


<div id="submit-button"></div>

## सबमिट बटन

फ़ॉर्म बनाते समय एक `submitButton` और `onSubmit` कॉलबैक पास करें:

``` dart
UserInfoForm(
  submitButton: Button.primary(text: "Submit"),
  onSubmit: (data) {
    print(data);
  },
  onFailure: (errors) {
    print(errors.first.rule.getMessage());
  },
)
```

`submitButton` स्वचालित रूप से फ़ॉर्म फ़ील्ड्स के नीचे प्रदर्शित होता है। आप किसी भी बिल्ट-इन बटन स्टाइल या कस्टम विजेट का उपयोग कर सकते हैं।

आप किसी भी विजेट को सबमिट बटन के रूप में भी उपयोग कर सकते हैं, इसे `footer` के रूप में पास करके:

``` dart
UserInfoForm(
  onSubmit: (data) {
    print(data);
  },
  footer: ElevatedButton(
    onPressed: () {
      UserInfoForm.actions.submit(
        onSuccess: (data) {
          print(data);
        },
      );
    },
    child: Text("Submit"),
  ),
)
```


<div id="form-layout"></div>

## फ़ॉर्म लेआउट

फ़ील्ड्स को एक `List` में रैप करके साइड-बाय-साइड रखें:

``` dart
@override
fields() => [
  // एकल फ़ील्ड (पूरी चौड़ाई)
  Field.text("Title"),

  // एक पंक्ति में दो फ़ील्ड्स
  [
    Field.text("First Name"),
    Field.text("Last Name"),
  ],

  // एक और एकल फ़ील्ड
  Field.textArea("Bio"),

  // एक पंक्ति में slider और range slider
  [
    Field.slider("Rating", style: FieldStyleSlider(min: 0, max: 10)),
    Field.rangeSlider("Budget", style: FieldStyleRangeSlider(min: 0, max: 1000)),
  ],

  // नॉन-फ़ील्ड विजेट एम्बेड करें
  Field.widget(child: Divider()),

  Field.email("Email"),
];
```

`List` में फ़ील्ड्स को समान `Expanded` चौड़ाई के साथ `Row` में रेंडर किया जाता है। फ़ील्ड्स के बीच की स्पेसिंग `NyFormWidget` पर `crossAxisSpacing` पैरामीटर द्वारा नियंत्रित होती है।


<div id="field-visibility"></div>

## फ़ील्ड विज़िबिलिटी

`Field` पर `hide()` और `show()` मेथड्स का उपयोग करके प्रोग्रामेटिक रूप से फ़ील्ड्स दिखाएँ या छुपाएँ। आप अपनी फ़ॉर्म क्लास के अंदर या `onChanged` कॉलबैक के माध्यम से फ़ील्ड्स तक पहुँच सकते हैं:

``` dart
// अपने NyFormWidget सबक्लास या onChanged कॉलबैक के अंदर
Field nameField = ...;

// फ़ील्ड छुपाएँ
nameField.hide();

// फ़ील्ड दिखाएँ
nameField.show();
```

छुपे हुए फ़ील्ड्स UI में रेंडर नहीं होते लेकिन फ़ॉर्म की फ़ील्ड सूची में अभी भी मौजूद रहते हैं।


<div id="field-styling"></div>

## फ़ील्ड स्टाइलिंग

प्रत्येक फ़ील्ड प्रकार के लिए स्टाइलिंग हेतु एक संबंधित `FieldStyle` सबक्लास है:

| फ़ील्ड प्रकार | स्टाइल क्लास |
|------------|-------------|
| Text, Email, Password, Number, URL, TextArea, PhoneNumber, Currency, Mask, CapitalizeWords, CapitalizeSentences | `FieldStyleTextField` |
| Date, DateTime | `FieldStyleDateTimePicker` |
| Picker | `FieldStylePicker` |
| Checkbox | `FieldStyleCheckbox` |
| Switch Box | `FieldStyleSwitchBox` |
| Radio | `FieldStyleRadio` |
| Chip | `FieldStyleChip` |
| Slider | `FieldStyleSlider` |
| Range Slider | `FieldStyleRangeSlider` |

किसी भी फ़ील्ड के `style` पैरामीटर में स्टाइल ऑब्जेक्ट पास करें:

``` dart
Field.text("Name",
  style: FieldStyleTextField(
    filled: true,
    fillColor: Colors.grey.shade100,
    border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
    contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
    prefixIcon: Icon(Icons.person),
  ),
)

Field.slider("Rating",
  style: FieldStyleSlider(
    min: 0,
    max: 10,
    divisions: 10,
    activeColor: Colors.blue,
    showValue: true,
  ),
)

Field.chips("Tags",
  options: FormCollection.from(["Sale", "New", "Featured"]),
  style: FieldStyleChip(
    selectedColor: Colors.blue,
    checkmarkColor: Colors.white,
    spacing: 8.0,
    runSpacing: 8.0,
  ),
)
```


<div id="ny-form-widget-static-methods"></div>

## NyFormWidget स्टैटिक मेथड्स

`NyFormWidget` आपके ऐप में कहीं से भी नाम से फ़ॉर्म्स के साथ इंटरैक्ट करने के लिए स्टैटिक मेथड्स प्रदान करता है:

| मेथड | विवरण |
|--------|-------------|
| `NyFormWidget.submit(name, onSuccess:, onFailure:, showToastError:)` | नाम से फ़ॉर्म सबमिट करें |
| `NyFormWidget.stateRefresh(name)` | फ़ॉर्म की UI स्टेट रिफ्रेश करें |
| `NyFormWidget.stateSetValue(name, key, value)` | फ़ॉर्म नाम से फ़ील्ड वैल्यू सेट करें |
| `NyFormWidget.stateSetOptions(name, key, options)` | फ़ॉर्म नाम से फ़ील्ड ऑप्शन्स सेट करें |
| `NyFormWidget.stateClearData(name)` | फ़ॉर्म नाम से सभी फ़ील्ड्स क्लियर करें |
| `NyFormWidget.stateRefreshForm(name)` | फ़ॉर्म फ़ील्ड्स रिफ्रेश करें (`fields()` को पुनः कॉल करता है) |

``` dart
// कहीं से भी "LoginForm" नामक फ़ॉर्म सबमिट करें
NyFormWidget.submit("LoginForm", onSuccess: (data) {
  print(data);
});

// फ़ील्ड वैल्यू रिमोटली अपडेट करें
NyFormWidget.stateSetValue("LoginForm", "Email", "new@email.com");

// सभी फ़ॉर्म डेटा क्लियर करें
NyFormWidget.stateClearData("LoginForm");
```

> **सुझाव:** इन स्टैटिक मेथड्स को सीधे कॉल करने के बजाय `NyFormActions` (नीचे देखें) का उपयोग करें -- यह अधिक संक्षिप्त और कम त्रुटि-प्रवण है।


<div id="ny-form-widget-constructor-reference"></div>

## NyFormWidget कंस्ट्रक्टर रेफरेंस

`NyFormWidget` को एक्सटेंड करते समय, ये कंस्ट्रक्टर पैरामीटर्स हैं जो आप पास कर सकते हैं:

``` dart
LoginForm(
  Key? key,
  double crossAxisSpacing = 10,  // पंक्ति फ़ील्ड्स के बीच क्षैतिज स्पेसिंग
  double mainAxisSpacing = 10,   // फ़ील्ड्स के बीच ऊर्ध्वाधर स्पेसिंग
  Map<String, dynamic>? initialData, // इनिशियल फ़ील्ड वैल्यूज़
  Function(Field field, dynamic value)? onChanged, // फ़ील्ड बदलने पर कॉलबैक
  Widget? header,                // फ़ॉर्म के ऊपर विजेट
  Widget? submitButton,          // सबमिट बटन विजेट
  Widget? footer,                // फ़ॉर्म के नीचे विजेट
  double headerSpacing = 10,     // हेडर के बाद स्पेसिंग
  double submitButtonSpacing = 10, // सबमिट बटन के बाद स्पेसिंग
  double footerSpacing = 10,     // फ़ुटर से पहले स्पेसिंग
  LoadingStyle? loadingStyle,    // लोडिंग इंडिकेटर स्टाइल
  bool locked = false,           // फ़ॉर्म को रीड-ओनली बनाता है
  Function(dynamic data)? onSubmit,   // सफल वैलिडेशन पर फ़ॉर्म डेटा के साथ कॉल किया जाता है
  Function(dynamic error)? onFailure, // विफल वैलिडेशन पर एरर के साथ कॉल किया जाता है
)
```

`onChanged` कॉलबैक बदले गए `Field` और उसकी नई वैल्यू प्राप्त करता है:

``` dart
LoginForm(
  onChanged: (Field field, dynamic value) {
    print("${field.key} changed to: $value");
  },
)
```


<div id="ny-form-actions"></div>

## NyFormActions

`NyFormActions` आपके ऐप में कहीं से भी फ़ॉर्म के साथ इंटरैक्ट करने का एक सुविधाजनक तरीका प्रदान करता है। इसे अपनी फ़ॉर्म क्लास में स्टैटिक गेटर के रूप में डिफ़ाइन करें:

``` dart
class LoginForm extends NyFormWidget {
  LoginForm({super.key, super.submitButton, super.onSubmit, super.onFailure});

  @override
  fields() => [
    Field.email("Email", validator: FormValidator.email()),
    Field.password("Password", validator: FormValidator.password()),
  ];

  static NyFormActions get actions => const NyFormActions('LoginForm');
}
```

### उपलब्ध एक्शन्स

| मेथड | विवरण |
|--------|-------------|
| `actions.updateField(key, value)` | फ़ील्ड की वैल्यू सेट करें |
| `actions.clearField(key)` | विशिष्ट फ़ील्ड क्लियर करें |
| `actions.clear()` | सभी फ़ील्ड्स क्लियर करें |
| `actions.refresh()` | फ़ॉर्म की UI स्टेट रिफ्रेश करें |
| `actions.refreshForm()` | `fields()` को पुनः कॉल करें और पुनर्निर्माण करें |
| `actions.setOptions(key, options)` | पिकर/चिप/रेडियो फ़ील्ड्स पर ऑप्शन्स सेट करें |
| `actions.submit(onSuccess:, onFailure:, showToastError:)` | वैलिडेशन के साथ सबमिट करें |

``` dart
// फ़ील्ड वैल्यू अपडेट करें
LoginForm.actions.updateField("Email", "new@email.com");

// सभी फ़ॉर्म डेटा क्लियर करें
LoginForm.actions.clear();

// फ़ॉर्म सबमिट करें
LoginForm.actions.submit(
  onSuccess: (data) {
    print(data);
  },
);
```

### NyFormWidget ओवरराइड्स

आपकी `NyFormWidget` सबक्लास में ओवरराइड किए जा सकने वाले मेथड्स:

| ओवरराइड | विवरण |
|----------|-------------|
| `fields()` | फ़ॉर्म फ़ील्ड्स डिफ़ाइन करें (आवश्यक) |
| `init` | इनिशियल डेटा प्रदान करें (सिंक या एसिंक) |
| `onChange(field, data)` | आंतरिक रूप से फ़ील्ड परिवर्तनों को हैंडल करें |


<div id="all-field-types-reference"></div>

## सभी फ़ील्ड प्रकार रेफरेंस

| कंस्ट्रक्टर | मुख्य पैरामीटर्स | विवरण |
|-------------|----------------|-------------|
| `Field.text()` | -- | स्टैंडर्ड टेक्स्ट इनपुट |
| `Field.email()` | -- | कीबोर्ड प्रकार के साथ ईमेल इनपुट |
| `Field.password()` | `viewable` | वैकल्पिक विज़िबिलिटी टॉगल के साथ पासवर्ड |
| `Field.number()` | `decimal` | न्यूमेरिक इनपुट, वैकल्पिक दशमलव |
| `Field.currency()` | `currency` (आवश्यक) | करेंसी-फ़ॉर्मेटेड इनपुट |
| `Field.capitalizeWords()` | -- | टाइटल केस टेक्स्ट इनपुट |
| `Field.capitalizeSentences()` | -- | सेंटेंस केस टेक्स्ट इनपुट |
| `Field.textArea()` | -- | मल्टी-लाइन टेक्स्ट इनपुट |
| `Field.phoneNumber()` | -- | ऑटो-फ़ॉर्मेटेड फ़ोन नंबर |
| `Field.url()` | -- | कीबोर्ड प्रकार के साथ URL इनपुट |
| `Field.mask()` | `mask` (आवश्यक), `match`, `maskReturnValue` | मास्क्ड टेक्स्ट इनपुट |
| `Field.date()` | -- | डेट पिकर |
| `Field.datetime()` | `firstDate`, `lastDate`, `dateFormat`, `initialPickerDateTime` | डेट और टाइम पिकर |
| `Field.checkbox()` | -- | बूलियन चेकबॉक्स |
| `Field.switchBox()` | -- | बूलियन टॉगल स्विच |
| `Field.picker()` | `options` (आवश्यक `FormCollection`) | सूची से सिंगल सिलेक्शन |
| `Field.radio()` | `options` (आवश्यक `FormCollection`) | रेडियो बटन ग्रुप |
| `Field.chips()` | `options` (आवश्यक `FormCollection`) | मल्टी-सिलेक्ट चिप्स |
| `Field.slider()` | -- | सिंगल वैल्यू स्लाइडर |
| `Field.rangeSlider()` | -- | रेंज वैल्यू स्लाइडर |
| `Field.custom()` | `child` (आवश्यक `NyFieldStatefulWidget`) | कस्टम स्टेटफुल विजेट |
| `Field.builder()` | `builder` (आवश्यक `NyFieldBuilder` या `NyFieldBuilderLegacy`) | सबक्लास किए बिना इनलाइन कस्टम फ़ील्ड |
| `Field.widget()` | `child` (आवश्यक `Widget`) | कोई भी विजेट एम्बेड करें (नॉन-फ़ील्ड) |

