Skip to content

Commit 7657879

Browse files
committed
learn about different ways of listening to Events
1 parent 0a894fd commit 7657879

File tree

8 files changed

+521
-0
lines changed

8 files changed

+521
-0
lines changed

Working-with-Events/README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
| Contents |
44
| :--- |
55
| [Introduction to Events in JavaScript](#introduction-to-events-in-javascript) |
6+
| [Different Ways of Listening to Events](#different-ways-of-listening-to-events) |
67

78
## [Introduction to Events in JavaScript](https://drive.google.com/uc?export=view&id=1tfi-wZ9BYL2wISnyZ2JCcutRPApHpyCV)
89

@@ -38,3 +39,48 @@ Readings:
3839
- [Introduction to browser events](https://javascript.info/introduction-browser-events)
3940

4041
- [JavaScript Events](https://www.geeksforgeeks.org/javascript-events/)
42+
43+
## Different Ways of Listening to Events
44+
45+
In JavaScript, there are several ways to listen to browser events, depending on the context in which the events are being used. Here are some common ways to listen to browser events:
46+
47+
1. **Using the [`addEventListener`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) method** - This is the most common way of listening to events in the browser. It allows you to attach an event listener to a specific DOM element and specify the type of event you want to listen to. Here's an example:
48+
49+
```javascript
50+
const button = document.querySelector('button');
51+
52+
button.addEventListener('click', () => {
53+
console.log('Button clicked');
54+
});
55+
```
56+
57+
2. **Using the `on` property** - Some DOM elements have an on property that can be used to attach an event listener. This method is less common than addEventListener, but it can be useful in certain situations. Here's an example:
58+
59+
```javascript
60+
const input = document.querySelector('input');
61+
62+
input.onchange = () => {
63+
console.log('Input value changed');
64+
};
65+
```
66+
67+
3. **Using inline event handlers** - This method involves adding event handlers directly to HTML elements using the `onclick`, `onchange`, or other similar attributes. This method is considered outdated and not recommended, but it is still supported in modern browsers. Here's an example:
68+
69+
```html
70+
<button onclick="console.log('Button clicked')">Click me</button>
71+
```
72+
73+
4. **Using the [`event`](https://developer.mozilla.org/en-US/docs/Web/API/Event/Event) object** - When an event is triggered, the browser creates an event object that contains information about the event. You can access this object and use it to perform additional operations or modify the default behavior of the event. Here's an example:
74+
75+
```javascript
76+
const link = document.querySelector('a');
77+
78+
link.addEventListener('click', (event) => {
79+
event.preventDefault();
80+
console.log('Link clicked');
81+
});
82+
```
83+
84+
In this example, we prevent the default behavior of the `click` event (which is to navigate to the link URL) using the [`preventDefault()`](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) method on the `event` object.
85+
86+
Overall, the [`addEventListener`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) method is the preferred way of listening to browser events in modern JavaScript, as it provides more flexibility and better separation of concerns. However, the other methods may still be useful in certain situations.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// console.log("Starting some analysis...");
2+
3+
// Demonstration of setInterval()
4+
5+
const intervalId = setInterval(() => {
6+
console.log("Starting some analysis...")
7+
}, 2000);
8+
9+
document.getElementById('stop-analytics').addEventListener(
10+
'click', () => {
11+
clearInterval(intervalId);
12+
// clearTimeout() will also work
13+
}
14+
)
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
class DOMHelper {
2+
static clearEventListeners(element){
3+
const clonedElement = element.cloneNode(true);
4+
element.replaceWith(clonedElement);
5+
return clonedElement;
6+
}
7+
8+
static moveElement(elementId, newDestinationSelector) {
9+
const element = document.getElementById(elementId);
10+
const destinationElement = document.querySelector(newDestinationSelector);
11+
destinationElement.append(element);
12+
element.scrollIntoView({behavior: 'smooth'});
13+
}
14+
}
15+
16+
class Component {
17+
constructor(hostElementId, insertBefore=false) {
18+
if (hostElementId) {
19+
this.hostElement = document.getElementById(hostElementId);
20+
} else {
21+
this.hostElement = document.body;
22+
}
23+
this.insertBefore = insertBefore;
24+
}
25+
26+
detach() {
27+
if (this.element) {
28+
this.element.remove();
29+
// this.element.parentElement.removeChild(this.element);
30+
}
31+
}
32+
33+
attach() {
34+
this.hostElement.insertAdjacentElement(this.insertBefore ? 'afterbegin' : 'beforeend', this.element);
35+
}
36+
}
37+
38+
class Tooltip extends Component {
39+
constructor(closeNotifierFunction, toolTipText, hostElementId) {
40+
super(hostElementId);
41+
this.closeNotifier = closeNotifierFunction;
42+
this.toolTipText = toolTipText;
43+
this.create();
44+
}
45+
46+
closeToolTip = () => {
47+
this.detach();
48+
this.closeNotifier();
49+
};
50+
51+
create() {
52+
const toolTipElement = document.createElement('div');
53+
toolTipElement.className = 'card';
54+
// toolTipElement.textContent = this.toolTipText;
55+
const tootTipTemplate = document.getElementById('tooltip');
56+
const tootTipBody = document.importNode(tootTipTemplate.content, true);
57+
tootTipBody.querySelector('p').textContent = this.toolTipText;
58+
toolTipElement.append(tootTipBody);
59+
60+
const hostElementLeft = this.hostElement.offsetLeft;
61+
const hostElementTop = this.hostElement.offsetTop;
62+
const hostElementHeight = this.hostElement.offsetHeight;
63+
const parentElementScrolling = this.hostElement.parentElement.scrollTop;
64+
65+
const x = hostElementLeft + 20;
66+
const y = hostElementTop + hostElementHeight - parentElementScrolling - 10;
67+
68+
toolTipElement.style.position = 'absolute';
69+
toolTipElement.style.left = x + 'px';
70+
toolTipElement.style.top = y + 'px';
71+
72+
toolTipElement.addEventListener('click', this.closeToolTip);
73+
this.element = toolTipElement;
74+
}
75+
}
76+
77+
class ProjectItem {
78+
hasActiveTooltip = false;
79+
80+
constructor(id, updateProjectListFunction, type) {
81+
this.id = id;
82+
this.updateProjectListHandler = updateProjectListFunction;
83+
this.connectMoreInfoButton();
84+
this.connectSwitchButton(type);
85+
}
86+
87+
showMoreInfoHandler() {
88+
if (this.hasActiveTooltip) {
89+
return;
90+
}
91+
const projectElement = document.getElementById(this.id);
92+
const toolTipText = projectElement.dataset.extraInfo;
93+
const tooltip = new Tooltip(() => {
94+
this.hasActiveTooltip = false;
95+
}, toolTipText, this.id);
96+
tooltip.attach();
97+
this.hasActiveTooltip = true;
98+
}
99+
100+
connectMoreInfoButton(){
101+
const prjItemElement = document.getElementById(this.id);
102+
const moreInfoBtn = prjItemElement.querySelector('button:first-of-type');
103+
moreInfoBtn.addEventListener('click', this.showMoreInfoHandler.bind(this));
104+
}
105+
106+
connectSwitchButton(type) {
107+
const prjItemElement = document.getElementById(this.id);
108+
let switchBtn = prjItemElement.querySelector('button:last-of-type');
109+
switchBtn = DOMHelper.clearEventListeners(switchBtn);
110+
switchBtn.textContent = type === 'active' ? 'Finish' : 'Activate';
111+
switchBtn.addEventListener('click', this.updateProjectListHandler.bind(null, this.id));
112+
}
113+
114+
update(updateProjectListFn, type) {
115+
this.updateProjectListHandler = updateProjectListFn;
116+
this.connectSwitchButton(type);
117+
}
118+
}
119+
120+
class ProjectList {
121+
projects = [];
122+
123+
constructor(type) {
124+
this.type = type;
125+
const prjItems = document.querySelectorAll(`#${type}-projects li`);
126+
for (const prjItem of prjItems) {
127+
this.projects.push(new ProjectItem(prjItem.id, this.switchProject.bind(this), this.type));
128+
}
129+
}
130+
131+
setSwitchHandlerFunction(switchHandlerFunction) {
132+
this.switchHandler = switchHandlerFunction;
133+
}
134+
135+
addProject(project) {
136+
this.projects.push(project);
137+
DOMHelper.moveElement(project.id, `#${this.type}-projects ul`);
138+
project.update(this.switchProject.bind(this), this.type);
139+
}
140+
141+
switchProject(projectId) {
142+
// adding project to another bucket
143+
this.switchHandler(this.projects.find(p => p.id === projectId));
144+
145+
// remove project
146+
// One way to do it
147+
// const projectIndex = this.projects.findIndex(p => p.id === projectId);
148+
// this.projects.splice(projectIndex, 1);
149+
150+
// Another way of removing the project
151+
this.projects = this.projects.filter(p => p.id !== projectId);
152+
}
153+
}
154+
155+
class App {
156+
static init(){
157+
const activeProjectsList = new ProjectList('active');
158+
const finishedProjectsList = new ProjectList('finished');
159+
activeProjectsList.setSwitchHandlerFunction(finishedProjectsList.addProject.bind(finishedProjectsList));
160+
finishedProjectsList.setSwitchHandlerFunction(activeProjectsList.addProject.bind(activeProjectsList));
161+
162+
/*
163+
This is an example of how JavaScript can execute code asynchronously via setTimeout() and setInterval(), a topic we haven't covered yet. When you set a timer in JavaScript, it won't pause the execution of your entire script. Instead, the browser registers the timer in the background and manages it, so your script can continue to run normally without interruption. When the timer expires, the browser will execute the registered function. It's important to understand that this process doesn't pause script execution, and the browser takes care of managing the timer in the background. This ensures that your script can continue to run without any pauses or disruptions.
164+
*/
165+
// document.getElementById('start-analytics').addEventListener('click', this.startAnalytics);
166+
const timerId = setTimeout(this.startAnalytics, 3000);
167+
168+
// If you click on `Stop Analytics` button before 3 seconds, the action will not be happened
169+
document.getElementById('stop-analytics').addEventListener('click', () => {clearTimeout(timerId);})
170+
}
171+
172+
// This is just a random function to demonstrate about adding a JS dynamically on some event
173+
static startAnalytics() {
174+
const analyticsScript = document.createElement('script');
175+
analyticsScript.src = 'assets/scripts/analytics.js';
176+
analyticsScript.defer = true;
177+
document.head.append(analyticsScript);
178+
}
179+
}
180+
181+
App.init();
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const button = document.querySelector('button');
2+
3+
/* Using the `on` property */
4+
5+
// button.onclick() = function() {
6+
7+
// }
8+
9+
// const buttonClickHandler = () => {
10+
// alert('Button was clicked!');
11+
// }
12+
13+
// const anotherButtonClickHandler= () => {
14+
// console.log('This was clicked!');
15+
// }
16+
17+
// Disadvantage of `on` property method is that you can assign multiple functions to an event
18+
// button.onclick = buttonClickHandler;
19+
// button.onclick = anotherButtonClickHandler;
20+
21+
// Recommended Approach
22+
button.addEventListener('click', () => {
23+
console.log('Clicked!');
24+
});

0 commit comments

Comments
 (0)