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

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

Arthur Evans

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

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

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

आम तौर पर, कस्टम फ़ॉर्म कंट्रोल में इनमें से कुछ सुविधाएं होती हैं. 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);
});

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

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

ब्राउज़र सहायता

  • Chrome: 5. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
  • एज: 12. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
  • फ़ायरफ़ॉक्स: 4. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
  • सफ़ारी: 5. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है

सोर्स

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

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

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

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

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

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

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

  • अपने कस्टम एलिमेंट क्लास में स्टैटिक 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);

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

आपका नियंत्रण, 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 का इस्तेमाल करके, फ़ॉर्म से जुड़े कस्टम एलिमेंट को स्टाइल किया जा सकता है pseudoclasses, जैसा पहले से मौजूद होता है.

लाइफ़साइकल कॉलबैक

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

void formAssociatedCallback(form)

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

void formDisabledCallback(disabled)

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

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 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> एलिमेंट की ज़रूरत नहीं होती.

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

Unस्प्लैश पेज पर, आउडम प्रवत की हीरो इमेज.