You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
6.8 KiB
239 lines
6.8 KiB
# EVENT BUBBLING
|
|
|
|
## Lesson Objectives
|
|
|
|
1. Describe event bubbling
|
|
1. Prove that event bubbling occurs
|
|
1. Access the event parameter
|
|
1. Differentiate between an event's `target` and `currentTarget`
|
|
1. Stop event propagation
|
|
1. Have an event handler return false
|
|
|
|
## Describe event bubbling
|
|
|
|
When elements are nested within the DOM, the DOM needs a way to decide which elements ought to trigger an event.
|
|
|
|

|
|
|
|
If a click event listener is set on the outer element, the green box, will a click on the inner element, the pink box, also trigger the event?
|
|
|
|
Does the pink box somehow 'block' the event? Does the "click me" text block it?
|
|
|
|
What _belongs_ to the green box?
|
|
|
|
```javascript
|
|
$('.outside').on('click', () => {
|
|
console.log('OUTSIDE is clicked');
|
|
});
|
|
```
|
|
|
|

|
|
|
|
Nothing within the green box blocks the event. Everything belongs to the green box. No matter where inside the green box you click, you'll get the console log.
|
|
|
|
### Bubbles
|
|
|
|
When you click on the pink box, this is the lowest level of your mouse location, the `target` of the event. JS checks to see if there is an event listener on this element.
|
|
|
|
Then, the event bubbles up to the parent, the green box, and checks to see if there is a listener there.
|
|
|
|
But, it doesn't stop there!
|
|
|
|
The event bubbles up through all parents to the body, and checks that too!
|
|
|
|
The event finally stops bubbling at the `document`.
|
|
|
|
## Prove that event bubbling occurs
|
|
|
|
So, if we set a listener on the pink element, the question is, will that also trigger the listener on the green one? Will it "bubble" up?
|
|
|
|
```javascript
|
|
$('.outside').on('click', () => {
|
|
console.log('OUTSIDE is clicked');
|
|
});
|
|
|
|
$('.inside').on('click', () => {
|
|
console.log('INSIDE is clicked');
|
|
});
|
|
```
|
|
|
|
Clicking on the innermost element:
|
|
|
|

|
|
|
|
|
|
### Test bubbling: Set listener on body
|
|
|
|
```javascript
|
|
$('.outside').on('click', () => {
|
|
console.log('OUTSIDE is clicked');
|
|
});
|
|
|
|
$('.inside').on('click', () => {
|
|
console.log('INSIDE is clicked');
|
|
});
|
|
|
|
$('body').on('click', () => {
|
|
console.log('BODY is clicked');
|
|
});
|
|
```
|
|
|
|
Clicking on the innermost element:
|
|
|
|

|
|
|
|
## Access the event parameter
|
|
|
|
```javascript
|
|
$('.inside').on('click', (event) => {
|
|
console.log('INSIDE is clicked');
|
|
});
|
|
```
|
|
|
|
When the `.on` method (or any JS event listener method) runs the callback function, it supplies the callback with an argument: an object that represents the event.
|
|
|
|
When can use this param in our callback. Call it what you like: you will see `e`, `ev`, `event`, etc.
|
|
|
|
## Differentiate between an event's `target` and `currentTarget`
|
|
|
|
On the `event` object, you can see the innermost thing that was clicked with `event.target`, and the thing that has the event listener with `event.currentTarget`.
|
|
|
|
**Comment out the inside and body event listeners**
|
|
|
|
On the outside event listener:
|
|
|
|
```javascript
|
|
$('.outside').on('click', (event) => {
|
|
console.log('OUTSIDE target is: ', event.target);
|
|
console.log('OUTSIDE currentTarget is: ', event.currentTarget);
|
|
});
|
|
```
|
|
|
|
If you click the green box (the outside element):
|
|
|
|

|
|
|
|
`target` and `currentTarget` are the same.
|
|
|
|
If you click the pink element (the inner element), we expect the event to bubble to the outside and trigger the event listener:
|
|
|
|

|
|
|
|
`target` is the innermost element that was clicked: the **inside** pink one.
|
|
|
|
`currentTarget` is the element on which the event listener is set: the **outside** green one.
|
|
|
|
### Consider this
|
|
|
|
```javascript
|
|
$('.outside').on('click', (event) => {
|
|
console.log('OUTSIDE target is: ', event.target);
|
|
console.log('OUTSIDE currentTarget is: ', event.currentTarget);
|
|
});
|
|
|
|
$('.inside').on('click', (event) => {
|
|
console.log('INSIDE target is: ', event.target);
|
|
console.log('INSIDE currentTarget is: ', event.currentTarget);
|
|
});
|
|
|
|
$('body').on('click', (event) => {
|
|
console.log('BODY target is: ', event.target);
|
|
console.log('Body currentTarget is: ', event.currentTarget);
|
|
});
|
|
```
|
|
|
|
If you click on the body, which listeners will be triggered? what will be the value of `target` for each listener? and what will be the value of `currentTarget` for each listener?
|
|
|
|
If you click on the outside box, which listeners will be triggered, what will be the value of `target` for each listener? and what will be the value of `currentTarget` for each listener?
|
|
|
|
If you click on the inner box, which listeners will be triggered? what will be the value of `target` for each listener? and what will be the value of `currentTarget` for each listener?
|
|
|
|
|
|
## Stop event propagation
|
|
|
|
If you want to isolate an element and prevent bubbling, use
|
|
|
|
* `event.stopPropagation()`
|
|
|
|
```javascript
|
|
$('.inside').on('click', (event) => {
|
|
console.log('INSIDE target is: ', event.target);
|
|
console.log('INSIDE currentTarget is: ', event.currentTarget);
|
|
event.stopPropagation();
|
|
});
|
|
```
|
|
|
|
Clicking on the inside element no longer triggers the outer event listeners:
|
|
|
|

|
|
|
|
Clicking on the outer event listener still triggers bubbling as expected:
|
|
|
|

|
|
|
|
|
|
## Have an event handler return false
|
|
|
|
When using jQuery, you can use `return false` within your event handlers to stop all of the default behavior associated with events, such as bubbling.
|
|
|
|
* `event.stopPropagation()` to stop bubbling
|
|
* `event.preventDefault()` to stop forms from refreshing the page
|
|
|
|
```javascript
|
|
$('.outside').on('click', (event) => {
|
|
console.log('OUTSIDE target is: ', event.target);
|
|
console.log('OUTSIDE currentTarget is: ', event.currentTarget);
|
|
return false;
|
|
});
|
|
|
|
$('.inside').on('click', (event) => {
|
|
console.log('INSIDE target is: ', event.target);
|
|
console.log('INSIDE currentTarget is: ', event.currentTarget);
|
|
return false;
|
|
});
|
|
|
|
$('body').on('click', (event) => {
|
|
console.log('BODY target is: ', event.target);
|
|
console.log('Body currentTarget is: ', event.currentTarget);
|
|
return false;
|
|
});
|
|
```
|
|
|
|
## Element targeting with jQuery
|
|
|
|
Let's say I make a few copies of the squares:
|
|
|
|
```html
|
|
<div class="outside">
|
|
<p>Click me ... ?</p>
|
|
<div class="inside"></div>
|
|
</div>
|
|
|
|
<div class="outside">
|
|
<p>Click me ... ?</p>
|
|
<div class="inside"></div>
|
|
</div>
|
|
|
|
<div class="outside">
|
|
<p>Click me ... ?</p>
|
|
<div class="inside"></div>
|
|
</div>
|
|
```
|
|
|
|

|
|
|
|
|
|
By wrapping `event.currentTarget` in jQuery I can use jQuery methods on the target, and only affect the elements I clicked (not the others)
|
|
|
|
```javascript
|
|
$(event.currentTarget).css('background-color', 'black');
|
|
```
|
|
|
|
```javascript
|
|
$('.outside').on('click', (event) => {
|
|
$(event.currentTarget).css('background-color', 'black');
|
|
});
|
|
```
|
|
|
|

|