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

नए इवेंट और कस्टम एलिमेंट एपीआई की मदद से, फ़ॉर्म में हिस्सा लेना काफ़ी आसान हो गया है.

Arthur Evans

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

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

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

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

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

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

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

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

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

  1. आपको जिस फ़ॉर्म के साथ इंटरैक्ट करना है उसमें formdata इवेंट लिसनर जोड़ें.
  2. जब कोई उपयोगकर्ता सबमिट बटन पर क्लिक करता है, तो फ़ॉर्म एक formdata इवेंट ट्रिगर करता है. इसमें एक FormData ऑब्जेक्ट शामिल होता है, जिसमें सबमिट किया जा रहा सारा डेटा होता है.
  3. फ़ॉर्म सबमिट करने से पहले, हर 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);
});

Glitch पर दिए गए हमारे उदाहरण का इस्तेमाल करके, इसे आज़माएं. एपीआई को काम करते हुए देखने के लिए, इसे Chrome 77 या उसके बाद के वर्शन पर चलाएं.

ब्राउज़र के साथ काम करना

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

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

सोर्स

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

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

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

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

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

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

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

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

यहां बताया गया है कि ये आइटम, कस्टम एलिमेंट की बुनियादी डेफ़िनिशन में कैसे फ़िट होते हैं:

// Form-associated custom elements must be autonomous custom elements--
// meaning 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);

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

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

// 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 एट्रिब्यूट को जोड़ा गया हो या हटा दिया गया हो. इसके अलावा, यह भी हो सकता है कि 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 पैरामीटर तब फ़ायदेमंद होता है, जब सिर्फ़ वैल्यू के आधार पर कंट्रोल की स्थिति पहले जैसी नहीं की जा सकती. उदाहरण के लिए, मान लें कि आपने कई मोड वाला कलर पिकर बनाया है: पैलेट या आरजीबी कलर व्हील. सबमिट की जा सकने वाली value, चुने गए रंग का कैननिकल फ़ॉर्म होगा, जैसे कि "#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 currently 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;
}

काम करने का एक उदाहरण

नीचे दिया गया उदाहरण, फ़ॉर्म से जुड़े कस्टम एलिमेंट की कई सुविधाओं को एक साथ रखता है. एपीआई को काम करते हुए देखने के लिए, इसे Chrome 77 या इसके बाद के वर्शन पर चलाएं.

सुविधा की पहचान

सुविधा की पहचान करने की सुविधा का इस्तेमाल करके, यह पता लगाया जा सकता है कि 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 इवेंट और फ़ॉर्म से जुड़े कस्टम एलिमेंट, कस्टम फ़ॉर्म कंट्रोल बनाने के लिए नए टूल उपलब्ध कराते हैं.

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

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

Unsplash पर मौजूद, Oudom Pravat की हीरो इमेज.