Reputation: 1155
const log = console.log;
const child = document.getElementById('child');
const parent = document.getElementById('parent');
parent.addEventListener('newColor', function(e) {
e.preventDefault()
log('parent')
this.style.color = e.detail.textColor;
})
child.addEventListener('newColor', function(e) {
log('child')
this.style.color = e.detail.textColor;
this.style.backgroundColor = e.detail.bgrColor;
})
function changeColor() {
const myEvent = new CustomEvent('newColor', {
detail: {
textColor: 'red',
bgrColor: 'blue',
},
cancelable: true,
bubbles: true
})
child.dispatchEvent(myEvent);
}
changeColor()
<p id="parent">this is the parent<span id="child"> THIS IS THE CHILD ELEMENT </span></p>
Since event.preventDefault()
only prevent the default browser action, how can a custom Event be 'canceled' then?
For example, in here:
$("#but").click(function (ev) {
ev.preventDefault()
alert('child button clicked');
})
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<button id="but">button</button>
the preventDefault()
only prevents the default action, which would be to submit a form, not the execution of the rest of the function statements.
So, what is the point of having 'cancellable' property when you can't actually cancel a event with preventDefault()
?
Upvotes: 2
Views: 1248
Reputation: 2739
Usually when you call Event.preventDefault()
on a browser-provided object, for example:
document.querySelector("#id-checkbox").addEventListener("click", function(event) {
console.log("run") // This is still run
event.preventDefault()
});
It will not trigger browser-defined default action like checking the checkbox (but your code will still run, so the event is not "cancelled"). It is in fact equivalent to: (not equivalent exactly, read here)
function(event) {
console.log("run") // This is still run
return false
});
So what Event.preventDefault()
do is canceling default browser actions afterward. However, you cannot define default action on a custom Event
. Then how is it still useful? Actually it is still useful on some special occasions. To demonstrate how it will work with custom Event
, here is an example:
const log = console.log;
const child = document.getElementById('child');
const parent = document.getElementById('parent');
const child2 = document.getElementById('child2');
const parent2 = document.getElementById('parent2');
parent.addEventListener('newColor', function(e) {
if (e.defaultPrevented) return;
log('parent')
this.style.color = e.detail.textColor;
})
child.addEventListener('newColor', function(e) {
e.preventDefault();
log('child')
this.style.color = e.detail.textColor;
this.style.backgroundColor = e.detail.bgrColor;
})
parent2.addEventListener('newColorNotCancelable', function(e) {
if (e.defaultPrevented) return; // does not return as event is not cancelable
log('parentNotCancelable')
this.style.color = e.detail.textColor;
})
child2.addEventListener('newColorNotCancelable', function(e) {
e.preventDefault();
log('childNotCancelable')
this.style.color = e.detail.textColor;
this.style.backgroundColor = e.detail.bgrColor;
})
function changeColor() {
const myEvent = new CustomEvent('newColor', {
detail: {
textColor: 'red',
bgrColor: 'blue',
},
cancelable: true,
bubbles: true
})
child.dispatchEvent(myEvent)
const myEventNotCancelable = new CustomEvent('newColorNotCancelable', {
detail: {
textColor: 'red',
bgrColor: 'blue',
},
cancelable: false,
bubbles: true
})
child2.dispatchEvent(myEventNotCancelable)
}
changeColor()
<p id="parent">this is the parent<span id="child"> THIS IS THE CHILD ELEMENT </span></p>
<p id="parent2">this is the parent<span id="child2"> THIS IS THE CHILD ELEMENT </span></p>
When you dispatch an event on child
and child2
, the event will propagate to their parents. By calling Event.preventDefault()
on their children, you can make the parents know that the event has been "default prevented", if the Event
is cancelable. It is similar to Event.stopPropagation()
but it is more powerful because you can only skip certain DOM objects on the propagation chain.
Upvotes: 2
Reputation: 119
We need cancelable
field just to signal to some event listener whether the event can be cancelled. Yep, this is it. The point is that preventDefault
has not effect if called for some event e
and e.cancelable === false
.
Here's one example. Imagine that you develop some js-library that communicates the lib's user using events (i.e. it's designed per the EventBus pattern. )
The lib has a bunch of emitter functions. They emit custom events and execute some behaviour. Inside such emitter functions you might want to check whether the event emitted by the function was cancelled by some listener and change the function's behaviour accordingly. It may result to termination of the execution, some cleanup job, calling another function etc. What matters is that as a lib developer, you just let the user know what the lib does upon emitting some custom event e
.
Now if the user wants to prevent the lib's behaviour he needs to subscribe for e
and cancel it by calling e.preventDefault
. Yes, you can call it at custom event. What it does is making the emitter's EventTarget.dispatchEvent()
method return false
if the e
is cancelable
(not limited by that behaviour but that's what important for our example).
So why do we need the cancelable
field? It comes into play in some more sophisticated scenaniors. Imagine that your lib has some behaviour which can or cannot be stopped or modified under some but not every scenario. Your lib is a black box. How would you let the user know the exact case? Yep, e.cancelable === false
. As I've mentioned, the point is that preventDefault
has no effect if called upon non cancelable event. Also there's no error risen. So by signaling e.cancelable === false
you let the lib's user know that he has to resolve that other than by calling e.preventDefault()
.
Upvotes: 0