HowTo कॉम्पोनेंट – कैसे करें-चेकबॉक्स

ईवा गैस्परोविच

खास जानकारी

<howto-checkbox>, फ़ॉर्म में बूलियन विकल्प को दिखाता है. सबसे सामान्य तरह का चेकबॉक्स दो तरह का चेकबॉक्स है. इससे उपयोगकर्ता दो विकल्पों के बीच टॉगल कर सकते हैं -- चेकबॉक्स पर सही का निशान लगा होता है और उससे सही का निशान हटा दिया जाता है.

यह एलिमेंट, role="checkbox" और tabindex="0" एट्रिब्यूट को पहली बार बनाए जाने पर उन्हें खुद लागू करने की कोशिश करता है. role एट्रिब्यूट, स्क्रीन रीडर जैसी सहायक टेक्नोलॉजी की मदद करता है. इससे, उपयोगकर्ता को यह पता चलता है कि यह किस तरह का कंट्रोल है. tabindex एट्रिब्यूट, एलिमेंट को टैब में व्यवस्थित कर देता है. इससे कीबोर्ड फ़ोकस करने लायक और इस्तेमाल करने लायक बन जाता है. इन दो विषयों के बारे में ज़्यादा जानने के लिए, ARIA से क्या किया जा सकता है? और tabindex का इस्तेमाल करना लेख देखें.

चेकबॉक्स पर सही का निशान लगाने पर, यह checked बूलियन एट्रिब्यूट जोड़ देता है. साथ ही, इससे जुड़ी checked प्रॉपर्टी को true पर सेट कर देता है. इसके अलावा, एलिमेंट अपनी स्थिति के आधार पर, aria-checked एट्रिब्यूट को "true" या "false" पर सेट करता है. माउस या स्पेस बार वाले चेकबॉक्स पर क्लिक करने से, चुने गए इन स्टेटस को टॉगल किया जाता है.

चेकबॉक्स में भी disabled स्थिति दिखती है. अगर disabled प्रॉपर्टी को 'सही है' पर सेट किया गया है या disabled एट्रिब्यूट लागू किया गया है, तो चेकबॉक्स aria-disabled="true" सेट करता है और tabindex एट्रिब्यूट को हटा देता है. साथ ही, अगर चेकबॉक्स मौजूदा activeElement है, तो दस्तावेज़ पर फ़ोकस होता है.

चेकबॉक्स को howto-label एलिमेंट के साथ जोड़ा जाता है, ताकि यह पक्का किया जा सके कि इसका ऐक्सेस किया जा सकने वाला नाम मौजूद है.

रेफ़रंस

डेमो

GitHub पर लाइव डेमो देखें

इस्तेमाल से जुड़ा उदाहरण

<style>
  howto-checkbox {
    vertical-align: middle;
  }
  howto-label {
    vertical-align: middle;
    display: inline-block;
    font-weight: bold;
    font-family: sans-serif;
    font-size: 20px;
    margin-left: 8px;
  }
</style>

<howto-checkbox id="join-checkbox"></howto-checkbox>
<howto-label for="join-checkbox">Join Newsletter</howto-label>

कोड

(function() {

कीबोर्ड इवेंट को मैनेज करने के लिए, कुंजी कोड तय करें.

  const KEYCODE = {
    SPACE: 32,
  };

<template> एलिमेंट का कॉन्टेंट क्लोन करना, innerHTML के मुकाबले ज़्यादा बेहतर परफ़ॉर्म करता है. ऐसा इसलिए, क्योंकि इससे एचटीएमएल पार्स की अतिरिक्त लागत से बचा जा सकता है.

  const template = document.createElement('template');

  template.innerHTML = `
    <style>
      :host {
        display: inline-block;
        background: url('../images/unchecked-checkbox.svg') no-repeat;
        background-size: contain;
        width: 24px;
        height: 24px;
      }
      :host([hidden]) {
        display: none;
      }
      :host([checked]) {
        background: url('../images/checked-checkbox.svg') no-repeat;
        background-size: contain;
      }
      :host([disabled]) {
        background:
          url('../images/unchecked-checkbox-disabled.svg') no-repeat;
        background-size: contain;
      }
      :host([checked][disabled]) {
        background:
          url('../images/checked-checkbox-disabled.svg') no-repeat;
        background-size: contain;
      }
    </style>
  `;


  class HowToCheckbox extends HTMLElement {
    static get observedAttributes() {
      return ['checked', 'disabled'];
    }

नया इंस्टेंस बनाए जाने पर, एलिमेंट का कंस्ट्रक्टर चलाया जा सकता है. इंस्टेंस या तो एचटीएमएल को पार्स करके, document.createElement('howto-checkbox') को कॉल करके या नए HowToCheckbox( में) को कॉल करके बनाए जाते हैं. कंस्ट्रक्टर, शैडो DOM बनाने के लिए एक अच्छा विकल्प है. हालांकि, आपको किसी भी एट्रिब्यूट या लाइट DOM बच्चों को छूने से बचना चाहिए, क्योंकि हो सकता है कि वे अभी उपलब्ध न हों.

    constructor() {
      super();
      this.attachShadow({mode: 'open'});
      this.shadowRoot.appendChild(template.content.cloneNode(true));
    }

जब एलिमेंट को डीओएम में डाला जाता है, तब connectedCallback() ट्रिगर होता है. शुरुआती role, tabindex, इंटरनल स्टेटस, और इवेंट लिसनर को इंस्टॉल करने के लिए यह एक बेहतर विकल्प है.

    connectedCallback() {
      if (!this.hasAttribute('role'))
        this.setAttribute('role', 'checkbox');
      if (!this.hasAttribute('tabindex'))
        this.setAttribute('tabindex', 0);

इस क्लास से उसका प्रोटोटाइप कनेक्ट होने से पहले, उपयोगकर्ता किसी एलिमेंट के इंस्टेंस पर प्रॉपर्टी सेट कर सकता है. _upgradeProperty() वाला तरीका, इंस्टेंस प्रॉपर्टी की जांच करेगा और उन्हें सही क्लास सेटर के ज़रिए चलाएगा. ज़्यादा जानकारी के लिए लेज़ी प्रॉपर्टी सेक्शन देखें.

      this._upgradeProperty('checked');
      this._upgradeProperty('disabled');

      this.addEventListener('keyup', this._onKeyUp);
      this.addEventListener('click', this._onClick);
    }

    _upgradeProperty(prop) {
      if (this.hasOwnProperty(prop)) {
        let value = this[prop];
        delete this[prop];
        this[prop] = value;
      }
    }

जब एलिमेंट को DOM से हटाया जाता है, तब disconnectedCallback() ट्रिगर होता है. यह रेफ़रंस रिलीज़ करने और इवेंट लिसनर को हटाने जैसे काम को साफ़ करने के लिए एक अच्छी जगह है.

    disconnectedCallback() {
      this.removeEventListener('keyup', this._onKeyUp);
      this.removeEventListener('click', this._onClick);
    }

प्रॉपर्टी और उनसे जुड़े एट्रिब्यूट एक-दूसरे की जानकारी देते हों. जांचे गए प्रॉपर्टी सेटर, सही/गलत वैल्यू को हैंडल करता है और उन वैल्यू को एट्रिब्यूट की स्थिति के बारे में बताता है. ज़्यादा जानकारी के लिए, वापस आने से बचें सेक्शन देखें.

    set checked(value) {
      const isChecked = Boolean(value);
      if (isChecked)
        this.setAttribute('checked', '');
      else
        this.removeAttribute('checked');
    }

    get checked() {
      return this.hasAttribute('checked');
    }

    set disabled(value) {
      const isDisabled = Boolean(value);
      if (isDisabled)
        this.setAttribute('disabled', '');
      else
        this.removeAttribute('disabled');
    }

    get disabled() {
      return this.hasAttribute('disabled');
    }

attributeChangedCallback() को तब कॉल किया जाता है, जब निगरानी में रखे गए एट्रिब्यूट की कैटगरी में से किसी एक एट्रिब्यूट को बदला जाता है. यह ARIA एट्रिब्यूट को सेट करने जैसे खराब असर को हैंडल करने की अच्छी जगह है.

    attributeChangedCallback(name, oldValue, newValue) {
      const hasValue = newValue !== null;
      switch (name) {
        case 'checked':
          this.setAttribute('aria-checked', hasValue);
          break;
        case 'disabled':
          this.setAttribute('aria-disabled', hasValue);

tabindex एट्रिब्यूट का इस्तेमाल करके, किसी एलिमेंट पर फ़ोकस करने की सुविधा को पूरी तरह से हटाने का विकल्प नहीं दिया जाता है. tabindex=-1 वाले एलिमेंट पर माउस से या focus() पर कॉल करके फ़ोकस किया जा सकता है. यह पक्का करने के लिए कि कोई एलिमेंट बंद हो और फ़ोकस नहीं किया जा सकता, tabindex एट्रिब्यूट हटाएं.

          if (hasValue) {
            this.removeAttribute('tabindex');

अगर फ़ोकस अभी इस एलिमेंट पर है, तो HTMLElement.blur() तरीके का इस्तेमाल करके इस एलिमेंट से फ़ोकस हटाएं

            this.blur();
          } else {
            this.setAttribute('tabindex', '0');
          }
          break;
      }
    }

    _onKeyUp(event) {

कार्रवाई बदलने वाले उन शॉर्टकट को हैंडल न करें जिनका इस्तेमाल आम तौर पर सहायक टेक्नोलॉजी में होता है.

      if (event.altKey)
        return;

      switch (event.keyCode) {
        case KEYCODE.SPACE:
          event.preventDefault();
          this._toggleChecked();
          break;

किसी भी दूसरी कुंजी को दबाए जाने पर, उसे अनदेखा कर दिया जाता है और वापस ब्राउज़र पर भेज दिया जाता है.

        default:
          return;
      }
    }

    _onClick(event) {
      this._toggleChecked();
    }

_toggleChecked() चेक किए गए सेटर को कॉल करता है और अपनी स्थिति फ़्लिप करता है. _toggleChecked() सिर्फ़ उपयोगकर्ता की कार्रवाई की वजह से होता है, इसलिए यह बदलाव इवेंट भी भेजेगा. यह इवेंट, <input type=checkbox> के स्थानीय व्यवहार की नकल करने के लिए बबल होता है.

    _toggleChecked() {
      if (this.disabled)
        return;
      this.checked = !this.checked;
      this.dispatchEvent(new CustomEvent('change', {
        detail: {
          checked: this.checked,
        },
        bubbles: true,
      }));
    }
  }

  customElements.define('howto-checkbox', HowToCheckbox);
})();