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.