0

Do you have any idea how to disable click event in native web compontent? I've tried to remove event listener in connectedCallback() section but it doesn't work.

How it looks my code:

if(state ==='disabled') {
  this.shadowRoot.querySelector("div.primary_button").style.backgroundColor = "#D9D9D9";
  this.shadowRoot.querySelector("div.primary_button").style.color = "#333333";
  this.shadowRoot.querySelector("div.primary_button").style.cursor = "not-allowed";

  this.removeEventListener('click',  e => {
    this.dispatchCustomEvent();
  });
}
Intervalia
  • 10,248
  • 2
  • 30
  • 60
Piotr Treska
  • 63
  • 1
  • 5

2 Answers2

1

class ingButton extends HTMLElement {

    constructor() {
      super();
    }
  
    connectedCallback() {
        this.initShadowDom();

 
        //   this.style.backgroundColor="red";

        var state = this.getAttribute('disabled');

        if(state ==='disabled')
        {

         this.shadowRoot.querySelector("div.primary_button").style.backgroundColor = "#D9D9D9";
         this.shadowRoot.querySelector("div.primary_button").style.color = "#333333";
         this.shadowRoot.querySelector("div.primary_button").style.cursor = "not-allowed";


         this.removeEventListener('click',  e => {
             this.dispatchCustomEvent();
          });

        }

        // this.shadowRoot.querySelector('div').addEventListener('click',  e => {
        //     this.dispatchCustomEvent();
        //   });
    }
    get divs() {
        return this.shadowRoot.querySelector('div');
    }

    dispatchCustomEvent(){
        var event = new CustomEvent('build', {
            bubbles: true,
            cancelable: false,
          });  
        this.dispatchEvent(event)
        // this.style.display = "inline-block"
        // this.shadowRoot.dispatchEvent(event)
    }

    get Template() {
      return `
       <style>
        .primary_button
        {
            border-width: 0px;
            border-radius:4px;
            width: 140px;
            height: 40px;
            background-color: #FF6200;
            text-align: center;
            line-height: normal;
            display: block;
            cursor: pointer;
            disabled: disabled;
        }

        .text_button
        {
            border-width: 0px;
            border-radius:4px;
            border: none;
            width: 140px;
            height: 40px;
            background: inherit;
            -moz-box-shadow: none;
            -webkit-box-shadow: none;
            box-shadow: none;
            disabled: disabled;
        }

        .text
        {
            border-width: 0px;
            position: absolute;
            width: 136px;
            color: #FFFFFF;
            word-wrap: break-word;
            font-family: 'ING Me';
            font-weight: 410;
            font-style: normal;
            font-size: 13px;
            disabled: disabled;
        }
       </style>

        <div class="primary_button">
        <div class="text_button">
        <div class="text">
        <p><span>Generate report</span></p>
        </div>
        </div>
        </div>
      `;
    }

      initShadowDom() {
        let shadowRoot = this.attachShadow({mode: 'open'});
    
        shadowRoot.innerHTML = this.Template;

        
      }

      attributeChangedCallback(name, oldValue, newValue) {
        // When the drawer is disabled, update keyboard/screen reader behavior.
        if (this.disabled) {
            console.log("disabled");
          this.setAttribute('disabled', 'disabled');
        } else {
        }
        // TODO: also react to the open attribute changing.
      }
  }
  window.customElements.define('ing-button', ingButton);
     <html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <script src="ing-button.js"> </script>
</head>
<body>
    <div style="width: 200px;">
        <ing-button onclick="invokeAlert()" disabled="disabled" ></ing-button>
    </div>
</body>
</html>

<script>
    function invokeAlert()
    {
        alert("test");
    }
</script>

JavaScript:

Piotr Treska
  • 63
  • 1
  • 5
0

Ok. Here is a fix:

It is not that you want to try to remove any event listener, instead you want to get there before the user defined event listener and prevent it from happening.

To do this you need to have an event listener on the shadowRoot. That click event will happen before the element click event. Then, if your component is disabled, you must call evt.preventDefault(); and evt.stopImmediatePropagation(); to prevent the onclick from happening.

In the example below I removed things that were not needed for the example and I added a few things that I will describe below.

class ingButton extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({mode: 'open'}).innerHTML = this.Template;

    this.shadowRoot.addEventListener('click', evt => {
      if (this.hasAttribute('disabled')) {
        evt.preventDefault();
        evt.stopImmediatePropagation();
        this.dispatchCustomEvent();
      }
    },true);
  }
  
  dispatchCustomEvent(){
    var event = new CustomEvent('build', {
      bubbles: true,
      cancelable: false,
    });  
    this.dispatchEvent(event)
  }
  
  get disabled() {
    return this.hasAttribute('disabled');
  }
  set disabled(val) {
    if (val) {
      this.setAttribute('disabled', '');
    }
    else {
      this.removeAttribute('disabled');
    }
  }

  get divs() {
    return this.shadowRoot.querySelector('div');
  }

  get Template() {
    return `
     <style>
      :host([disabled]) .primary_button {
        background-color: #D9D9D9;
        color: #333;
        cursor: not-allowed;
      }

      .primary_button
      {
        border-width: 0px;
        border-radius:4px;
        width: 140px;
        height: 40px;
        background-color: #FF6200;
        text-align: center;
        line-height: normal;
        display: block;
        cursor: pointer;
      }

      .text_button
      {
        border-width: 0px;
        border-radius:4px;
        border: none;
        width: 140px;
        height: 40px;
        background: inherit;
        -moz-box-shadow: none;
        -webkit-box-shadow: none;
        box-shadow: none;
      }

      .text
      {
        border-width: 0px;
        position: absolute;
        width: 136px;
        color: #FFFFFF;
        word-wrap: break-word;
        font-family: 'ING Me';
        font-weight: 410;
        font-style: normal;
        font-size: 13px;
      }
     </style>

      <div class="primary_button">
      <div class="text_button">
      <div class="text">
      <p><span>Generate report</span></p>
      </div>
      </div>
      </div>
    `;
  }
}

customElements.define('ing-button', ingButton);

customElements.whenDefined('ing-button').then(() => {
  let ingButton = document.querySelector('ing-button');
  
  ingButton.addEventListener('build', evt => {
    alert('ing-button: build event');
  });

  document.getElementById('toggle').addEventListener('click', evt => {
    ingButton.disabled = !ingButton.disabled;
  });
});
<div style="width: 200px;">
<ing-button onclick="alert('clicked on')" disabled></ing-button>
<button id="toggle">Toggle</button>
</div>

I added the toggle button to allow me to enable and disable the custom element. I added a disabled property for easy ability to set the state. I moved the creation of shadowDOM and the internal click handler into the constructor. Notice the true at the end of the addEventListener call. That uses capture mode. (Look here for more info on capture mode vs. bubble mode for events.) There is no need to worry about the disabled attribute using attributeChangedCallback since we check the existence of the disabled attribute every time the user clicks on our component. I added CSS to auto set the color and cursor when disabled:

  :host([disabled]) .primary_button {
    background-color: #D9D9D9;
    color: #333;
    cursor: not-allowed;
  }

Any other questions, just ask.

UPDATE 1

I will add that if you are trying to act like a button that your code should probably use a <button> instead of trying to make your own. There are many things that exist in a button that are difficult/time consuming to add. And if you want your site to work well with the visually impaired then you should really use the <button> instead of making your own.

Intervalia
  • 10,248
  • 2
  • 30
  • 60