फ़ॉर्म के और बेहतर कंट्रोल

Arthur Evans

पब्लिश होने की तारीख: 8 अगस्त, 2019

कई डेवलपर, कस्टम फ़ॉर्म कंट्रोल बनाते हैं. ऐसा इसलिए किया जाता है, ताकि वे ऐसे कंट्रोल उपलब्ध करा सकें जो ब्राउज़र में पहले से मौजूद नहीं हैं. इसके अलावा, वे फ़ॉर्म कंट्रोल के लुक और फ़ील को अपनी पसंद के मुताबिक बना सकें. ऐसा, पहले से मौजूद फ़ॉर्म कंट्रोल की मदद से नहीं किया जा सकता.

हालांकि, एचटीएमएल फ़ॉर्म में पहले से मौजूद कंट्रोल की सुविधाओं को दोहराना मुश्किल हो सकता है. किसी फ़ॉर्म में <input> एलिमेंट जोड़ने पर, ये सुविधाएं अपने-आप चालू हो जाती हैं:

  • इनपुट को फ़ॉर्म के कंट्रोल की सूची में अपने-आप जोड़ दिया जाता है.
  • इनपुट की वैल्यू, फ़ॉर्म के साथ अपने-आप सबमिट हो जाती है.
  • इनपुट, फ़ॉर्म की पुष्टि में हिस्सा लेता है. :valid और :invalid छद्म क्लास का इस्तेमाल करके, इनपुट को स्टाइल किया जा सकता है.
  • जब फॉर्म रीसेट किया जाता है, जब फॉर्म पुनः लोड किया जाता है, या जब ब्राउज़र फॉर्म प्रविष्टियों को स्वतः भरने का प्रयास करता है, तो इनपुट को सूचित किया जाता है.

आम तौर पर, कस्टम फ़ॉर्म कंट्रोल में इनमें से कुछ ही सुविधाएं होती हैं. डेवलपर, JavaScript की कुछ सीमाओं को ध्यान में रखकर काम कर सकते हैं. जैसे, फ़ॉर्म सबमिट करने की प्रोसेस में हिस्सा लेने के लिए, फ़ॉर्म में छिपा हुआ <input> जोड़ना. हालांकि, अन्य सुविधाओं को सिर्फ़ JavaScript में नहीं बनाया जा सकता.

वेब की दो सुविधाओं की मदद से, कस्टम फ़ॉर्म कंट्रोल आसानी से बनाए जा सकते हैं. साथ ही, कस्टम कंट्रोल की सीमाओं को हटाया जा सकता है:

  • formdata इवेंट की मदद से, कोई भी JavaScript ऑब्जेक्ट फ़ॉर्म सबमिट करने की प्रोसेस में हिस्सा ले सकता है. इसलिए, छिपे हुए <input> का इस्तेमाल किए बिना फ़ॉर्म डेटा जोड़ा जा सकता है.
  • फॉर्म-संबद्ध कस्टम तत्व API, कस्टम तत्वों को अंतर्निहित फॉर्म नियंत्रणों की तरह कार्य करने देता है.

इन दोनों सुविधाओं का इस्तेमाल करके, बेहतर तरीके से काम करने वाले नए कंट्रोल बनाए जा सकते हैं.

इवेंट पर आधारित एपीआई

Browser Support

  • Chrome: 5.
  • Edge: 12.
  • Firefox: 4.
  • Safari: 5.

Source

formdata इवेंट, एक लो-लेवल एपीआई है. इसकी मदद से, कोई भी JavaScript कोड फ़ॉर्म सबमिट करने में हिस्सा ले सकता है.

  • जिस फ़ॉर्म के साथ इंटरैक्ट करना है उसमें formdata इवेंट लिसनर जोड़ें.
  • जब कोई उपयोगकर्ता 'सबमिट करें' पर क्लिक करता है, तो फ़ॉर्म एक formdata इवेंट ट्रिगर करता है. इसमें एक FormData ऑब्जेक्ट शामिल होता है. इस ऑब्जेक्ट में सबमिट किया जा रहा सारा डेटा होता है.
  • फ़ॉर्म सबमिट करने से पहले, हर formdata लिसनर को डेटा में बदलाव करने या उसे जोड़ने का मौका मिलता है.

यहां formdata इवेंट लिसनर में एक वैल्यू भेजने का उदाहरण दिया गया है:

const form = document.querySelector('form');
// FormData event is sent on <form> submission, before transmission.
// The event has a formData property
form.addEventListener('formdata', ({formData}) => {
  // https://developer.mozilla.org/docs/Web/API/FormData
  formData.append('my-input', myInputValue);
});

फ़ॉर्म से जुड़े कस्टम एलिमेंट

इवेंट पर आधारित एपीआई का इस्तेमाल किसी भी तरह के कॉम्पोनेंट के साथ किया जा सकता है. हालांकि, इससे सिर्फ़ सबमिट करने की प्रोसेस के साथ इंटरैक्ट किया जा सकता है.

स्टैंडर्ड फ़ॉर्म कंट्रोल, फ़ॉर्म के लाइफ़साइकल के कई हिस्सों में शामिल होते हैं. फ़ॉर्म से जुड़े कस्टम एलिमेंट का मकसद, कस्टम विजेट और बिल्ट-इन कंट्रोल के बीच के अंतर को कम करना है. फ़ॉर्म से जुड़े कस्टम एलिमेंट में, स्टैंडर्ड फ़ॉर्म एलिमेंट की कई सुविधाएं होती हैं:

  • फ़ॉर्म से जुड़े कस्टम एलिमेंट को <form> के अंदर रखने पर, वह फ़ॉर्म से अपने-आप जुड़ जाता है. जैसे, ब्राउज़र से मिला कंट्रोल.
  • <label> एलिमेंट का इस्तेमाल करके, एलिमेंट को लेबल किया जा सकता है.
  • यह एलिमेंट ऐसी वैल्यू सेट कर सकता है जो फ़ॉर्म के साथ अपने-आप सबमिट हो जाती है.
  • तत्व एक ध्वज सेट कर सकता है जो यह इंगित करता है कि उसके पास वैध इनपुट है या नहीं. अगर फ़ॉर्म कंट्रोल में से किसी एक में अमान्य इनपुट है, तो फ़ॉर्म सबमिट नहीं किया जा सकता.
  • यह एलिमेंट, फ़ॉर्म की लाइफ़साइकल के अलग-अलग हिस्सों के लिए कॉलबैक दे सकता है. जैसे, जब फ़ॉर्म बंद हो जाता है या अपनी डिफ़ॉल्ट स्थिति पर रीसेट हो जाता है.
  • यह एलिमेंट, फ़ॉर्म कंट्रोल के लिए स्टैंडर्ड सीएसएस स्यूडोक्लास के साथ काम करता है. जैसे, :disabled और :invalid.

इस दस्तावेज़ में, हर चीज़ के बारे में नहीं बताया गया है. हालांकि, इसमें फ़ॉर्म के साथ कस्टम एलिमेंट को इंटिग्रेट करने के लिए ज़रूरी बुनियादी बातों के बारे में बताया गया है.

फ़ॉर्म से जुड़े कस्टम एलिमेंट को तय करना

कस्टम एलिमेंट को फ़ॉर्म से जुड़े कस्टम एलिमेंट में बदलने के लिए, कुछ अतिरिक्त चरणों की ज़रूरत होती है:

  • अपने कस्टम एलिमेंट क्लास में एक स्टैटिक formAssociated प्रॉपर्टी जोड़ें. इससे ब्राउज़र को यह पता चलता है कि एलिमेंट को फ़ॉर्म कंट्रोल की तरह इस्तेमाल करना है.
  • फ़ॉर्म कंट्रोल के लिए अतिरिक्त तरीकों और प्रॉपर्टी को ऐक्सेस करने के लिए, एलिमेंट पर attachInternals() तरीके को कॉल करें. जैसे, setFormValue() और setValidity().
  • फ़ॉर्म कंट्रोल के साथ काम करने वाली सामान्य प्रॉपर्टी और तरीके जोड़ें. जैसे, name, value, और validity.

यहां बताया गया है कि वे आइटम मूल कस्टम तत्व परिभाषा में कैसे फिट होते हैं:

// Form-associated custom elements must be autonomous custom elements.
// They must extend HTMLElement, not one of its subclasses.
class MyCounter extends HTMLElement {

  // Identify the element as a form-associated custom element
  static formAssociated = true;

  constructor() {
    super();
    // Get access to the internal form control APIs
    this.internals_ = this.attachInternals();
    // internal value for this control
    this.value_ = 0;
  }

  // Form controls usually expose a "value" property
  get value() { return this.value_; }
  set value(v) { this.value_ = v; }

  // The following properties and methods aren't strictly required,
  // but browser-level form controls provide them. Providing them helps
  // ensure consistency with browser-provided controls.
  get form() { return this.internals_.form; }
  get name() { return this.getAttribute('name'); }
  get type() { return this.localName; }
  get validity() {return this.internals_.validity; }
  get validationMessage() {return this.internals_.validationMessage; }
  get willValidate() {return this.internals_.willValidate; }

  checkValidity() { return this.internals_.checkValidity(); }
  reportValidity() {return this.internals_.reportValidity(); }

  
}
customElements.define('my-counter', MyCounter);

रजिस्टर करने के बाद, इस एलिमेंट का इस्तेमाल उन सभी जगहों पर किया जा सकता है जहां ब्राउज़र से मिले फ़ॉर्म कंट्रोल का इस्तेमाल किया जाता है:

<form>
  <label>Number of bunnies: <my-counter></my-counter></label>
  <button type="submit">Submit</button>
</form>

कोई वैल्यू सेट करना

attachInternals() वाला तरीका, एक ElementInternals ऑब्जेक्ट दिखाता है. यह ऑब्जेक्ट, फ़ॉर्म कंट्रोल एपीआई का ऐक्सेस देता है. इनमें से सबसे बुनियादी तरीका setFormValue() है. यह कंट्रोल की मौजूदा वैल्यू सेट करता है.

setFormValue() तरीके में, तीन तरह की वैल्यू में से कोई एक वैल्यू हो सकती है:

  • एक स्ट्रिंग मान.
  • File ऑब्जेक्ट.
  • FormData ऑब्जेक्ट. एक से ज़्यादा वैल्यू पास करने के लिए, FormData ऑब्जेक्ट का इस्तेमाल किया जा सकता है. उदाहरण के लिए, क्रेडिट कार्ड का इनपुट कंट्रोल, कार्ड नंबर, समयसीमा खत्म होने की तारीख, और पुष्टि करने का कोड पास कर सकता है.

मान सेट करने के लिए:

this.internals_.setFormValue(this.value_);

एकाधिक मान सेट करने के लिए, आप कुछ इस प्रकार कर सकते हैं:

// Use the control's name as the base name for submitted data
const n = this.getAttribute('name');
const entries = new FormData();
entries.append(n + '-first-name', this.firstName_);
entries.append(n + '-last-name', this.lastName_);
this.internals_.setFormValue(entries);

इनपुट की पुष्टि करना

आपका कंट्रोल, फ़ॉर्म की पुष्टि करने में भी हिस्सा ले सकता है. इसके लिए, इंटरनल ऑब्जेक्ट पर setValidity() तरीके को कॉल करें.

// Assume this is called whenever the internal value is updated
onUpdateValue() {
  if (!this.matches(':disabled') && this.hasAttribute('required') &&
      this.value_ < 0) {
    this.internals_.setValidity({customError: true}, 'Value cannot be negative.');
  }
  else {
    this.internals_.setValidity({});
  }
  this.internals.setFormValue(this.value_);
}

फ़ॉर्म से जुड़े कस्टम एलिमेंट को :valid और :invalid स्यूडोक्लास की मदद से स्टाइल किया जा सकता है. ठीक उसी तरह जैसे बिल्ट-इन फ़ॉर्म कंट्रोल को स्टाइल किया जाता है.

जीवनचक्र कॉलबैक

फ़ॉर्म से जुड़े कस्टम एलिमेंट के एपीआई में, लाइफ़साइकल के कुछ अतिरिक्त कॉलबैक शामिल होते हैं. इनका इस्तेमाल, फ़ॉर्म के लाइफ़साइकल से जुड़ने के लिए किया जाता है. कॉलबैक का इस्तेमाल करना ज़रूरी नहीं है: सिर्फ़ तब कॉल बैक लागू करें, जब आपके एलिमेंट को लाइफ़साइकल के उस पॉइंट पर कुछ करना हो.

void formAssociatedCallback(form)

इस फ़ंक्शन को तब कॉल किया जाता है, जब ब्राउज़र किसी एलिमेंट को फ़ॉर्म एलिमेंट से जोड़ता है या किसी एलिमेंट को फ़ॉर्म एलिमेंट से अलग करता है.

void formDisabledCallback(disabled)

इस फ़ंक्शन को तब कॉल किया जाता है, जब एलिमेंट की disabled स्थिति बदलती है. ऐसा तब होता है, जब इस एलिमेंट का disabled एट्रिब्यूट जोड़ा या हटाया जाता है. इसके अलावा, ऐसा तब भी होता है, जब इस एलिमेंट के पूर्वज <fieldset> की disabled स्थिति बदलती है.

उदाहरण के लिए, जब एलिमेंट बंद होता है, तब वह अपने शैडो DOM में मौजूद एलिमेंट को बंद कर सकता है.

void formResetCallback()

फ़ॉर्म रीसेट होने के बाद कॉल किया जाता है. तत्व को डिफ़ॉल्ट स्थिति में रीसेट होना चाहिए. <input> तत्वों के लिए, इसमें आमतौर पर मार्कअप में सेट की गई value विशेषता से मेल खाने के लिए value प्रॉपर्टी सेट करना शामिल होता है. चेकबॉक्स की मदद से, checked प्रॉपर्टी को checked एट्रिब्यूट से मैच करने के लिए सेट किया जाता है.

void formStateRestoreCallback(state, mode)

इन दो स्थितियों में से किसी एक में कॉल किया जाता है:

  • जब ब्राउज़र, एलिमेंट की स्थिति को वापस लाता है. जैसे, नेविगेशन के बाद या जब ब्राउज़र रीस्टार्ट होता है. mode आर्ग्युमेंट "restore" है.
  • जब ब्राउज़र की इनपुट-असिस्ट सुविधाएं, जैसे कि फ़ॉर्म अपने-आप भरने की सुविधा, कोई वैल्यू सेट करती है. mode आर्ग्युमेंट "autocomplete" है.

पहले आर्ग्युमेंट का टाइप इस बात पर निर्भर करता है कि setFormValue() तरीके को कैसे कॉल किया गया था.

फ़ॉर्म की स्थिति वापस लाना

कुछ मामलों में, जैसे कि किसी पेज पर वापस जाने या ब्राउज़र को रीस्टार्ट करने पर, ब्राउज़र फ़ॉर्म को उस स्थिति में वापस लाने की कोशिश कर सकता है जिसमें उपयोगकर्ता ने उसे छोड़ा था.

फ़ॉर्म से जुड़े कस्टम एलिमेंट के लिए, सेव की गई स्थिति को वापस लाने के लिए, setFormValue() तरीके में पास की गई वैल्यू का इस्तेमाल किया जाता है. इस तरीके को एक वैल्यू पैरामीटर के साथ कॉल किया जा सकता है. जैसा कि पिछले उदाहरणों में दिखाया गया है. इसके अलावा, इसे दो पैरामीटर के साथ भी कॉल किया जा सकता है:

this.internals_.setFormValue(value, state);

value, कंट्रोल की सबमिट की जा सकने वाली वैल्यू को दिखाता है. वैकल्पिक state पैरामीटर, कंट्रोल की स्थिति का इंटरनल प्रतिनिधित्व है. इसमें ऐसा डेटा शामिल हो सकता है जिसे सर्वर पर नहीं भेजा जाता. state पैरामीटर, value पैरामीटर के जैसे ही टाइप लेता है: स्ट्रिंग, File या FormData ऑब्जेक्ट.

state पैरामीटर तब काम आता है, जब सिर्फ़ वैल्यू के आधार पर कंट्रोल की स्थिति को वापस नहीं लाया जा सकता. उदाहरण के लिए, मान लें कि आपने कई मोड वाला कलर पिकर बनाया है: पैलेट या आरजीबी कलर व्हील. सबमिट की जा सकने वाली वैल्यू, कैननिकल फ़ॉर्म में चुना गया रंग होता है. जैसे, "#7fff00". किसी कंट्रोल को उसकी पिछली स्थिति में वापस लाने के लिए, आपको यह भी पता होना चाहिए कि वह किस मोड में था. इसलिए, स्टेट "palette/#7fff00" की तरह दिख सकती है.

this.internals_.setFormValue(this.value_,
    this.mode_ + '/' + this.value_);

आपके कोड को, सेव की गई स्थिति की वैल्यू के आधार पर अपनी स्थिति को वापस लाना होगा.

formStateRestoreCallback(state, mode) {
  if (mode == 'restore') {
    // expects a state parameter in the form 'controlMode/value'
    [controlMode, value] = state.split('/');
    this.mode_ = controlMode;
    this.value_ = value;
  }
  // Chrome doesn't handle autofill for form-associated custom elements.
  // In the autofill case, you might need to handle a raw value.
}

सरल नियंत्रण (उदाहरण के लिए संख्या इनपुट) के मामले में, मान संभवतः नियंत्रण को उसकी पिछली स्थिति में पुनर्स्थापित करने के लिए पर्याप्त है. यदि आप setFormValue() को कॉल करते समय state को छोड़ देते हैं, तो मान formStateRestoreCallback() को पास कर दिया जाता है.

formStateRestoreCallback(state, mode) {
  // Simple case, restore the saved value
  this.value_ = state;
}

सुविधा का पता लगाना

सुविधा की पहचान करने की सुविधा का इस्तेमाल करके, यह पता लगाया जा सकता है कि formdata इवेंट और फ़ॉर्म से जुड़े कस्टम एलिमेंट उपलब्ध हैं या नहीं. किसी भी सुविधा के लिए कोई पॉलीफ़िल जारी नहीं किया गया है. दोनों ही मामलों में, आप नियंत्रण के मान को फ़ॉर्म में प्रसारित करने के लिए एक छिपे हुए फ़ॉर्म तत्व को जोड़ सकते हैं.

फॉर्म-संबंधित कस्टम तत्वों की कई उन्नत सुविधाओं को पॉलीफ़िल करना संभवतः कठिन या असंभव है.

if ('FormDataEvent' in window) {
  // formdata event is supported
}

if ('ElementInternals' in window &&
    'setFormValue' in window.ElementInternals.prototype) {
  // Form-associated custom elements are supported
}

formdata इवेंट आपको एक इंटरफ़ेस देता है जिससे आप अपने फ़ॉर्म डेटा को सबमिट प्रक्रिया में जोड़ सकते हैं, बिना कोई छिपा हुआ <input> एलिमेंट बनाए. फ़ॉर्म-संबद्ध कस्टम तत्व API के साथ, आप कस्टम फ़ॉर्म नियंत्रणों के लिए क्षमताओं का एक नया सेट प्रदान कर सकते हैं जो अंतर्निहित फ़ॉर्म नियंत्रणों की तरह काम करते हैं.