mirror of
https://github.com/dholerobin/Lecture_Notes.git
synced 2025-09-13 13:52:12 +00:00
push
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
|
||||
|
||||
## SetTimeout Method
|
||||
|
||||
`SetTimeout` is a method that allows you to execute a specific function after a certain delay.
|
||||
|
||||
**Syntax:**
|
||||
```javascript
|
||||
SetTimeoutCfn(function, delay);
|
||||
```
|
||||
|
||||
- `function`: The function you want to execute after the delay.
|
||||
- `delay`: The time interval (in milliseconds) after which the specified function should be executed.
|
||||
|
||||
For example, if you want to start an animation after a delay of 1, 2, or 3 seconds, you could use the following code:
|
||||
|
||||
```javascript
|
||||
function startAnimation() {
|
||||
// Code to start the animation
|
||||
}
|
||||
|
||||
// Using SetTimeout to call the startAnimation function after a delay
|
||||
SetTimeoutCfn(startAnimation, 1000); // 1000 milliseconds (1 second)
|
||||
SetTimeoutCfn(startAnimation, 2000); // 2000 milliseconds (2 seconds)
|
||||
SetTimeoutCfn(startAnimation, 3000); // 3000 milliseconds (3 seconds)
|
||||
```
|
||||
|
||||
|
||||
```javascript
|
||||
// Declare a variable to hold the timeout ID
|
||||
let animationTimeout;
|
||||
|
||||
// Function to start the animation
|
||||
function startAnimation() {
|
||||
// Code to start the animation
|
||||
console.log("Animation started");
|
||||
}
|
||||
|
||||
// Function to stop the animation
|
||||
function stopAnimation() {
|
||||
// Clear the timeout to prevent the animation from starting
|
||||
clearTimeout(animationTimeout);
|
||||
console.log("Animation stopped");
|
||||
}
|
||||
|
||||
// Using SetTimeout to call the startAnimation function after a delay
|
||||
animationTimeout = setTimeout(startAnimation, 2000); // Starts after 2000 milliseconds (2 seconds)
|
||||
|
||||
// You can call stopAnimation to cancel the scheduled animation
|
||||
// For example, if you want to stop it before it starts
|
||||
stopAnimation();
|
||||
```
|
||||
|
||||
In this example, we've introduced a variable `animationTimeout` to store the ID returned by the `setTimeout` function. This ID represents the scheduled timeout. When you want to stop the animation, you call `clearTimeout(animationTimeout)`, which cancels the scheduled animation and prevents it from starting.
|
||||
|
||||
Remember that using the `clearTimeout` function only has an effect if the specified timeout has not yet occurred. If the timeout has already triggered and the animation has started, clearing the timeout won't have any impact on the ongoing animation.
|
||||
|
||||
## Debouncing
|
||||
**Debouncing** is a technique used in web development to control the rate at which a function is executed, particularly in response to frequent events like scrolling, resizing, or typing. It ensures that a function is only executed after a certain period of inactivity, effectively reducing the number of times the function is called and improving performance.
|
||||
|
||||
The basic idea behind debouncing is to postpone the execution of a function until a certain amount of time has passed since the last event. This is particularly useful when you want to avoid triggering a function multiple times rapidly, which can lead to unnecessary computations or actions.
|
||||
|
||||
Here's a simple example of debouncing using JavaScript:
|
||||
|
||||
```javascript
|
||||
// Debounce function: accepts a function and a delay
|
||||
function debounce(func, delay) {
|
||||
let timeoutId;
|
||||
|
||||
// Return a function that will be executed after the delay
|
||||
return function() {
|
||||
// Clear the previous timeout
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
// Set a new timeout
|
||||
timeoutId = setTimeout(func, delay);
|
||||
};
|
||||
}
|
||||
|
||||
// Function to be debounced
|
||||
function processInput() {
|
||||
console.log("Processing input...");
|
||||
}
|
||||
|
||||
// Create a debounced version of the processInput function
|
||||
const debouncedProcessInput = debounce(processInput, 300);
|
||||
|
||||
// Simulate frequent user input (e.g., typing)
|
||||
document.addEventListener("input", debouncedProcessInput);
|
||||
```
|
||||
|
||||
In this example, the `debounce` function takes two arguments: the function you want to debounce (`func`) and the delay period (`delay`). It returns a new function that, when invoked, will clear any existing timeout and set a new one to execute the original function after the specified delay.
|
||||
|
||||
The debounced version of the `processInput` function (`debouncedProcessInput`) is then used as an event listener for the "input" event. This means that the `processInput` function will only be executed after the user has stopped typing for 300 milliseconds. If the user continues typing, the timeout will be reset, ensuring that the function is only executed once there's a pause in typing.
|
||||
|
||||
This technique is useful in scenarios where you want to avoid overwhelming the system with frequent function calls, especially for tasks like live search suggestions, updating search results, or handling user interactions.
|
||||
|
||||
Certainly! Let's walk through the theoretical explanation of the debouncing code using the provided IDs and time intervals: `id=1` with `1000ms`, `id=2` with `2000ms`, `id=3` with `2500ms`, and `id=4` with `3000ms`. We'll use these values to simulate events and understand how the debouncing mechanism works.
|
||||
|
||||
**Scenario and Explanation:**
|
||||
|
||||
Imagine that we have a user interface with a search bar. The user is typing in the search bar to perform a search, and we want to send a network request to fetch search results. However, we don't want to send a network request for every keystroke; instead, we want to wait until the user has finished typing or paused before sending the request.
|
||||
|
||||
Here's how the events play out:
|
||||
|
||||
1. `id=1`, 1000ms: The user starts typing. This event triggers the `debouncedSendNetworkRequest` function, which is set to execute after a delay of 1000ms. Since the user hasn't finished typing yet, the timer is reset to 1000ms.
|
||||
|
||||
2. `id=2`, 2000ms: The user continues typing. Another event occurs while the timer is still counting down. The timer is reset to 2000ms.
|
||||
|
||||
3. `id=3`, 2500ms: The user is still typing, but this time there's less than 2500ms left on the timer. The timer is reset to 2500ms.
|
||||
|
||||
4. `id=4`, 3000ms: The user has stopped typing, and there's no further event triggering. The timer reaches 0 after 3000ms of inactivity. At this point, the `debouncedSendNetworkRequest` function is finally executed since there hasn't been any activity for the duration of the timeout.
|
||||
|
||||
**Explanation of Code:**
|
||||
|
||||
Let's use the provided code example to explain how this works in JavaScript:
|
||||
|
||||
```javascript
|
||||
// Debounce function for network requests
|
||||
function debounceNetworkRequest(func, delay) {
|
||||
let timeoutId;
|
||||
|
||||
return function() {
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
timeoutId = setTimeout(func, delay);
|
||||
};
|
||||
}
|
||||
|
||||
// Function to send network request
|
||||
function sendNetworkRequest() {
|
||||
// Code to send the network request
|
||||
console.log("Network request sent");
|
||||
}
|
||||
|
||||
// Create a debounced version of the network request function
|
||||
const debouncedSendNetworkRequest = debounceNetworkRequest(sendNetworkRequest, 1000);
|
||||
|
||||
// Simulate user typing events
|
||||
console.log("User starts typing...");
|
||||
debouncedSendNetworkRequest(); // id=1, 1000ms
|
||||
debouncedSendNetworkRequest(); // id=2, 2000ms
|
||||
debouncedSendNetworkRequest(); // id=3, 2500ms
|
||||
console.log("User stops typing...");
|
||||
debouncedSendNetworkRequest(); // id=4, 3000ms
|
||||
```
|
||||
|
||||
As the code simulates user typing events and the associated debounced function calls, you'll notice that the actual network request is only sent when the user stops typing or pauses for at least 3000ms (the highest delay among the simulated events). This demonstrates how debouncing effectively postpones the execution of the function until the user's input has settled.
|
||||
|
||||
|
||||
|
||||
## Throttling
|
||||
|
||||
Throttling is another technique used in web development to control the rate at which a function is executed, particularly in response to frequent events. Unlike debouncing, where the function is delayed until a certain period of inactivity occurs, throttling ensures that the function is executed at a steady rate, but not more frequently than a defined interval.
|
||||
|
||||
In your example, let's explain throttling using the provided IDs and time intervals: `id=1` with `1000ms`, `id=2` with `2000ms`, `id=3` with `2500ms`, and `id=4` with `3000ms`.
|
||||
|
||||
**Scenario and Explanation:**
|
||||
|
||||
Imagine the same user interface with a search bar, and the user is typing to perform a search. In this case, we want to ensure that the network request is sent at a controlled rate, regardless of how quickly the user types. This helps to prevent excessive network requests and maintain a smoother user experience.
|
||||
|
||||
Here's how the events play out using throttling:
|
||||
|
||||
1. `id=1`, 1000ms: The user starts typing. The `throttledSendNetworkRequest` function is triggered. Since there's been more than 1000ms since the last execution, the network request is sent immediately.
|
||||
|
||||
2. `id=2`, 2000ms: The user continues typing. An event occurs within 2000ms of the last execution. However, the throttling mechanism prevents the `throttledSendNetworkRequest` function from executing immediately. The function will be queued to execute after 1000ms (the throttle interval).
|
||||
|
||||
3. `id=3`, 2500ms: The user is still typing, and an event occurs within the 1000ms throttle interval. However, the function execution is still delayed, as it hasn't been 1000ms since the last execution.
|
||||
|
||||
4. `id=4`, 3000ms: The user has stopped typing, and an event occurs after 3000ms since the last execution. The `throttledSendNetworkRequest` function is triggered again, as the throttle interval has passed.
|
||||
|
||||
**Explanation of Code:**
|
||||
|
||||
Here's how the throttling code example works in JavaScript:
|
||||
|
||||
```javascript
|
||||
// Throttle function for network requests
|
||||
function throttleNetworkRequest(func, delay) {
|
||||
let lastExecution = 0;
|
||||
|
||||
return function() {
|
||||
const now = Date.now();
|
||||
|
||||
if (now - lastExecution >= delay) {
|
||||
func();
|
||||
lastExecution = now;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Function to send network request
|
||||
function sendNetworkRequest() {
|
||||
// Code to send the network request
|
||||
console.log("Network request sent");
|
||||
}
|
||||
|
||||
// Create a throttled version of the network request function
|
||||
const throttledSendNetworkRequest = throttleNetworkRequest(sendNetworkRequest, 1000);
|
||||
|
||||
// Simulate user typing events
|
||||
console.log("User starts typing...");
|
||||
throttledSendNetworkRequest(); // id=1, 1000ms
|
||||
throttledSendNetworkRequest(); // id=2, 2000ms (delayed)
|
||||
throttledSendNetworkRequest(); // id=3, 2500ms (delayed)
|
||||
console.log("User stops typing...");
|
||||
throttledSendNetworkRequest(); // id=4, 3000ms
|
||||
```
|
||||
|
||||
In this code, the `throttleNetworkRequest` function is used to create a throttled version of the network request function. The function execution time is compared to the last execution time, and if the specified delay has passed since the last execution, the function is executed immediately. Otherwise, it's delayed until the delay interval has passed.
|
||||
|
||||
This mechanism ensures that the network request is sent at a controlled rate, respecting the throttle interval, and prevents excessive requests while still providing timely results to the user.
|
||||
|
||||
Here's a tabular comparison between debouncing and throttling:
|
||||
|
||||
| Aspect | Debouncing | Throttling |
|
||||
|---------------------|--------------------------------------------------|------------------------------------------------|
|
||||
| Purpose | Delay function execution until inactivity | Limit function execution rate |
|
||||
| Execution | Executes after a pause in events | Executes at a steady rate |
|
||||
| Event Resets Timer? | Yes, resets the timer on each event during delay | No, maintains a steady execution interval |
|
||||
| Frequency Handling | Reduces function calls during rapid events | Limits function calls to a set interval |
|
||||
| Use Cases | Typing (search suggestions), resizing events | Scrolling, mouse movement, rate-limited APIs |
|
||||
|
||||
Remember that the choice between debouncing and throttling depends on the specific use case and the desired behavior for handling frequent events in your application.
|
@@ -0,0 +1,505 @@
|
||||
# Introduction to Document Object Model
|
||||
|
||||
#### Definition
|
||||
Dom is a tree structure in which every HTML element is arranged in heirarchical order.
|
||||
|
||||
#### Example
|
||||
|
||||
```htmlembedded
|
||||
<!DOCTYPE html>
|
||||
<html lang = "en">
|
||||
<head>
|
||||
<meta charset = "UTF - 8">
|
||||
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
|
||||
<h1>This is heading 2</h1>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
<h1>This is heading 1</h1>
|
||||
|
||||
<p>This is Paragraph</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||

|
||||
|
||||
|
||||
#### DOM tree visualization of above example
|
||||
|
||||

|
||||
|
||||
**Note:**
|
||||
* We will be uisng javascript to put the interactivity in our web apps or websites.
|
||||
* JavaScript is used to put interactivity in DOM elements.
|
||||
|
||||
|
||||
#### Question
|
||||
|
||||
On clicking the button append hello to the page.
|
||||
|
||||
#### Solution
|
||||
|
||||
**Step 1:** Slecting html element
|
||||
|
||||
To select oe identify a particular html element we have methods.
|
||||
* getElementById
|
||||
* QuerySelector
|
||||
* QuerySelectorAll
|
||||
|
||||
|
||||
**Code:** Using getElementById
|
||||
|
||||
```htmlembedded
|
||||
<!DOCTYPE html>
|
||||
<html lang = "en">
|
||||
<head>
|
||||
<meta charset = "UTF - 8">
|
||||
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<button id = "btn - 1"> Say Hello </button>
|
||||
|
||||
<script>
|
||||
|
||||
// on clicking the button append hello to the page
|
||||
|
||||
let btn = document.getElementById('btn-1')
|
||||
console.log(btn)
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
|
||||
**Code:** Using getElementsByClassName
|
||||
|
||||
```htmlembedded
|
||||
<!DOCTYPE html>
|
||||
<html lang = "en">
|
||||
<head>
|
||||
<meta charset = "UTF - 8">
|
||||
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<button class = "btn - 1"> Say Hello </button>
|
||||
|
||||
<script>
|
||||
|
||||
// on clicking the button append hello to the page
|
||||
|
||||
let btn = document.getElementsByClassName('btn - 1')
|
||||
console.log(btn)
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
|
||||
**Code:** Using querySelector by ID
|
||||
|
||||
```htmlembedded
|
||||
<!DOCTYPE html>
|
||||
<html lang = "en">
|
||||
<head>
|
||||
<meta charset = "UTF - 8">
|
||||
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<button id = "btn - 1"> Say Hello </button>
|
||||
|
||||
<script>
|
||||
|
||||
// on clicking the button append hello to the page
|
||||
|
||||
let btn = document.querySelector('#btn - 1')
|
||||
console.log(btn)
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Code:** Using querySelector by class
|
||||
|
||||
```htmlembedded
|
||||
<!DOCTYPE html>
|
||||
<html lang = "en">
|
||||
<head>
|
||||
<meta charset = "UTF - 8">
|
||||
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<button id = "btn - 1"> Say Hello </button>
|
||||
<button class = "btn - 1"> Say Bye </button>
|
||||
|
||||
<script>
|
||||
|
||||
// on clicking the button append hello to the page
|
||||
|
||||
let btn = document.querySelector('.btn-1')
|
||||
console.log(btn)
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||

|
||||
|
||||
|
||||
**Code:** Using querySelector by elements
|
||||
|
||||
The document method querySelector() returns the first element within the document that matches the specified selector, or group of selectors. If no matches are found, null is returned.
|
||||
|
||||
```htmlembedded
|
||||
<!DOCTYPE html>
|
||||
<html lang = "en">
|
||||
<head>
|
||||
<meta charset = "UTF-8">
|
||||
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<button id = "btn - 1"> Say Hello </button>
|
||||
|
||||
<script>
|
||||
|
||||
// on clicking the button append hello to the page
|
||||
|
||||
let btn = document.querySelector('button')
|
||||
console.log(btn)
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Step 2:** hello should get appended
|
||||
|
||||
**What is an event?**
|
||||
Anything that happens depending on some other thins is an event. Let's say you are clicking on button then something will happen (hello is getting printed).
|
||||
|
||||
**Method - addEventListener:** We can add any event to any of our elements with using addEventListener method.
|
||||
|
||||
|
||||
```javascript
|
||||
<!DOCTYPE html>
|
||||
<html lang = "en">
|
||||
<head>
|
||||
<meta charset = "UTF - 8">
|
||||
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<button id = "btn - 1"> Say Hello </button>
|
||||
|
||||
<script>
|
||||
|
||||
// on clicking the button append hello to the page
|
||||
|
||||
let btn = document.querySelector('#btn-1')
|
||||
console.log(btn)
|
||||
|
||||
btn.addEventListener('click', function(e){
|
||||
|
||||
// console.log(e)
|
||||
|
||||
let divElem = document.createElement('div')
|
||||
|
||||
divElem.innerText = 'Hello'
|
||||
|
||||
let body = document.querySelector('body')
|
||||
|
||||
body.appendChild(divElem)
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
#### Append Hello DOM Tree
|
||||
|
||||

|
||||
|
||||
|
||||
#### Question
|
||||
|
||||
Fix the list by inserting the missing element using querySelectorAll and insertBefore
|
||||
|
||||
#### Solution
|
||||
|
||||
**Step 1:** creating node list
|
||||
|
||||
**Note:** Node list is an array like structure which will have your elements in indexed form stored.
|
||||
|
||||
```javascript
|
||||
<!DOCTYPE html>
|
||||
<html lang = "en">
|
||||
<head>
|
||||
<meta charset = "UTF - 8">
|
||||
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<ul>
|
||||
<li>1</li>
|
||||
<li>2</li>
|
||||
<li>3</li>
|
||||
<li>4</li>
|
||||
<li>5</li>
|
||||
<li>6</li>
|
||||
|
||||
<li>8</li>
|
||||
<li>9</li>
|
||||
<li>10</li>
|
||||
</ul>
|
||||
|
||||
<script>
|
||||
// Fix the list by inserting the missing element using querySelectorAll and insertBefor
|
||||
|
||||
let allItems = document.querySelectorAll('li');
|
||||
console.log(allItems);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Step 2:** adding element
|
||||
|
||||
```javascript
|
||||
<!DOCTYPE html>
|
||||
<html lang = "en">
|
||||
<head>
|
||||
<meta charset = "UTF - 8">
|
||||
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<ul>
|
||||
<li>1</li>
|
||||
<li>2</li>
|
||||
<li>3</li>
|
||||
<li>4</li>
|
||||
<li>5</li>
|
||||
<li>6</li>
|
||||
|
||||
<li>8</li>
|
||||
<li>9</li>
|
||||
<li>10</li>
|
||||
</ul>
|
||||
|
||||
<script>
|
||||
// Fix the list by inserting the missing element using querySelectorAll and insertBefore
|
||||
|
||||
let ourList = document.querySelector('ul');
|
||||
console.log(ourList);
|
||||
|
||||
let allItems = document.querySelectorAll('li');
|
||||
console.log(allItems);
|
||||
|
||||
let indexThatHas8 = allItems[6];
|
||||
|
||||
let sevenElement = document.createElement('li')
|
||||
sevenElement.innerText = '7'
|
||||
|
||||
ourList.insertBefore(sevenElement, indexThatHas8)
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
|
||||
#### Question
|
||||
|
||||
Fix the mathmatical problem using JS
|
||||
|
||||
#### Solution
|
||||
|
||||
```javascript
|
||||
<!DOCTYPE html>
|
||||
<html lang = "en">
|
||||
<head>
|
||||
<meta charset = "UTF - 8">
|
||||
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Q. Fix the mathmatical problem usng JS <br> -->
|
||||
<p>2 + 2 = 22</p>
|
||||
|
||||
<script>
|
||||
let para = document.querySelector('p')
|
||||
para.innerText = `2 + 2 = 4`
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
|
||||
#### Question
|
||||
|
||||
Write a script which fetches the data-color attribute of the card and double clicking on them and attahces the fetched class to that card and also changes the data-color attribute to "used"
|
||||
|
||||
#### Solution
|
||||
|
||||
**classList:** An element can have multiple classes attached to it and all of those classes are collected in a structure called classList.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
<div class = "card test blue"> Our card </div>
|
||||
|
||||
```
|
||||
|
||||
The classList for this div will be - [card, test, blue]
|
||||
|
||||
```javascript
|
||||
<!DOCTYPE html>
|
||||
<html lang = "en">
|
||||
<head>
|
||||
<meta charset = "UTF - 8" />
|
||||
<meta http - equiv = "X - UA - Compatible" content = "IE = edge" />
|
||||
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0" />
|
||||
<title>Document</title>
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
padding-top: 5rem;
|
||||
}
|
||||
|
||||
.blue {
|
||||
background-color: blue;
|
||||
box-shadow: 0px 0px 6px 5px;
|
||||
}
|
||||
|
||||
.green {
|
||||
background-color: green;
|
||||
box-shadow: 0px 0px 6px 5px;
|
||||
}
|
||||
|
||||
.red {
|
||||
background-color: red;
|
||||
box-shadow: 0px 0px 6px 5px;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: 1px solid;
|
||||
height: 10rem;
|
||||
width: 10rem;
|
||||
margin: 2rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class = "card" data-color = "blue"></div>
|
||||
<div class = "card" data-color = "red"></div>
|
||||
<div class = "card" data-color = "blue"></div>
|
||||
<div class = "card" data-color = "red"></div>
|
||||
<div class = "card" data-color = "red"></div>
|
||||
<div class = "card" data-color = "blue"></div>
|
||||
<div class = "card" data-color = "green"></div>
|
||||
<div class = "card" data-color = "blue"></div>
|
||||
<div class = "card" data-color = "green"></div>
|
||||
<div class = "card" data-color = "blue"></div>
|
||||
<script>
|
||||
// Q Write a script which fetches the data-color attribute of the card on
|
||||
//double clicking on them and attaches the fetched class to that card.
|
||||
// Also changes the data-color attribute to "used"
|
||||
|
||||
let cardsNodeList = document.querySelectorAll('.card')
|
||||
|
||||
console.log(cardsNodeList)
|
||||
|
||||
for(let i = 0 ; i < cardsNodeList.length; i ++ ){
|
||||
cardsNodeList[i].addEventListener('dblclick' , function(e){
|
||||
console.log(e.currentTarget)
|
||||
let classTobeAttached = e.currentTarget.getAttribute('data-color')
|
||||
|
||||
console.log(classTobeAttached)
|
||||
|
||||
e.currentTarget.classList.add(classTobeAttached)
|
||||
e.currentTarget.setAttribute('data-color' , 'used')
|
||||
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,742 @@
|
||||
# Dynamic DOM (Consume and work with an API)
|
||||
|
||||
|
||||
|
||||
## Agenda
|
||||
* Create a weather app using an API.
|
||||
* We will be using the "weather API" for getting the data of real-time weather and use that data in our app.
|
||||
* Pre-requisites required for this app include **JSON**, **API** which will be covered in this lecture itself.
|
||||
|
||||
|
||||
|
||||
### JSON
|
||||
* It stands for JavaScript Object Notation which is a data representation format.
|
||||
* Let us consider an example to understand. Suppose, you have a farm and you sell products like vegetables, fruits, eggs etc. When a customer comes, everything is organized in different sections. You won't be storing everything inside a single container. It will be segregated like this-
|
||||
|
||||

|
||||
|
||||
When a customer demands a product, that particular product will be given to them. In the same way, an API also works.
|
||||
|
||||
**API**
|
||||
* Stands for **Application Programming Interface**.
|
||||
* It is an interface where all the data and protocols can be stored in a section-wise manner.
|
||||
* Just like the above example in the way we served the request to the customers, the data will be saved in an interface called as API
|
||||
* Consider that apart from the customers, the you also cater to the needs of a restaurant by providing them with the products that they need.
|
||||
* In this way, the demands of both customers and restaurant gets their demands fulfilled.
|
||||
* These customers are basically **clients**. The shops are nothing but **servers**.
|
||||
> Ask the students if they are familiar with the concept of client and server.
|
||||
|
||||
* The data is being requested from an external factor. Whatever the client needs, he will seek that from the external source.
|
||||
* There are different use cases of various data and it is impossible to store it in a single place.
|
||||
|
||||
**Key points**
|
||||
* API acts as a bridge between client and server.
|
||||
* It has huge sets of data that can be used for applications.
|
||||
* API not only has data, but also has protocols, method implementations etc.
|
||||
|
||||
#### Example
|
||||
Consider you want to order a burger from Zomato or Swiggy. You decide to order it from Burger King. For that, Zomato will need to use the API of burger king to get the data of Burger king.
|
||||
|
||||
* This data is coming from the API.
|
||||
* The API is stored in JSON format.
|
||||
|
||||

|
||||
|
||||
|
||||
> Ask students if they have heard about APIs, then mention that some of the experienced folks might have heard about this. Earlier, REST APIs and SOAP APIs were used to store data and write APIs. Now JS devs thought about introducing JSON which is similar to the JS Syntax.
|
||||
|
||||
|
||||
**Key points**
|
||||
* JSON stands for JavaScript Object Notation.
|
||||
* It has a format similar to that of objects in JS. It has key-value pairs.
|
||||
* The value can be obtained by using a key.
|
||||
* The JSON file should end with '.json' extension.
|
||||
|
||||
|
||||
>Open VSCode and create a Farm.json file.
|
||||
|
||||
Coming to the previous example, a farm can have name, registration number, number of goods etc. There are many farms as such. **We want to create a dataset of all the farms where we can see data of each individual farm.**
|
||||
|
||||
|
||||
#### Code
|
||||
|
||||
First start with this code, and tell the students to ensure that the **keys** are enclosed in **double quotes** so that it does not throw an error.
|
||||
```javascript
|
||||
|
||||
[
|
||||
{
|
||||
"name":"Farm 1",
|
||||
"products":["Eggs","Milk","vegetables"],
|
||||
"registrationNo":1234,
|
||||
"Employees":70,
|
||||
"isOperating": true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
This is the first object. Whenever we are creating different objects within the same JSON file, ensure that the **keys remain the same** for all the objects. They should **not change**.
|
||||
|
||||
The code for 3 farms is-
|
||||
```javascript
|
||||
|
||||
{
|
||||
{
|
||||
"name":"Farm 1",
|
||||
"products":["Eggs","Milk","vegetables"],
|
||||
"registrationNo":1234,
|
||||
"Employees":70,
|
||||
"isOperating": true
|
||||
},
|
||||
{
|
||||
"name":"Farm 2",
|
||||
"products":["Eggs","Milk","Cheese"],
|
||||
"registrationNo":12345,
|
||||
"Employees":60,
|
||||
"isOperating": false
|
||||
},
|
||||
{
|
||||
"name":"Farm 1",
|
||||
"products":["vegetables"],
|
||||
"registrationNo":12346,
|
||||
"Employees":30,
|
||||
"isOperating": true
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
> Show some examples of APIs to the students. Tell them that we will be creating a weather app today and open it.
|
||||
> https://www.weatherapi.com/
|
||||
> Inform that they need to sign-in.
|
||||
|
||||
* Find the API key and paste it under the **API explorer** tab.
|
||||
* Select the protocol as **HTTPS**.
|
||||
* Click on show response. You can see the JSON format in the response section.
|
||||
|
||||
Proceeding to our code, create an `index.html` file. Inside the script tag, paste the above JSON code.
|
||||
|
||||
```javascript
|
||||
<!DOCTYPE html>
|
||||
<html lang = "en">
|
||||
<head>
|
||||
<meta charset = "UTF - 8">
|
||||
<meta name = "viewport" content = "width = device-width, initial-scale = 1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
let data = [
|
||||
{
|
||||
"name":"Farm 1",
|
||||
"products":["Eggs","Milk","vegetables"],
|
||||
"registrationNo":1234,
|
||||
"Employees":70,
|
||||
"isOperating": true
|
||||
},
|
||||
{
|
||||
"name":"Farm 2",
|
||||
"products":["Eggs","Milk","Cheese"],
|
||||
"registrationNo":12345,
|
||||
"Employees":60,
|
||||
"isOperating": false
|
||||
},
|
||||
{
|
||||
"name":"Farm 1",
|
||||
"products":["vegetables"],
|
||||
"registrationNo":12346,
|
||||
"Employees":30,
|
||||
"isOperating": true
|
||||
}
|
||||
|
||||
]
|
||||
console.log(data)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
You will see an array of objects. This is not in the JSON format. To obtain the JSON format, we will enclose the objects in backtick.
|
||||
|
||||
**Key points**
|
||||
* To convert JSON to JavaScript readable code, we use the **JSON.parse()** method
|
||||
* The data received from a web server is a string, so to convert we use the JSON.parse() method to convert to a JavaScript object.
|
||||
* When working with APIs, we get everything in string, so to parse that JSON, we use the JSON.parse() method.
|
||||
|
||||
|
||||
>Brief the students about the steps to sign up on the https://www.weatherapi.com/. Ask them to do it accordingly.
|
||||
|
||||
* After logging in, there will be an API key generated which will be unique for everyone. Copy that key first.
|
||||
* Under **API Response Fields**, you can check all the fields that the API is providing. There are many options available.
|
||||
* Under **API Explorer**, paste the key. You will see the API Call as follows.
|
||||
|
||||

|
||||
|
||||
|
||||
Here the "q" stands for **query** and here we are querying for London. The call is basically our URL and inside this we also have our API key and the search query.
|
||||
|
||||
* Apart from the current data, you can also get the Forecast, Future data as provided by the API.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
> Inform the students that For this project, we will be focusing on the JS part, so the CSS part has already been created and we just have to paste it.
|
||||
> Guide the students about the final interface before starting the code.
|
||||
|
||||

|
||||
|
||||
|
||||
**Step 1**
|
||||
Create `index.html`, `style.css` and `index.js` files in VSCode.
|
||||
|
||||
**Step 2**
|
||||
Inside the `index.html` file, we will be creating various divisions for various parameters like temperature, location, time and date etc.
|
||||
|
||||

|
||||
|
||||
In the other division for weather condition, we will display an emoji along with the weather condition.
|
||||
|
||||

|
||||
|
||||
**Step 3**
|
||||
Create a form which contains an input field and a button also.
|
||||
|
||||

|
||||
|
||||
> Write a step-by-step code for each step.
|
||||
|
||||
**Code**
|
||||
```javascript
|
||||
<!DOCTYPE html>
|
||||
<html lang = "en">
|
||||
<head>
|
||||
<meta charset = "UTF - 8">
|
||||
<meta http-equiv = "X - UA - Compatible" content = "IE = edge">
|
||||
<meta name = "viewport" content = "width = device-width, initial-scale = 1.0">
|
||||
<title>Weather app Class</title>
|
||||
|
||||
<link rel = "stylesheet" href = "style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class = "container">
|
||||
<div class = "weather">
|
||||
<div class = "temp">20</div>
|
||||
<div class = "time_location">
|
||||
<p>Location</p>
|
||||
<span>Random time and Date</span>
|
||||
</div>
|
||||
|
||||
<div class = "weather_condition">
|
||||
<p><img src = "" alt = ""></p>
|
||||
<span>Condition</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<nav>
|
||||
<form>
|
||||
<input type = "text" placeholder = "Search_location" class = "searchField">
|
||||
<button type = "submit">Search</button>
|
||||
</form>
|
||||
</nav>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
<script src = "index.js"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
Execute the above code, the output is
|
||||
|
||||

|
||||
|
||||
This is a simple HTML code, we will have to add CSS to style it.
|
||||
|
||||
> Inform the students that we will not focus on the CSS part as it is simple. We will just paste the code.
|
||||
|
||||
**Style.css**-
|
||||
```css
|
||||
@import url("https://fonts.googleapis.com/css2?family=Economica&family=Grape+Nuts&family=Roboto:wght@100;300;400;700;900&display=swap");
|
||||
|
||||
* {
|
||||
margin: 0%;
|
||||
padding: 0;
|
||||
font-family: "Roboto", sans-serif;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background-color:#01161E;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
.weather {
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.weather > div {
|
||||
margin: 0.625rem;
|
||||
}
|
||||
|
||||
.weather1 {
|
||||
font-size: 4rem;
|
||||
}
|
||||
|
||||
.weather p {
|
||||
font-size: 2rem;
|
||||
}
|
||||
.weather span {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.weather3 span {
|
||||
margin: 0.3rem;
|
||||
}
|
||||
|
||||
.weather3 img {
|
||||
width: 2rem;
|
||||
}
|
||||
nav {
|
||||
height: 100px;
|
||||
padding: 1rem 0;
|
||||
position: absolute;
|
||||
bottom: 0%;
|
||||
width: 100%;
|
||||
background-color: rgba(180, 177, 177, 0.202);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
nav form {
|
||||
width: 70%;
|
||||
grid-template-columns: 5fr 1fr;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.searchField {
|
||||
font-size: 1.1rem;
|
||||
outline: none;
|
||||
color: white;
|
||||
background-color: transparent;
|
||||
padding: 1rem 0;
|
||||
border: none;
|
||||
border-bottom: 2px solid white;
|
||||
width: 98%;
|
||||
}
|
||||
|
||||
nav form button {
|
||||
background-color:#4ECDC4;
|
||||
font-size: 1.1rem;
|
||||
color: white;
|
||||
outline: none;
|
||||
border: none;
|
||||
cursor: pointer;}
|
||||
```
|
||||
|
||||
After executing the CSS code, the output is
|
||||
|
||||

|
||||
|
||||
**Index.js**-
|
||||
|
||||
We will see how to get data from an API. We will use the **fetch API**. The **fetch()** method will be used here.
|
||||
> Type fetch method in the browser and just show the docs as a glimpse.
|
||||
|
||||
The URL will be passed to the fetch() method as a parameter. We will understand how to use the fetch() method inside our JS code.
|
||||
|
||||
We will be coming across various terms like async, await but they will be covered in depth in the later lectures.
|
||||
|
||||
Before diving deep into the fetch() method, we will understand the try and catch block which is a pre-requisite for this.
|
||||
|
||||
The try block is used to execute the code that might encounter an error. An error can lead to unexpected termination of the program. Hence we put it inside the try block and any error that might be encountered by the try block is sent to the catch block. This is the exception handling concept.
|
||||
|
||||
In the try block, we will define the URL which is the API call.
|
||||
|
||||
```javascript
|
||||
let url = `https://api.weatherapi.com/v1/current.json?key=35af7ff606db422880d141328231305&q=${target}&aqi=no`
|
||||
```
|
||||
Here we have wrapped the url in backticks so that we can use the string template literals which denoted bt the `${}` symbol.
|
||||
|
||||
* Let us understand using a real-life analogy about asynchronous programming.
|
||||
|
||||
* Suppose you are teaching a batch of 100 students. One student asks doubt and it takes 5 minutes to resolve it. Another student asks a doubt which takes another 5 minutes. One more student asks a doubt and it takes 5 minutes. To solve the doubts of 3 students, 97 students has to waste their 15 minutes.
|
||||
|
||||
> Ask the students what could a better approach for this?
|
||||
|
||||
* A better approach is to teach first and in the last few minutes of the lecture, take up the doubts of the students. In this way, the time of the other students is not wasted.
|
||||
|
||||
* Now just replace students with functions. The first approach is the synchronous programming where everything happens in a sequence.
|
||||
|
||||
* In synchronous programming, important instructions get blocked due to some previous instructions, which causes a delay in the user interface. **Asynchronous** code execution allows to execution next instructions immediately and **doesn't block the flow** because of previous instructions.
|
||||
|
||||
**Key points**
|
||||
* In APIs, we will be using the asynchronous JS.
|
||||
* We will be using **async** and **await** keywords which are important.
|
||||
* The **async** keyword needs to be added before the function which tells the function that it is asynchronous.
|
||||
* The **await** keyword tells that it needs wait till the data comes.
|
||||
|
||||
```javascript
|
||||
const response = await fetch(url)
|
||||
```
|
||||
|
||||
Now let's run the code till now.
|
||||
|
||||
```java
|
||||
let target = "Pune"
|
||||
async function fetchData(target){
|
||||
try {
|
||||
let url = `https://api.weatherapi.com/v1/current.json?key=8b6d5f63a04a485fa5351525232908&q=${target}&aqi=no`
|
||||
|
||||
const response = await fetch(url)
|
||||
|
||||
console.log(response)
|
||||
}
|
||||
catch(error){
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
fetchData(target)
|
||||
```
|
||||
|
||||
We will obtain this
|
||||
|
||||

|
||||
|
||||
This is not in the JSON format. We will have to convert this to JSON by using the **.json() method**.
|
||||
|
||||
We will add this line-
|
||||
```javascript
|
||||
const data = await response.json()
|
||||
console.log(data)
|
||||
```
|
||||
|
||||
We will receive the data in JS object format.
|
||||
|
||||
Now we will **extract dynamic values from** the object.
|
||||
|
||||
Look into the format, to obtain temperature, we will go under `current` and then in `temp_c`
|
||||
|
||||

|
||||
|
||||
Let us write the required values.
|
||||
|
||||
```java
|
||||
let currentTemp = data.current.temp_c
|
||||
let currentCondition = data.current.condition.text
|
||||
let locationName = data.location.name
|
||||
let localTime = data.location.localtime
|
||||
let conditionEmoji = data.current.condition.icon
|
||||
```
|
||||
We will print these values on the console to see if they have been fetched properly or not. Output is
|
||||
|
||||

|
||||
|
||||
|
||||
To print and display the data on the website, we will use DOM. The data has to be changed dynamically and for that, DOM has to be used. We will use the classes earlier written in HTML to target and dynamically set values. The code for DOM part-
|
||||
|
||||
```javascript
|
||||
const temperatureField = document.querySelector(".temp");
|
||||
const cityField = document.querySelector(".time_location p");
|
||||
const dateField = document.querySelector(".time_location span");
|
||||
const emojiField = document.querySelector(".weather_condition img");
|
||||
const weatherField = document.querySelector(".weather_condition span");
|
||||
const searchField = document.querySelector(".searchField");
|
||||
const form = document.querySelector("form");
|
||||
```
|
||||
> Just explain in short about the variable and which class it is targeting. Eg- `temperatureField` variable is targeting the `temp` class.
|
||||
|
||||
Now, we want to make our search bar work. We will add an event listener to it. Whenever there is an event performed, the event listener will execute the callback function passed as a parameter.
|
||||
|
||||
The search function changes the value of the target(the target city) to the value that we have entered. After typing the city and pressing the submit button, the form will get submitted and the "submit" event will get invoked.
|
||||
|
||||
The `fetchData` function will be passed the value of the target that we have entered.
|
||||
|
||||
```javascript
|
||||
form.addEventListener('submit' , search )
|
||||
|
||||
//search- callback function
|
||||
|
||||
function search(){
|
||||
target = searchField.value
|
||||
|
||||
fetchData(target)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The code till now is
|
||||
|
||||
```javascript
|
||||
const temperatureField = document.querySelector(".temp");
|
||||
const cityField = document.querySelector(".time_location p");
|
||||
const dateField = document.querySelector(".time_location span");
|
||||
const emojiField = document.querySelector(".weather_condition img");
|
||||
const weatherField = document.querySelector(".weather_condition span");
|
||||
const searchField = document.querySelector(".searchField");
|
||||
const form = document.querySelector("form");
|
||||
|
||||
let target = "Pune"
|
||||
async function fetchData(target){
|
||||
try {
|
||||
let url = `https://api.weatherapi.com/v1/current.json?key=8b6d5f63a04a485fa5351525232908&q=${target}&aqi=no`
|
||||
|
||||
const response = await fetch(url)
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
form.addEventListener('submit' , search )
|
||||
|
||||
function search(){
|
||||
target = searchField.value
|
||||
|
||||
fetchData(target)
|
||||
}
|
||||
console.log(data)
|
||||
|
||||
let currentTemp = data.current.temp_c
|
||||
let currentCondition = data.current.condition.text
|
||||
let locationName = data.location.name
|
||||
let localTime = data.location.localtime
|
||||
let conditionEmoji = data.current.condition.icon
|
||||
console.log(currentTemp ,currentCondition ,locationName , localTime , conditionEmoji )
|
||||
}
|
||||
catch(error){
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
fetchData(target)
|
||||
```
|
||||
|
||||
After we run the code, we see that even after entering the name of the city in the search bar, the results are not getting updated. It is because, the form is submitting the value somewhere and page is getting refreshed. This is the nature of the form that after it is submitted, the page is refreshed.
|
||||
|
||||
For that, we use the **preventDefault()** method. Our code for the `search()` function becomes-
|
||||
|
||||
```javascript
|
||||
function search(e){
|
||||
|
||||
e.preventDefault()
|
||||
target = searchField.value
|
||||
|
||||
fetchData(target)
|
||||
}
|
||||
```
|
||||
|
||||
Now, when we search for a city, the output is obtained on the console.
|
||||
|
||||

|
||||
|
||||
|
||||
Now, we will update the data on our page. A function `updateDOM()` will be created which will contain the values to be updates as parameters.
|
||||
|
||||
|
||||
>First demonstrate this example. We will use the **innerText()** method to set the value inside the HTML.
|
||||
|
||||
```javascript
|
||||
function updateDOM(temp , locationName , time , emoji , condition){
|
||||
|
||||
temperatureField.innerText = temp
|
||||
|
||||
cityField.innerText = locationName
|
||||
|
||||
|
||||
emojiField.src = emoji
|
||||
|
||||
weatherField.innerText = condition
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
**ADD DAY**
|
||||
|
||||
We can also add day along with the date. Here, **date objects** will be used.
|
||||
|
||||
> console.log(time) then ask the students whether the date or the time is useful to get the day. The answer is date.
|
||||
|
||||
Since the date and time is separated by a space, we will use the **split()** method to separate them.
|
||||
|
||||

|
||||
|
||||
The split() method splits the value at the delimiter provided and returns an array. Here. after splitting the above value, we get the date at 0th position and time at 1st position.
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
const exactTime = time.split(" ")[1]
|
||||
const exactdate = time.split(' ')[0]
|
||||
```
|
||||
|
||||
To convert date to day, we follow-
|
||||
```java
|
||||
const exactDate = new Date(exactdate).getDay()
|
||||
```
|
||||
|
||||
The output is a number which indicate the day in form of a number.
|
||||
|
||||

|
||||
|
||||
We will write another function that converts the day number to day.
|
||||
|
||||
```javascript
|
||||
function getDayFullName(num) {
|
||||
switch (num) {
|
||||
case 0:
|
||||
return "Sunday";
|
||||
|
||||
case 1:
|
||||
return "Monday";
|
||||
|
||||
case 2:
|
||||
return "Tuesday";
|
||||
|
||||
case 3:
|
||||
return "Wednesday";
|
||||
|
||||
case 4:
|
||||
return "Thursday";
|
||||
|
||||
case 5:
|
||||
return "Friday";
|
||||
|
||||
case 6:
|
||||
return "Saturday";
|
||||
|
||||
default:
|
||||
return "Don't Know";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Our final code is
|
||||
|
||||
```javascript
|
||||
const temperatureField = document.querySelector(".temp");
|
||||
const cityField = document.querySelector(".time_location p");
|
||||
const dateField = document.querySelector(".time_location span");
|
||||
const emojiField = document.querySelector(".weather_condition img");
|
||||
const weatherField = document.querySelector(".weather_condition span");
|
||||
const searchField = document.querySelector(".searchField");
|
||||
const form = document.querySelector("form");
|
||||
|
||||
|
||||
let target = 'Pune'
|
||||
|
||||
|
||||
form.addEventListener('submit' , search )
|
||||
|
||||
|
||||
function search(e){
|
||||
|
||||
e.preventDefault()
|
||||
target = searchField.value
|
||||
|
||||
fetchData(target)
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function fetchData(target){
|
||||
try {
|
||||
let url = `https://api.weatherapi.com/v1/current.json?key=35af7ff606db422880d141328231305&q=${target}&aqi=no`
|
||||
|
||||
const response = await fetch(url)
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
console.log(data)
|
||||
|
||||
|
||||
let currentTemp = data.current.temp_c
|
||||
let currentCondition = data.current.condition.text
|
||||
let locationName = data.location.name
|
||||
let localTime = data.location.localtime
|
||||
let conditionEmoji = data.current.condition.icon
|
||||
|
||||
console.log(currentTemp ,currentCondition ,locationName , localTime , conditionEmoji )
|
||||
|
||||
|
||||
updateDOM(currentTemp , locationName ,localTime ,conditionEmoji , currentCondition)
|
||||
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function updateDOM(temp , locationName , time , emoji , condition){
|
||||
|
||||
|
||||
console.log(time)
|
||||
|
||||
const exactTime = time.split(" ")[1]
|
||||
const exactdate = time.split(' ')[0]
|
||||
|
||||
|
||||
|
||||
|
||||
const exactDay = getDayFullName(new Date(exactdate).getDay())
|
||||
console.log(exactDay)
|
||||
|
||||
|
||||
|
||||
temperatureField.innerText = temp
|
||||
|
||||
cityField.innerText = locationName
|
||||
|
||||
dateField.innerText = `${exactTime} ${exactDay} ${exactdate}`
|
||||
|
||||
|
||||
emojiField.src = emoji
|
||||
|
||||
weatherField.innerText = condition
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getDayFullName(num) {
|
||||
switch (num) {
|
||||
case 0:
|
||||
return "Sunday";
|
||||
|
||||
case 1:
|
||||
return "Monday";
|
||||
|
||||
case 2:
|
||||
return "Tuesday";
|
||||
|
||||
case 3:
|
||||
return "Wednesday";
|
||||
|
||||
case 4:
|
||||
return "Thursday";
|
||||
|
||||
case 5:
|
||||
return "Friday";
|
||||
|
||||
case 6:
|
||||
return "Saturday";
|
||||
|
||||
default:
|
||||
return "Don't Know";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fetchData(target)
|
||||
```
|
@@ -0,0 +1,462 @@
|
||||
|
||||
|
||||
## Agenda
|
||||
**Topics to cover in Javascript:**
|
||||
|
||||
Certainly, here are the headings for the provided topics:
|
||||
|
||||
1. **Kanban Board**
|
||||
2. **Create and Update Task**
|
||||
3. **Lock and Unlock Tasks**
|
||||
4. **Colors**
|
||||
5. **Pop-up Dialog Box**
|
||||
6. **Delete**
|
||||
8. **Local Storage**
|
||||
|
||||
We will try to cover most of these topics in today's sessions and the remaining in the next.
|
||||
|
||||
So let's start.
|
||||
|
||||
|
||||
|
||||
## Demo of the project:
|
||||
|
||||
Initially showing the demonstartion of the adding task, setting the colors, unlock/lock feature, filtering based on the colors and delete feature.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
Discussing about the local storage and the crud operation and also try to cover the drag-drop functionalities, accessibility.
|
||||
|
||||
On the highest level, mainly there are two components, to mark those will be using the two divs namely toolbox-container and maincontainer.
|
||||
|
||||
Inside the toolbox container first there are different tags for colors which we ca have and after that these two boxes of + and X. Apart fro that we can those ticket also.
|
||||
|
||||
|
||||
### WireFrame of the Kanban Board
|
||||
|
||||

|
||||
|
||||
In toolbox container there are two container namely toolbox-priority-cont and action-btn-cont.
|
||||
* Inside the toolbox-priority-cont we are having the four divs of colors(pink, blue, purple and green).
|
||||
* In the toolbox-priority-cont having the two divs of add-btn and remove-btn. Alaso adding the font from the cdn font library.
|
||||
|
||||
|
||||
Opening the live server and just seeing the effects of the added code till now and nothing is visible till now since no css has been added.
|
||||
|
||||
```htmlembedded
|
||||
<!DOCTYPE html>
|
||||
<html lang = "en">
|
||||
<head>
|
||||
<meta charset = "UTF - 8">
|
||||
<meta http-equiv = "X - UA - Compatible" content = "IE = edge">
|
||||
<meta name = "viewport" content = "width = device-width, initial-scale = 1.0">
|
||||
<title>KanbanBoard</title>
|
||||
<link rel = "stylesheet" href = "./style.css">
|
||||
<link rel = "stylesheet" href = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw == " crossorigin = "anonymous" referrerpolicy = "no-referrer" />
|
||||
</head>
|
||||
<body>
|
||||
<div class = "toolbox-cont">
|
||||
<div class = "toolbox-priority-cont">
|
||||
<div class = "color red"></div>
|
||||
<div class = "color blue"></div>
|
||||
<div class = "color green"></div>
|
||||
<div class = "color black"></div>
|
||||
</div>
|
||||
<div class = "action-btn-cont">
|
||||
<div class = "add-btn">
|
||||
<i class = "fa-solid fa-plus fa-xl"></i>
|
||||
</div>
|
||||
<div class = "remove-btn">
|
||||
<i class = "fa-solid fa-trash fa-lg"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class = "main-cont">
|
||||
<!-- <div class = "ticket-cont">
|
||||
<div class = "ticket-color red"></div>
|
||||
<div class = "ticket-id">#qu45</div>
|
||||
<div class = "task-area" contenteditable = "true">Some Task</div>
|
||||
<div class = "lock-unlock"><i class = "fa-solid fa-lock"></i></div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
|
||||
<div class = "modal-cont">
|
||||
<textarea class = "textarea-cont" placeholder = "Enter Your Task"></textarea>
|
||||
<div class = "priority-color-cont">
|
||||
<div class = "priority-color red"></div>
|
||||
<div class = "priority-color blue"></div>
|
||||
<div class = "priority-color green"></div>
|
||||
<div class = "priority-color black active"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src = "https://cdn.jsdelivr.net/npm/short-unique-id@latest/dist/short-unique-id.min.js"></script>
|
||||
<script src = "./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||

|
||||
|
||||
Nothing is visible as no css has been added.
|
||||
|
||||

|
||||
|
||||
Let's start creating the css file namely style.css, and adding the code for the colors first by creating the css variables for the colors like pink, green, purple etc.
|
||||
|
||||
```css
|
||||
/* create css variables */
|
||||
:root{
|
||||
--ligthBackground: #F9F5EB;
|
||||
--background:#E4DCCF;
|
||||
--red:#EA5455;
|
||||
--blue:#002B5B;
|
||||
--green:#245953;
|
||||
}
|
||||
|
||||
*{
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: var(--background);
|
||||
}
|
||||
```
|
||||
|
||||
Now adding the css for the toolbox container starting with height, background-color and then adding the toolbox-priority-container by providing it with height, background-color. Same for the action-btn also same color and height.
|
||||
|
||||
```css
|
||||
/* styling starts from here */
|
||||
|
||||
|
||||
/* ************toolbox_cont **********/
|
||||
.toolbox-cont{
|
||||
height: 5rem;
|
||||
background-color: var(--blue);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100vw;
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
Now adding the display: flex in the parent conatiner namely in the toolbox-container in the css code. Add margin-left in the toolbox-priority-cont and margin-left in the action-btn-cont. Also change the background-color of the action-btn-cont to the light.
|
||||
|
||||
Now add the color blocks in the toolbox-priority-cont. Providing the height and width to the color block. Also add the display:space-evenly and align-items:center to the parent class.
|
||||
|
||||
```css
|
||||
.toolbox-priority-cont{
|
||||
height: 3rem;
|
||||
width: 18rem;
|
||||
background-color:var(--ligthBackground);
|
||||
margin-left: 5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.action-btn-cont{
|
||||
height: 3rem;
|
||||
width: 10rem;
|
||||
background-color:var(--ligthBackground);
|
||||
margin-left: 5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.color{
|
||||
height: 1.5rem;
|
||||
width: 3rem;
|
||||
}
|
||||
.red{
|
||||
background-color: var(--red);
|
||||
}
|
||||
|
||||
.blue{
|
||||
background-color: var(--blue);
|
||||
}
|
||||
|
||||
.green{
|
||||
background-color: var(--green);
|
||||
}
|
||||
|
||||
.black{
|
||||
background-color: black;
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||

|
||||
|
||||
|
||||

|
||||
|
||||
Provide the font size to the both add-btn and remove-btn and also add the display:flex, align-item:center and justify-content:space-evenly in the action-btn-cont.
|
||||
|
||||
```css
|
||||
.add-btn,.remove-btn{
|
||||
font-size: 1.25rem
|
||||
}
|
||||
.action-btn-cont{
|
||||
height: 3rem;
|
||||
width: 10rem;
|
||||
background-color:var(--ligthBackground);
|
||||
margin-left: 5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
}
|
||||
```
|
||||

|
||||
|
||||
Now let's add the hover effect to the button of add-btn and remove-btn as follows:
|
||||
```css
|
||||
.add-btn:hover{
|
||||
background-color: #4BB543;
|
||||
}
|
||||
.remove-btn:hover{
|
||||
background-color: #4BB543;
|
||||
}
|
||||
```
|
||||
|
||||
**Asking Question?**
|
||||
|
||||
Can you add the hover effect to these color boxes in the nav bar?
|
||||
**Ans:** You can try by themself.
|
||||
|
||||
Now lets start creating the modal with its html and css structure as follows:
|
||||
|
||||
```htmlembedded
|
||||
<div class = "modal-cont">
|
||||
<textarea class = "textarea-cont" placeholder = "Enter Your Task"></textarea>
|
||||
<div class = "priority-color-cont">
|
||||
<div class = "priority-color red"></div>
|
||||
<div class = "priority-color blue"></div>
|
||||
<div class = "priority-color green"></div>
|
||||
<div class = "priority-color black active"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
```css
|
||||
.modal-cont{
|
||||
height: 50vh;
|
||||
width: 45vw;
|
||||
display: flex;
|
||||
background-color: lightsalmon;
|
||||
position: absolute;
|
||||
top:30%;
|
||||
left: 27%;
|
||||
display: none;
|
||||
|
||||
|
||||
}
|
||||
.textArea-cont{
|
||||
height: 100%;
|
||||
width: 75%;
|
||||
resize: none;
|
||||
outline: none;
|
||||
border: none;
|
||||
background-color: #dfe4ea;
|
||||
font-size: 2rem;
|
||||
color: black;
|
||||
}
|
||||
.priority-colors-container{
|
||||
height: 100%;
|
||||
width: 25%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #4b4b4b;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
|
||||
}
|
||||
.priority-color{
|
||||
height: 3rem;
|
||||
width: 5rem;
|
||||
}
|
||||
|
||||
.active{
|
||||
border: 5px solid lightsalmon;
|
||||
}
|
||||
```
|
||||

|
||||
|
||||
|
||||

|
||||
|
||||
|
||||

|
||||
|
||||
|
||||

|
||||
|
||||
This CSS code defines styles for a modal container and its components:
|
||||
|
||||
1. **.modal-cont:**
|
||||
- Defines the modal's dimensions and appearance.
|
||||
- Positioned absolutely with a specific top and left offset.
|
||||
- Initially hidden with `display: none`.
|
||||
|
||||
2. **.textArea-cont:**
|
||||
- Represents a text area within the modal.
|
||||
- Takes 75% of the modal's width.
|
||||
- Has specific styling for background color, font size, and no borders.
|
||||
|
||||
3. **.priority-colors-container:**
|
||||
- A container for priority color elements.
|
||||
- Takes 25% of the modal's width.
|
||||
- Aligns items vertically and adds a background color.
|
||||
|
||||
4. **.priority-color:**
|
||||
- Represents priority color elements.
|
||||
- Fixed dimensions for each element.
|
||||
|
||||
5. **.active:**
|
||||
- Adds a border to elements with this class, using a lightsalmon color.
|
||||
|
||||
Overall, these styles are likely used for a modal interface, with a text area and priority color options.
|
||||
|
||||
Now we will be working for the buttons of + and X by giving the event listener to them. Here is a basic structure of the event Litener for them as follows:
|
||||
|
||||
```htmlembedded
|
||||
Eventlistener.(click):
|
||||
let flag=false
|
||||
flag=true
|
||||
if(flag=true){
|
||||
modal visible
|
||||
}
|
||||
```
|
||||
|
||||
```javascript!
|
||||
let addBtn = document.querySelector('.add-btn')
|
||||
let modalCont = document.querySelector('.modal-cont')
|
||||
let addTaskFlag = false
|
||||
|
||||
addBtn.addEventListener('click' , function(){
|
||||
// Display the model
|
||||
addTaskFlag = !addTaskFlag
|
||||
|
||||
if(addTaskFlag == true){
|
||||
modalCont.style.display = 'flex'
|
||||
}
|
||||
else{
|
||||
modalCont.style.display = 'none'
|
||||
}
|
||||
|
||||
})
|
||||
```
|
||||
This JavaScript code adds functionality to a button:
|
||||
|
||||
1. `addBtn` and `modalCont` variables are defined to select HTML elements with specific classes.
|
||||
|
||||
2. An event listener is added to `addBtn` for a click event.
|
||||
|
||||
3. When the button is clicked, a flag (`addTaskFlag`) toggles between true and false.
|
||||
|
||||
4. If `addTaskFlag` is true, the modal container (`modalCont`) is displayed by changing its `display` style property to 'flex'.
|
||||
|
||||
5. If `addTaskFlag` is false, the modal container is hidden by setting its `display` property to 'none'.
|
||||
|
||||
This code toggles the visibility of the modal when the button is clicked.
|
||||
|
||||
|
||||
Now lets create the structure of the task ticket as follows:
|
||||
|
||||
```htmlembedded
|
||||
<!-- Task Ticket -->
|
||||
|
||||
<div class = "main-cont">
|
||||
<!-- <div class = "ticket-cont">
|
||||
<div class = "ticket-color"></div>
|
||||
<div class = "ticket-id">12345</div>
|
||||
<div class = "task-area" contenteditable = "false">Random Task</div>
|
||||
<div class = "ticket-lock">
|
||||
<i class = "fa-solid fa-lock"></i>
|
||||
</div>
|
||||
</div> -->
|
||||
```
|
||||
Now also give the styling to the task ticket:
|
||||
```javascript
|
||||
.modal-cont{
|
||||
height: 50vh;
|
||||
width: 45vw;
|
||||
display: flex;
|
||||
background-color: lightsalmon;
|
||||
position: absolute;
|
||||
top:30%;
|
||||
left: 27%;
|
||||
display: none;
|
||||
}
|
||||
.ticket-cont{
|
||||
height: 12rem;
|
||||
width: 15rem;
|
||||
background-color: coral;
|
||||
}
|
||||
.ticket-color{
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.ticket-id{
|
||||
background-color: yellow;
|
||||
height: 2rem;
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||

|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
This CSS code defines styles for a modal container and its associated ticket elements:
|
||||
|
||||
1. **.modal-cont:**
|
||||
- Defines the modal's dimensions and appearance.
|
||||
- Positioned absolutely with specific top and left offsets.
|
||||
- Initially hidden with `display: none`.
|
||||
- Has a flex display and a light salmon background color.
|
||||
|
||||
2. **.ticket-cont:**
|
||||
- Represents a ticket container.
|
||||
- Fixed height and width for each ticket.
|
||||
- Coral background color.
|
||||
|
||||
3. **.ticket-color:**
|
||||
- Represents a color strip on the ticket.
|
||||
- Fixed height and width, typically used for visual categorization.
|
||||
|
||||
4. **.ticket-id:**
|
||||
- Represents the ID section of the ticket.
|
||||
- Has a yellow background color and a specific height.
|
||||
|
||||
These styles appear to be used for creating a modal with tickets, each with a color strip and an ID section.
|
||||
|
||||
|
@@ -0,0 +1,292 @@
|
||||
# Full Stack LLD & Projects: JavaScript-8: Kanban Board-2(DOM Implementation & Manipulation)
|
||||
|
||||
|
||||
|
||||
**Agenda of this Lecture:**
|
||||
|
||||
* Ticket Generation
|
||||
* Adding Task, colour, ID to generated ticket
|
||||
* Ticket Removal
|
||||
* Locking Mechanism
|
||||
* Editing Ticket Content
|
||||
|
||||
|
||||
|
||||
### Explanation
|
||||
|
||||
We'll begin by implementing the ticket generation feature, which involves creating a function to dynamically generate new task tickets. These tickets will then be manipulated and moved across the columns using DOM (Document Object Model) manipulation.
|
||||
|
||||
In the file `script.js` we will add this function:
|
||||
|
||||
```javascript
|
||||
function createTicket() {
|
||||
// Create a new ticket container element
|
||||
let ticketCont = document.createElement('div');
|
||||
}
|
||||
```
|
||||
|
||||
Now we will add **class** to this particular div using the `setAttribute` :
|
||||
|
||||
```javascript
|
||||
function createTicket() {
|
||||
// Create a new ticket container element
|
||||
let ticketCont = document.createElement('div');
|
||||
|
||||
// Set the class attribute of the ticket container
|
||||
ticketCont.setAttribute('class', 'ticket-cont'); //
|
||||
}
|
||||
```
|
||||
|
||||
Whenever this function is called, a new ticket will be created with class `ticket-cont`.
|
||||
|
||||
As `ticketCont` contains 3 more divs inside, we will create them inside this function using `innerHTML` function
|
||||
|
||||
```javascript
|
||||
function createTicket() {
|
||||
// Create a new ticket container element
|
||||
let ticketCont = document.createElement('div');
|
||||
ticketCont.setAttribute('class', 'ticket-cont');
|
||||
|
||||
// Create the HTML content for the ticket container
|
||||
ticketCont.innerHTML = `
|
||||
<div class="ticket-color"></div>
|
||||
<div class="ticket-id">12345/div>
|
||||
<div class="task-area">Random Task</div>`
|
||||
|
||||
mainCont.appendChild(ticketCont)
|
||||
```
|
||||
|
||||
So we are passing the HTML codes here, so whenever a ticket is created , these 3 divs will also be there.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### Explanation
|
||||
|
||||
The `addEventListener` method is used to attach an event listener to a DOM element, allowing you to respond to specific events like clicks, key presses, mouse movements, etc.
|
||||
|
||||
We add an event listener to the `modalCont` element for the 'keydown' event. This event occurs when a key on the keyboard is pressed and then released.
|
||||
|
||||
```javascript
|
||||
modalCont.addEventListener('keydown', function(e) {
|
||||
let key = e.key;
|
||||
|
||||
if (key === 'Shift') {
|
||||
createTicket(); // Call the createTicket function to create a new ticket
|
||||
modalCont.style.display = 'none'; // Hide the modal
|
||||
textArea.value = ''; // Clear the textarea's content
|
||||
}
|
||||
})
|
||||
```
|
||||

|
||||
|
||||
|
||||
|
||||
### Explanation
|
||||
|
||||
As of now everything like Task, color and ID of the created task is static. In this we will be making it dynamic.
|
||||
|
||||

|
||||
|
||||
So we can choose color, and the ticket will come with a randomly generated ID.
|
||||
|
||||
To identify and select these priority color divs, we will use `querySelectorAll` method
|
||||
|
||||
We want to select all elements with the class name 'priority-color' using `querySelectorAll` and then iterate through each of these elements using the forEach method. Here's how you can do that:
|
||||
|
||||
```javascript
|
||||
let allPriorityColors = document.querySelectorAll('.priority-color');
|
||||
|
||||
allPriorityColors.forEach(function(colorElem) {
|
||||
colorElem.addEventListener('click', function() {
|
||||
// Remove 'active' class from all priority colors
|
||||
allPriorityColors.forEach(function(priorityColorElem) {
|
||||
priorityColorElem.classList.remove('active');
|
||||
});
|
||||
|
||||
// Add 'active' class to the clicked colorElem
|
||||
colorElem.classList.add('active');
|
||||
|
||||
// Implement additional logic to assign the selected color to a task
|
||||
// For example, you can use this space to perform your task color assignment
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
In this code, when a color element with the class 'priority-color' is clicked, the event listener:
|
||||
|
||||
* Iterates through all `allPriorityColors` and removes the 'active' class from each element.
|
||||
* Adds the 'active' class to the clicked `colorElem`.
|
||||
* Implements additional logic to assign the selected color to a task
|
||||
|
||||

|
||||
|
||||
So right now we have implemented such that we can select this color, but now we want to get the value of the particular color.
|
||||
|
||||
Now we will have a **color array**.
|
||||
|
||||
We define an array of colors and updates the modalPriorityColor variable based on the selected color when a color element is clicked.
|
||||
|
||||
```javascript
|
||||
let colors = ["lightpink", "lightgreen", "lightblue", "black"];
|
||||
let modalPriorityColor = colors[colors.length - 1]; // Default to black
|
||||
|
||||
let allPriorityColors = document.querySelectorAll('.priority-color');
|
||||
|
||||
allPriorityColors.forEach(function(colorElem) {
|
||||
colorElem.addEventListener('click', function() {
|
||||
// Remove 'active' class from all priority colors
|
||||
allPriorityColors.forEach(function(priorityColorElem) {
|
||||
priorityColorElem.classList.remove('active');
|
||||
});
|
||||
|
||||
// Add 'active' class to the clicked colorElem
|
||||
colorElem.classList.add('active');
|
||||
|
||||
modalPriorityColor = colorElem.classList[0]; // Update modalPriorityColor
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
In this code:
|
||||
|
||||
* You define an array colors with color names.
|
||||
* `modalPriorityColor` is initially set to the last color in the array ('black') as the default.
|
||||
* The event listener loop iterates through each color element and adds a click event listener.
|
||||
* When a color element is clicked, the 'active' class is toggled as before.
|
||||
* Additionally, the `modalPriorityColor` is updated to match the class name of the clicked color element, indicating the selected color.
|
||||
|
||||
|
||||
|
||||
**Passing ticketColor to createTicket Function:**
|
||||
|
||||
In the `createTicket` function, you need to add a parameter `ticketColor` to the function signature. This parameter is intended to hold the selected color for the ticket. When calling the `createTicket` function inside the `modalCont` event listener, you're passing the `modalPriorityColor` as an argument to this function.
|
||||
|
||||
This change allows you to set the ticket color dynamically based on the selected priority color. You can use the ticketColor parameter to apply the selected color to the appropriate part of the ticket's HTML content.
|
||||
|
||||
```javascript
|
||||
function createTicket(ticketColor) {
|
||||
// Create a new ticket container element
|
||||
let ticketCont = document.createElement('div');
|
||||
ticketCont.setAttribute('class', 'ticket-cont');
|
||||
|
||||
// Create the HTML content for the ticket container
|
||||
ticketCont.innerHTML = `
|
||||
<div class="ticket-color" style="background-color: ${ticketColor};"></div>
|
||||
<div class="ticket-id">12345</div>
|
||||
<div class="task-area">Random Task</div>
|
||||
`;
|
||||
|
||||
// Append the ticket container to the main container
|
||||
mainCont.appendChild(ticketCont);
|
||||
}
|
||||
|
||||
// Event listener for 'Shift' key press in modalCont
|
||||
modalCont.addEventListener('keydown', function(e) {
|
||||
let key = e.key;
|
||||
|
||||
if (key === 'Shift') {
|
||||
createTicket(modelPriorityColor); // Create a new ticket with the selected color
|
||||
modalCont.style.display = 'none'; // Hide the modal
|
||||
textArea.value = ''; // Clear the textarea's content
|
||||
}
|
||||
});
|
||||
```
|
||||

|
||||
|
||||
|
||||
Now we need to update the task details
|
||||
|
||||
* The `createTicket` function accepts two parameters: `ticketColor` for the color of the ticket and `ticketTask` for the content of the ticket's task.
|
||||
* The `ticketTask` parameter is used to dynamically insert the task content into the task-area div element.
|
||||
* In the modalCont event listener, the content of the `textAreaCont` element is retrieved using .value and assigned to taskContent.
|
||||
* When the 'Shift' key is pressed, a new ticket is created with the selected color and task content, and then the modal is hidden.
|
||||
* The content of the `textAreaCont` element is cleared for the next input.
|
||||
|
||||
```javascript
|
||||
function createTicket(ticketColor, ticketTask) {
|
||||
// Create a new ticket container element
|
||||
let ticketCont = document.createElement('div');
|
||||
ticketCont.setAttribute('class', 'ticket-cont');
|
||||
|
||||
// Create the HTML content for the ticket container
|
||||
ticketCont.innerHTML = `
|
||||
<div class="ticket-color" style="background-color: ${ticketColor};"></div>
|
||||
<div class="ticket-id">12345</div>
|
||||
<div class="task-area">${ticketTask}</div>
|
||||
`;
|
||||
|
||||
// Append the ticket container to the main container
|
||||
mainCont.appendChild(ticketCont);
|
||||
}
|
||||
|
||||
// Event listener for 'Shift' key press in modalCont
|
||||
modalCont.addEventListener('keydown', function(e) {
|
||||
let key = e.key;
|
||||
|
||||
if (key === 'Shift') {
|
||||
let taskContent = textAreaCont.value; // Get the content from the textarea
|
||||
createTicket(modelPriorityColor, taskContent); // Create a new ticket with the selected color and task content
|
||||
modalCont.style.display = 'none'; // Hide the modal
|
||||
textAreaCont.value = ''; // Clear the textarea's content
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Now we need to uniquely generate ID for each task created:
|
||||
|
||||
We will be using an external library **shortID** for this
|
||||
|
||||
```javascript
|
||||
function createTicket(ticketColor, ticketID, ticketTask) {
|
||||
// Create a new ticket container element
|
||||
let ticketCont = document.createElement('div');
|
||||
ticketCont.setAttribute('class', 'ticket-cont');
|
||||
|
||||
// Create the HTML content for the ticket container
|
||||
ticketCont.innerHTML = `
|
||||
<div class="ticket-color" style="background-color: ${ticketColor};"></div>
|
||||
<div class="ticket-id">${ticketID}</div>
|
||||
<div class="task-area">${ticketTask}</div>
|
||||
`;
|
||||
|
||||
// Append the ticket container to the main container
|
||||
mainCont.appendChild(ticketCont);
|
||||
}
|
||||
|
||||
// Event listener for 'Shift' key press in modalCont
|
||||
modalCont.addEventListener('keydown', function(e) {
|
||||
let key = e.key;
|
||||
|
||||
if (key === 'Shift') {
|
||||
let taskContent = textAreaCont.value; // Get the content from the textarea
|
||||
let ticketID = shortid(); // Generate a unique ticket ID
|
||||
createTicket(modelPriorityColor, ticketID, taskContent); // Create a new ticket with the selected color, ticket ID, and task content
|
||||
modalCont.style.display = 'none'; // Hide the modal
|
||||
textAreaCont.value = ''; // Clear the textarea's content
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
To remove the task, we can do similarly to what we did for adding task:
|
||||
|
||||
```javascript
|
||||
let removeTaskFlag = false;
|
||||
|
||||
let removeBtn = document.querySelector('.remove-btn'); // Replace with the actual class or ID selector
|
||||
removeBtn.addEventListener('click', function() {
|
||||
removeTaskFlag = !removeTaskFlag; // Toggle the removeTaskFlag when the button is clicked
|
||||
|
||||
if (removeTaskFlag) {
|
||||
alert('Delete button is activated.');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
@@ -0,0 +1,172 @@
|
||||
# Full Stack LLD & Projects: JavaScript-9: Kanban Board -3(Bussiness Logics & Local Storage)
|
||||
|
||||
|
||||
**Agenda of this Lecture:**
|
||||
|
||||
* Locking Mechanism
|
||||
* Changing the Priority color of the Task
|
||||
* Filtering out Task with using the priority color filter
|
||||
* Showing All Tasks on db click
|
||||
|
||||
|
||||
|
||||
### Explanation
|
||||
|
||||
Currently we have just implemented the project, but we dont have any lock in the project.
|
||||
Hence, we will be implementing the lock in this section
|
||||
|
||||
We can use the **font-awesome** and get a lock icon for our tasks.
|
||||
|
||||
|
||||
```javascript
|
||||
function createTicket(ticketColor, ticketID, ticketTask) {
|
||||
// Create a new ticket container element
|
||||
let ticketCont = document.createElement('div');
|
||||
ticketCont.setAttribute('class', 'ticket-cont');
|
||||
|
||||
// Create the HTML content for the ticket container
|
||||
ticketCont.innerHTML = `
|
||||
<div class="ticket-color" style="background-color: ${ticketColor};"></div>
|
||||
<div class="ticket-id">${ticketID}</div>
|
||||
<div class="task-area">${ticketTask}</div>
|
||||
<div class="ticket-lock"><i class="fa-solid fa-lock"></i></div>
|
||||
`;
|
||||
|
||||
// Append the ticket container to the main container
|
||||
mainCont.appendChild(ticketCont);
|
||||
|
||||
handleRemoval(ticketCont);
|
||||
}
|
||||
```
|
||||
|
||||
* We have added an additional `div` element with the class `ticket-lock` to represent the lock icon for each ticket.
|
||||
* Inside the `ticket-lock` div, you're using Font Awesome's icon syntax to include the lock icon using the fa-lock class from the `fa-solid` style.
|
||||
|
||||

|
||||
|
||||
|
||||
Now we have added the lock, but we need to make it functional now:
|
||||
|
||||
```javascript
|
||||
let lockClose = 'fa-lock';
|
||||
let lockOpen = 'fa-lock-open';
|
||||
|
||||
function handleLock(ticket) {
|
||||
let ticketLockElem = ticket.querySelector('.ticket-lock');
|
||||
let ticketLockIcon = ticketLockElem.children[0];
|
||||
|
||||
ticketLockIcon.addEventListener('click', function() {
|
||||
console.log('Lock Selected'); // Added single quotes around the log message
|
||||
if (ticketLockIcon.classList.contains(lockClose)) {
|
||||
ticketLockIcon.classList.remove(lockClose);
|
||||
ticketLockIcon.classList.add(lockOpen);
|
||||
|
||||
} else {
|
||||
ticketLockIcon.classList.remove(lockOpen);
|
||||
ticketLockIcon.classList.add(lockClose);
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Now to make the content editable inside the task section whenever the lock is open, we will make the following changes:
|
||||
|
||||
```javascript
|
||||
let lockClose = 'fa-lock';
|
||||
let lockOpen = 'fa-lock-open';
|
||||
|
||||
function handleLock(ticket) {
|
||||
let ticketLockElem = ticket.querySelector('.ticket-lock');
|
||||
let ticketLockIcon = ticketLockElem.children[0];
|
||||
|
||||
let ticketTaskArea = ticket.querySelector('.task-area'); // Corrected selector
|
||||
|
||||
ticketLockIcon.addEventListener('click', function() {
|
||||
console.log('Lock Selected');
|
||||
if (ticketLockIcon.classList.contains(lockClose)) {
|
||||
ticketLockIcon.classList.remove(lockClose);
|
||||
ticketLockIcon.classList.add(lockOpen);
|
||||
ticketTaskArea.setAttribute('contenteditable', 'true'); // Changed 'contenteditable', 'true'
|
||||
} else {
|
||||
ticketLockIcon.classList.remove(lockOpen);
|
||||
ticketLockIcon.classList.add(lockClose);
|
||||
ticketTaskArea.setAttribute('contenteditable', 'false'); // Changed 'contenteditable', 'false'
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
* Corrected the selector for `ticketTaskArea` to use '.task-area'.
|
||||
* Changed the `contenteditable` attribute value to 'true' or 'false' to correctly toggle the editable state of the task area based on the lock state.
|
||||
|
||||
|
||||
### Explanation
|
||||
|
||||
In this section we will handle the color of the tasks
|
||||
|
||||
|
||||
|
||||
```javascript
|
||||
function handleColor(ticket) {
|
||||
let ticketColorBand = ticket.querySelector('.ticket-color'); // Corrected selector
|
||||
ticketColorBand.addEventListener('click', function() {
|
||||
let currentColor = ticketColorBand.classList[0]; // Changed index to 0
|
||||
|
||||
let currentColorIdx = colors.findIndex(function(color) {
|
||||
return currentColor === color;
|
||||
});
|
||||
|
||||
currentColorIdx++; // Increment the index
|
||||
|
||||
let newTicketColorIdx = currentColorIdx % colors.length; // Corrected variable name
|
||||
let newTicketColor = colors[newTicketColorIdx]; // Corrected variable name
|
||||
|
||||
ticketColorBand.classList.remove(currentColor); // Corrected spelling
|
||||
ticketColorBand.classList.add(newTicketColor); // Corrected spelling
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### Explanation
|
||||
|
||||
In this feature, we need to filter the task according to the priority color.
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
let toolboxColors = document.querySelectorAll('.color');
|
||||
|
||||
for (let i = 0; i < toolboxColors.length; i++) {
|
||||
toolboxColors[i].addEventListener('click', function() {
|
||||
let selectedToolboxColor = toolboxColors[i].classList[0];
|
||||
|
||||
let allTickets = document.querySelectorAll('.ticket-cont'); // Corrected selector
|
||||
for (let j = 0; j < allTickets.length; j++) {
|
||||
allTickets[j].remove(); // Removed square brackets and added j to index
|
||||
|
||||
let filteredTickets = ticketsArr.filter(function(ticket) {
|
||||
return selectedToolboxColor === ticket.ticketColor;
|
||||
});
|
||||
|
||||
filteredTickets.forEach(function(filteredTicket) {
|
||||
createTicket(
|
||||
filteredTicket.ticketColor,
|
||||
filteredTicket.ticketTask,
|
||||
filteredTicket.ticketID
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
|
@@ -0,0 +1,309 @@
|
||||
|
||||
|
||||
|
||||
In the previous session, we covered topics such as ticket creation, deletion, locking, and unlocking, as well as dynamically changing the priority color. We comprehensively explored the implementation of these functionalities.
|
||||
|
||||
However, a new issue has arisen. Upon initial usage, the filter buttons function as intended. Yet, upon subsequent clicks, a problem arises where duplicate tickets of the selected color are generated.
|
||||
|
||||
What might be the underlying cause of this problem?
|
||||
|
||||
To address this issue, we're planning to implement a validation process using unique identifier to prevent the occurrence of duplicate tickets.
|
||||
|
||||
|
||||
This is the code that we have implemented till now for filtering tickets.
|
||||
|
||||
|
||||
We've executed the loop that iterates through the toolbox colors, covering every index. For each color dip, we've attached corresponding event listeners. When a click event occurs, our first step is to determine which color dip or filter was clicked – for instance, selecting black would mean retrieving tasks labeled with a black priority color.
|
||||
|
||||
Following the color selection from the toolbox, we proceed to match that color with the colors associated with each ticket. We apply a filtering process to narrow down the array of tickets to only include those that match the selected color. The result is an array of filtered tickets, where each ticket object contains information like color values, task details, and IDs.
|
||||
|
||||
At this juncture, we remove the default set of tickets and replace them with the newly filtered array. This is the approach we discussed in the previous session. However, an issue arises when we repeatedly select a color, leading to the duplication of arrays.
|
||||
|
||||
|
||||

|
||||
|
||||
#### Pseudocode
|
||||
```javascript
|
||||
|
||||
for (let i = 0; i < toolboxColors.length; i++) {
|
||||
toolboxColors[i].addEventListener('click', function() {
|
||||
let selectedToolBoxColor = toolboxColors[i].classList[0];
|
||||
|
||||
let filteredTickets = ticketsArr.filter(function(ticket) {
|
||||
return selectedToolBoxColor === ticket.ticketColor;
|
||||
});
|
||||
|
||||
let allTickets = document.querySelectorAll('.ticket-cont');
|
||||
|
||||
for (let i = 0; i < allTickets.length; i++) {
|
||||
allTickets[i].remove();
|
||||
}
|
||||
|
||||
filteredTickets.forEach(function(filteredTicket) {
|
||||
createTicket(filteredTicket.ticketColor, filteredTicket.ticketTask, filteredTicket.ticketId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
To tackle this issue, we're planning to implement a validation mechanism that utilizes unique identifier to ensure that duplicate tickets aren't generated. This way, the filtered ticket array will only consist of distinct tickets corresponding to the selected color.
|
||||
|
||||
|
||||
So, using the unique IDs associated with each ticket is a great way to prevent duplicates. This way, we can ensure that the same ticket isn't added to the filtered array more than once.
|
||||
|
||||

|
||||
|
||||
In which part of the code should you integrate this ID-checking mechanism to effectively prevent duplicate tickets from being included in the filtered array?
|
||||
|
||||
Within the createTicket method, we'll implement the following logic: if a ticket possesses an existing ID, it will be used; otherwise, a new unique ID will be generated during its initial creation. It's essential to note that the ticket will only be pushed to the array if it lacks an ID, ensuring avoidance of duplication.
|
||||
|
||||
|
||||
#### Pseudocode
|
||||
```javascript
|
||||
function createTicket(ticketColor, ticketTask, ticketId) {
|
||||
// Adding an identifier
|
||||
let id = ticketId || shortid();
|
||||
}
|
||||
```
|
||||
|
||||
Prior to adding the ID to the array, we will perform a validation to ascertain its existence, and only if it indeed exists, will it be appended within the createTicket method.
|
||||
|
||||
#### Pseudocode
|
||||
```javascript
|
||||
function createTicket(ticketColor, ticketTask, ticketId) {
|
||||
// Adding an identifier
|
||||
let id = ticketId || shortid();
|
||||
|
||||
// Other code
|
||||
|
||||
if (!ticketId) {
|
||||
ticketArr.push({ ticketColor, ticketTask, ticketId: id });
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
title: What is local storage?
|
||||
description: Gaining Insight into Local Storage and How to Utilize It
|
||||
duration: 600
|
||||
card_type: cue_card
|
||||
---
|
||||
|
||||
> Note to instructor - Address any questions that the students might have.
|
||||
|
||||
|
||||
What kind of ID will the shortid library generate?
|
||||
|
||||
It will produce a random ID for the ticket.
|
||||
|
||||
|
||||
Upon accessing your browser, you'll encounter the inspect page, which offers a variety of elements to explore. Within this inspect interface, navigate to the application tab. Here, you'll be presented with numerous sections such as local storage, session storage, and cookies. For today's discussion, our focus will be on local storage.
|
||||
|
||||
What exactly is local storage? What are your thoughts on the ideal function of local storage?
|
||||
|
||||
The issue lies in data loss when a page is refreshed. We intend for the application to retain data even after a refresh – that's the core purpose of having this feature.
|
||||
|
||||
This occurrence arises from our utilization of local storage as the repository for all our data. Now, let's delve into the concept of local storage. In essence, it offers the capacity to store up to 5mb of information, enabling your browser to retain such data. Imagine a scenario where you're crafting an application and the need for a database isn't there. In situations where a 5-megabyte threshold suffices, local storage serves as a viable means to preserve and manage the data.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
What is a Windows object?
|
||||
|
||||
Within JavaScript, resides the window object. This object grants access to an array of properties, methods, and functionalities offered by the Document Object Model (DOM).
|
||||
|
||||
|
||||
#### Pseudocode
|
||||
|
||||
```htmlembedded
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Title of the document</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- The content of the document... -->
|
||||
</body>
|
||||
|
||||
<script>
|
||||
console.log(window);
|
||||
</script>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||

|
||||
|
||||
We can use numerous methods and properties within the browser including local storage feature. Access to local storage is facilitated through the window object. Within local storage, you can engage actions like setting an item and getting an item. The "setItem" function is utilized to store data, while "getItem" serves to retrieve stored data. This data is maintained in a JavaScript-oriented key-value structure.
|
||||
|
||||
Moreover, there's a "removeItem" capability that permits the deletion of specific entries from local storage. Should the need arise to completely erase all data, the "localStorage.clear" command accomplishes that task.
|
||||
|
||||
|
||||
|
||||
Now, let's see how we are gonna implement local storage
|
||||
|
||||
|
||||
In which scenarios will the requirement for local storage arise?
|
||||
|
||||
Let's review all our functionalities:
|
||||
|
||||

|
||||
|
||||
|
||||
a. Creating a ticket involves storing them within local storage.
|
||||
b. Updating a ticket, whether altering its color or task, entails updating these modified values in local storage.
|
||||
c. Deleting a ticket results in its removal from local storage.
|
||||
|
||||
Notably, if you refrain from deletion and subsequently refresh the page, local storage will retain the instance of that particular ticket, so we need to remove that from local storage to reflect the data.
|
||||
|
||||
Whenever a ticket creation occurs, we have the option to store it in local storage using the "setItem" method. This involves providing the name of the array as a parameter. Here, during the code insertion within the createTicket method, we will employ the setItem function of localStorage:
|
||||
|
||||
#### Pseudocode
|
||||
```javascript
|
||||
|
||||
function createTicket(ticketColor, ticketTask, ticketId) {
|
||||
if (!ticketId) {
|
||||
ticketArr.push({ ticketColor, ticketTask, ticketId: shortid() });
|
||||
localStorage.setItem('tickets', JSON.stringify(ticketArr));
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
It's important to note that local storage accommodates data in string format. Thus, any data you intend to store should be converted into string form before insertion.
|
||||
|
||||
|
||||
> Note to instructor - Test to determine whether the local storage has been successfully established or not.
|
||||
|
||||
|
||||

|
||||
|
||||
After refreshing the page, you'll notice that the data resides within local storage, yet the paradox emerges – despite setting the data, we encounter a loss of the data itself. The situation unfolds as we've successfully stored the data, yet the process of retrieving the values proves elusive.
|
||||
|
||||

|
||||
|
||||
|
||||
We employ the stringify method to establish the data, while the reverse, JSON.parse, allows us to retrieve the data back in JSON format.
|
||||
|
||||
As we initiate the application, our first step is to retrieve all the tickets stored within local storage. If we come across any items designated as "tickets," our subsequent approach revolves around displaying or generating these tickets accordingly. For each of these identified tickets, the createTicket method will be invoked.
|
||||
|
||||
#### Pseudocode
|
||||
```javascript=
|
||||
|
||||
// local storage
|
||||
|
||||
if (localStorage.getItem('tickets')) {
|
||||
ticketsArr = JSON.parse(localStorage.getItem('tickets'));
|
||||
ticketsArr.forEach(function(ticket) {
|
||||
createTicket(ticket.ticketColor, ticket.ticketTask, ticket.ticketId);
|
||||
});
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
> Note to instructor - Test this by refreshing the page again; you'll observe that nothing is removed.
|
||||
|
||||
|
||||
> Note to instructor - Feel free to address any questions that students might have.
|
||||
|
||||
|
||||
Initially, let's construct a function that facilitates the retrieval of the ticket's index using its corresponding ID. The ID will help in identifying the ticket that requires updating.
|
||||
|
||||
#### Pseudocode
|
||||
```javascript
|
||||
|
||||
function getTicketIdx(id) {
|
||||
let ticketIdx = ticketArr.findIndex(function(ticketObj) {
|
||||
return ticketObj.ticketId === id;
|
||||
});
|
||||
return ticketIdx;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Within the handleLock function, whenever a lock is unlocked through a click event, it becomes imperative to retrieve the index of the corresponding ticket. This enables us to determine the specific location where this action occurred.
|
||||
|
||||
|
||||
#### Pseudocode
|
||||
```javascript
|
||||
function handleLock(ticket) {
|
||||
let ticketLockElem = ticket.querySelector('.ticket-lock');
|
||||
let ticketLockIcon = ticketLockElem.children[0];
|
||||
let ticketTaskArea = ticket.querySelector('.task-area');
|
||||
|
||||
ticketLockIcon.addEventListener('click', function() {
|
||||
let ticketIdx = getTicketIdx(id);
|
||||
// Other code
|
||||
|
||||
// Updated task
|
||||
ticketsArr[ticketIdx].ticketTask = ticketTaskArea.innerText;
|
||||
localStorage.setItem('tickets', JSON.stringify(ticketsArr));
|
||||
});
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Henceforth, it will be retained with an updated task.
|
||||
|
||||
|
||||
|
||||
|
||||
Now, let's proceed to explore the color feature.
|
||||
|
||||
|
||||
#### Pseudocode
|
||||
```javascript
|
||||
function handleColor(ticket) {
|
||||
let ticketColorBand = ticket.querySelector('.ticket-color');
|
||||
|
||||
ticketColorBand.addEventListener('click', function() {
|
||||
// getting index
|
||||
let ticketIdx = getTicketIdx(id);
|
||||
let currentColor = ticketColorBand.classList[1];
|
||||
|
||||
let currentColorIdx = colors.findIndex(function(color) {
|
||||
return currentColor === color;
|
||||
});
|
||||
|
||||
currentColorIdx++;
|
||||
|
||||
let newTicketColorIdx = currentColorIdx % colors.length;
|
||||
let newTicketColor = colors[newTicketColorIdx];
|
||||
|
||||
ticketColorBand.classList.remove(currentColor);
|
||||
ticketColorBand.classList.add(newTicketColor);
|
||||
|
||||
// Updated task
|
||||
ticketsArr[ticketIdx].ticketColor = newTicketColor;
|
||||
localStorage.setItem('tickets', JSON.stringify(ticketsArr));
|
||||
});
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
Now, let's evaluate the final feature, which involves deleting data from local storage.
|
||||
|
||||
|
||||
#### Pseudocode
|
||||
```javascript
|
||||
function handleRemoval(ticket) {
|
||||
ticket.addEventListener('click', function() {
|
||||
if (!removeTaskFlag) return;
|
||||
|
||||
let idx = getTicketIdx(id);
|
||||
ticket.remove(); // UI removal
|
||||
|
||||
let deletedElement = ticketsArr.splice(idx, 1);
|
||||
localStorage.setItem('tickets', JSON.stringify(ticketsArr));
|
||||
});
|
||||
}
|
||||
|
||||
```
|
||||
|
@@ -0,0 +1,407 @@
|
||||
|
||||
## Agenda
|
||||
|
||||
- What is Event Propagation?
|
||||
- Concept of Bubbling
|
||||
- Concept of capturing
|
||||
- Machine coding question
|
||||
- Star Rating Component
|
||||
- Counter Component
|
||||
|
||||
We will try to cover most of these topics in today's sessions and the remaining in the next.
|
||||
|
||||
It is going to be a bit challenging, advanced, but very interesting session covering topics that are asked very frequently in interviews.
|
||||
|
||||
So let's start.
|
||||
|
||||
|
||||
## Event Propagation
|
||||
Event propagation refers to the process of how events are dispatched and processed in the Document Object Model (DOM) hierarchy of elements in web development. There are two main phases of event propagation: capturing phase and bubbling phase. During these phases, events can propagate through the DOM tree from the root to the target element (capturing) or from the target element back up to the root (bubbling).
|
||||
|
||||
### Bubbling
|
||||
Event bubbling is one of the phases of event propagation in the DOM. When an event occurs on a DOM element, it first triggers the event handlers on the target element itself, then it bubbles up to its parent elements in the DOM hierarchy. This allows for the creation of more general event listeners that can be applied to parent elements to handle events from multiple child elements.
|
||||
|
||||
### Capturing
|
||||
Event capturing is the other phase of event propagation in the DOM. During the capturing phase, events start from the root element and propagate down to the target element. This phase occurs before the bubbling phase and can be useful when you want to capture events on parent elements before they reach their child elements.
|
||||
|
||||
Certainly, let's use an example to explain event bubbling and capturing with three nested `<div>` elements: `#grandparent`, `#parent`, and `#child`. Suppose you have the following HTML structure:
|
||||
|
||||
```html
|
||||
<div id="grandparent">
|
||||
<div id="parent">
|
||||
<div id="child"></div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Now, let's say we attach a click event listener to each of these `<div>` elements and observe how event propagation works.
|
||||
|
||||
```javascript
|
||||
const grandparent = document.querySelector('#grandparent');
|
||||
const parent = document.querySelector('#parent');
|
||||
const child = document.querySelector('#child');
|
||||
|
||||
grandparent.addEventListener('click', function() {
|
||||
console.log('Grandparent clicked');
|
||||
});
|
||||
|
||||
parent.addEventListener('click', function() {
|
||||
console.log('Parent clicked');
|
||||
});
|
||||
|
||||
child.addEventListener('click', function() {
|
||||
console.log('Child clicked');
|
||||
});
|
||||
```
|
||||
|
||||
Here's how the event propagation works during both the capturing and bubbling phases when you click on the `#child` element:
|
||||
|
||||
1. **Capturing Phase:**
|
||||
When an event occurs, it starts from the root element (`<html>`) and goes down the DOM tree. In this phase, the event handlers are triggered in the following order:
|
||||
|
||||
1. `#grandparent` capturing
|
||||
2. `#parent` capturing
|
||||
3. `#child` capturing (target phase)
|
||||
|
||||
However, we don't have capturing event listeners in this example, so nothing will be logged during this phase.
|
||||
|
||||
2. **Target Phase:**
|
||||
This is where the event reaches the target element, which is `#child`. The event handler for `#child` is triggered, and you will see the message "Child clicked" logged to the console.
|
||||
|
||||
3. **Bubbling Phase:**
|
||||
After the target phase, the event bubbles up through the DOM tree in the opposite direction. The event handlers are triggered in the following order:
|
||||
|
||||
1. `#child` bubbling
|
||||
2. `#parent` bubbling
|
||||
3. `#grandparent` bubbling (root phase)
|
||||
|
||||
As a result, you will see the messages "Parent clicked" and "Grandparent clicked" logged to the console, in that order.
|
||||
|
||||
So, the output in the console when you click on the `#child` element will be:
|
||||
|
||||
```
|
||||
Child clicked
|
||||
Parent clicked
|
||||
Grandparent clicked
|
||||
```
|
||||
|
||||
This example demonstrates the sequence of event propagation during both the capturing and bubbling phases in the context of nested `<div>` elements. The capturing and bubbling phases allow you to handle events at different levels of the DOM hierarchy.
|
||||
|
||||
Let's explore the event propagation using the `useCapture` parameter set to both `true` and `false` for the same example with the three nested `<div>` elements: `#grandparent`, `#parent`, and `#child`.
|
||||
|
||||
```javascript
|
||||
const grandparent = document.querySelector('#grandparent');
|
||||
const parent = document.querySelector('#parent');
|
||||
const child = document.querySelector('#child');
|
||||
|
||||
grandparent.addEventListener('click', function() {
|
||||
console.log('Grandparent clicked (Bubbling)');
|
||||
}, false);
|
||||
|
||||
parent.addEventListener('click', function() {
|
||||
console.log('Parent clicked (Bubbling)');
|
||||
}, false);
|
||||
|
||||
child.addEventListener('click', function() {
|
||||
console.log('Child clicked (Bubbling)');
|
||||
}, false);
|
||||
|
||||
grandparent.addEventListener('click', function() {
|
||||
console.log('Grandparent clicked (Capturing)');
|
||||
}, true);
|
||||
|
||||
parent.addEventListener('click', function() {
|
||||
console.log('Parent clicked (Capturing)');
|
||||
}, true);
|
||||
|
||||
child.addEventListener('click', function() {
|
||||
console.log('Child clicked (Capturing)');
|
||||
}, true);
|
||||
```
|
||||
|
||||
In this example, we've added event listeners with both capturing and bubbling phases for each of the three elements. The `useCapture` parameter is set to `true` for capturing and `false` for bubbling.
|
||||
|
||||
**Scenario 1: useCapture set to `false` (Bubbling)**
|
||||
|
||||
When you click on the `#child` element, the event will propagate in the bubbling phase. The order of event handling will be:
|
||||
|
||||
1. `#child` clicked (Bubbling)
|
||||
2. `#parent` clicked (Bubbling)
|
||||
3. `#grandparent` clicked (Bubbling)
|
||||
|
||||
The output in the console will be:
|
||||
|
||||
```
|
||||
Child clicked (Bubbling)
|
||||
Parent clicked (Bubbling)
|
||||
Grandparent clicked (Bubbling)
|
||||
```
|
||||
|
||||
**Scenario 2: useCapture set to `true` (Capturing)**
|
||||
|
||||
When you click on the `#child` element, the event will propagate in the capturing phase. The order of event handling will be:
|
||||
|
||||
1. `#grandparent` clicked (Capturing)
|
||||
2. `#parent` clicked (Capturing)
|
||||
3. `#child` clicked (Capturing)
|
||||
|
||||
The output in the console will be:
|
||||
|
||||
```
|
||||
Grandparent clicked (Capturing)
|
||||
Parent clicked (Capturing)
|
||||
Child clicked (Capturing)
|
||||
```
|
||||
|
||||
In both scenarios, the event propagation follows the sequence based on the capturing or bubbling phase, as determined by the `useCapture` parameter. Keep in mind that the capturing phase occurs before the bubbling phase and that events propagate through the DOM hierarchy accordingly.
|
||||
|
||||
### Event Propagation Cycle
|
||||
The event propagation cycle refers to the sequence of phases through which an event travels within the Document Object Model (DOM) hierarchy. There are two main phases in the event propagation cycle: the capturing phase and the bubbling phase. Here's an overview of the cycle:
|
||||
|
||||
1. **Capturing Phase:**
|
||||
- The event starts at the root of the DOM tree (typically the `<html>` element).
|
||||
- The event travels down the DOM tree through each ancestor element of the target element.
|
||||
- During this phase, event handlers registered with the capturing phase (`useCapture` set to `true`) are triggered on each ancestor element in the order they appear in the hierarchy from the root to the target.
|
||||
- The event reaches the target element.
|
||||
|
||||
2. **Target Phase:**
|
||||
- The event reaches the target element for which the event was triggered.
|
||||
- Event handlers registered on the target element are executed.
|
||||
|
||||
3. **Bubbling Phase:**
|
||||
- After the target phase, the event travels back up the DOM tree in reverse order.
|
||||
- Event handlers registered with the bubbling phase (`useCapture` set to `false`) are triggered on each ancestor element in the reverse order from the target to the root.
|
||||
- The event eventually reaches the root of the DOM tree.
|
||||
|
||||
This cycle allows developers to define event listeners that respond to events at different levels of the DOM hierarchy. By using capturing and bubbling, you can efficiently manage and handle events on multiple elements without needing to attach individual listeners to each element.
|
||||
|
||||
|
||||
Certainly, let's modify the example to demonstrate how to stop event propagation after the click event on the `#child` element using the `stopPropagation` method. Here's the updated code:
|
||||
|
||||
```javascript
|
||||
const grandparent = document.querySelector('#grandparent');
|
||||
const parent = document.querySelector('#parent');
|
||||
const child = document.querySelector('#child');
|
||||
|
||||
grandparent.addEventListener('click', function(e) {
|
||||
console.log('Grandparent clicked (Bubbling)');
|
||||
});
|
||||
|
||||
parent.addEventListener('click', function(e) {
|
||||
console.log('Parent clicked (Bubbling)');
|
||||
});
|
||||
|
||||
child.addEventListener('click', function(e) {
|
||||
console.log('Child clicked (Bubbling)');
|
||||
e.stopPropagation(); // Stop propagation after clicking the child element
|
||||
});
|
||||
```
|
||||
|
||||
In this example, when you click on the `#child` element, the event propagation will be stopped after the event handler for the `#child` element executes. As a result, the event will not continue to bubble up to the parent and grandparent elements. Only the message "Child clicked (Bubbling)" will be logged to the console.
|
||||
|
||||
If you remove the line `e.stopPropagation();`, you'll see the standard bubbling behavior where the event continues to propagate, and you'll see all three messages in the console: "Child clicked (Bubbling)", "Parent clicked (Bubbling)", and "Grandparent clicked (Bubbling)".
|
||||
|
||||
Remember that stopping propagation can impact the expected behavior of event handling, so it should be used with caution and only when necessary.
|
||||
|
||||
|
||||
|
||||
|
||||
Here are the problem statements for each of the machine coding round problems you mentioned:
|
||||
|
||||
1. **Star Rating Component:**
|
||||
Design a star rating component that allows users to rate something using stars. The component should display a visual representation of the rating using filled and empty stars. Users can click on the stars to select a rating.
|
||||
|
||||
2. **Counter Component:**
|
||||
|
||||
3. **Nested Comment System:**
|
||||
Build a nested comment system where users can leave comments on a post. Each comment can have replies, creating a nested structure. Users should be able to reply to comments and collapse/expand comment threads.
|
||||
|
||||
4. **Product Card Component:**
|
||||
Design a product card component that displays information about a product. It should include details like the product name, image, price, and a "Add to Cart" button. Users can click the button to add the product to their cart.
|
||||
|
||||
5. **OTP Input Section:**
|
||||
Implement an OTP (One-Time Password) input section where users receive an OTP via SMS or email and need to enter it to verify their identity. The component should provide a field for each digit of the OTP and handle the validation process.
|
||||
|
||||
For each problem, you'll need to design and implement a solution using the programming language of your choice. Make sure to consider the user experience, error handling, and any other relevant aspects. Depending on the context of the coding round, you might be required to write modular and efficient code, handle edge cases, and possibly interact with a user interface (if applicable).
|
||||
|
||||
### Creating a counter component
|
||||
Firstly we will be discussing the problem statement of Creating a counter component that displays a number and has buttons to increment and decrement the number. The user should be able to click the buttons to increase or decrease the displayed number.
|
||||
|
||||
Certainly, here's a simple implementation of a counter app using HTML, CSS, and JavaScript that includes the functionalities you mentioned:
|
||||
|
||||
**HTML (index.html):**
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<title>Counter App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="counter">
|
||||
<button class="btn" id="decrement">-</button>
|
||||
<span id="count">0</span>
|
||||
<button class="btn" id="increment">+</button>
|
||||
<button class="btn" id="reset">Reset</button>
|
||||
</div>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
**CSS (styles.css):**
|
||||
```css
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.counter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 15px;
|
||||
font-size: 18px;
|
||||
background-color: #3498db;
|
||||
color: #fff;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
```
|
||||
|
||||
**JavaScript (script.js):**
|
||||
```javascript
|
||||
const decrementButton = document.getElementById('decrement');
|
||||
const incrementButton = document.getElementById('increment');
|
||||
const resetButton = document.getElementById('reset');
|
||||
const countDisplay = document.getElementById('count');
|
||||
|
||||
let count = 0;
|
||||
|
||||
decrementButton.addEventListener('click', () => {
|
||||
if (count > 0) {
|
||||
count--;
|
||||
countDisplay.textContent = count;
|
||||
}
|
||||
});
|
||||
|
||||
incrementButton.addEventListener('click', () => {
|
||||
count++;
|
||||
countDisplay.textContent = count;
|
||||
});
|
||||
|
||||
resetButton.addEventListener('click', () => {
|
||||
count = 0;
|
||||
countDisplay.textContent = count;
|
||||
});
|
||||
```
|
||||
|
||||
In this implementation, we have an HTML structure with buttons for decrementing, incrementing, and resetting the counter. The JavaScript code adds event listeners to these buttons to handle their respective functionalities. The counter value is displayed and updated in the `countDisplay` element. The CSS styles provide a basic look for the counter app.
|
||||
|
||||
Copy and paste the HTML, CSS, and JavaScript code into separate files (index.html, styles.css, script.js) in the same directory, and then open the index.html file in a web browser to see and interact with the counter app.
|
||||
|
||||
### Star Rating Component
|
||||
Firstly we will be discussing the problem statement of Designing a star rating component that allows users to rate something using stars. The component should display a visual representation of the rating using filled and empty stars. Users can click on the stars to select a rating..
|
||||
|
||||
Absolutely, here's an explanation for the star rating component that includes comments in the JavaScript code to help you understand how it works:
|
||||
|
||||
**index.html:**
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<title>Star Rating Component</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="rating">
|
||||
<!-- Display five stars, each with a data-value attribute representing its rating value -->
|
||||
<span id="stars">
|
||||
<span class="star" data-value="1">★</span>
|
||||
<span class="star" data-value="2">★</span>
|
||||
<span class="star" data-value="3">★</span>
|
||||
<span class="star" data-value="4">★</span>
|
||||
<span class="star" data-value="5">★</span>
|
||||
</span>
|
||||
<!-- Display the current rating -->
|
||||
<p>Rating: <span id="rating">0</span>/5</p>
|
||||
</div>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
**script.js:**
|
||||
```javascript
|
||||
// Get all star elements
|
||||
const stars = document.querySelectorAll('.star');
|
||||
|
||||
// Get the rating display element
|
||||
const ratingDisplay = document.getElementById('rating');
|
||||
|
||||
// Add a click event listener to each star
|
||||
stars.forEach(star => {
|
||||
star.addEventListener('click', () => {
|
||||
// Get the value from the data-value attribute
|
||||
const value = parseInt(star.getAttribute('data-value'));
|
||||
// Update the rating display and stars based on the clicked value
|
||||
updateRating(value);
|
||||
});
|
||||
});
|
||||
|
||||
// Function to update the rating display and filled stars
|
||||
function updateRating(value) {
|
||||
stars.forEach(star => {
|
||||
// Get the value from the data-value attribute
|
||||
const starValue = parseInt(star.getAttribute('data-value'));
|
||||
// Toggle the 'filled' class based on whether the star's value is less than or equal to the selected value
|
||||
star.classList.toggle('filled', starValue <= value);
|
||||
});
|
||||
// Update the rating display text content
|
||||
ratingDisplay.textContent = value;
|
||||
}
|
||||
```
|
||||
|
||||
**styles.css:**
|
||||
```css
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.rating {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.star {
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.star.filled {
|
||||
color: gold;
|
||||
}
|
||||
```
|
||||
|
||||
In this star rating component, users can click on stars to indicate their rating. The JavaScript code adds a click event listener to each star, and the `updateRating` function toggles the "filled" class on stars based on their value compared to the selected rating. The CSS styles provide visual feedback by changing the color of filled stars to gold.
|
||||
|
@@ -0,0 +1,269 @@
|
||||
|
||||
## Agenda
|
||||
|
||||
- What is Event Delegation?
|
||||
- Relation with concept of Bubbling
|
||||
- Machine coding question
|
||||
- Star Rating Component
|
||||
- Counter Component
|
||||
|
||||
We will try to cover most of these topics in today's sessions and the remaining in the next.
|
||||
|
||||
It is going to be a bit challenging, advanced, but very interesting session covering topics that are asked very frequently in interviews.
|
||||
|
||||
So let's start.
|
||||
|
||||
## Event delegation
|
||||
|
||||
Event delegation and event bubbling are closely related concepts that work hand-in-hand to optimize event handling in web development. When applied together, they provide an efficient way to manage interactions on a large number of elements.
|
||||
|
||||
Imagine you're browsing a website like Amazon, and on the product listing page, there are multiple product cards, each containing an "Add to Cart" button. Here's how event delegation and event bubbling come into play:
|
||||
|
||||
1. **Event Delegation:**
|
||||
Event delegation involves attaching a single event listener to a common ancestor element (in this case, the container holding the product cards). Instead of placing event listeners on each "Add to Cart" button individually, you attach one listener to the container.
|
||||
|
||||
2. **Event Bubbling:**
|
||||
Event bubbling refers to the natural propagation of an event through the DOM hierarchy. When an event occurs on a deeply nested element, it first triggers the event handler on that element and then "bubbles up" through its ancestors.
|
||||
|
||||
Now, let's see how these concepts work together:
|
||||
|
||||
- When a user clicks the "Add to Cart" button on a product card, the event starts at the button (target) and then bubbles up through its parent elements.
|
||||
- Since you've attached a single event listener to the container holding the product cards, the event bubbles up to the container.
|
||||
- The event listener captures the event at the container level and checks whether the clicked element (the button) matches certain criteria (e.g., having the class `add-to-cart`).
|
||||
- If the criteria are met, the listener knows that an "Add to Cart" action is intended and can extract information about the specific product from the event's context
|
||||
|
||||
Let's go through an example with code to demonstrate event delegation and event bubbling using different categories of products (headphones, laptops, mobiles) on a web page:
|
||||
|
||||
**HTML Structure:**
|
||||
```html
|
||||
<div id="categories">
|
||||
<div class="category" id="headphones">
|
||||
<h2>Headphones</h2>
|
||||
<div class="product">Product A</div>
|
||||
<div class="product">Product B</div>
|
||||
</div>
|
||||
<div class="category" id="laptops">
|
||||
<h2>Laptops</h2>
|
||||
<div class="product">Product X</div>
|
||||
<div class="product">Product Y</div>
|
||||
</div>
|
||||
<div class="category" id="mobiles">
|
||||
<h2>Mobiles</h2>
|
||||
<div class="product">Product P</div>
|
||||
<div class="product">Product Q</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**JavaScript:**
|
||||
```javascript
|
||||
const categoriesContainer = document.getElementById('categories');
|
||||
|
||||
categoriesContainer.addEventListener('click', (event) => {
|
||||
const clickedElement = event.target;
|
||||
|
||||
// Check if the clicked element is a product
|
||||
if (clickedElement.classList.contains('product')) {
|
||||
const category = clickedElement.closest('.category').querySelector('h2').textContent;
|
||||
const product = clickedElement.textContent;
|
||||
|
||||
console.log(`Clicked on ${product} in the ${category} category.`);
|
||||
// Handle the click action for the product here
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `categoriesContainer` element is the common ancestor for all categories and products.
|
||||
- The event listener is attached to the `categoriesContainer` to capture clicks on any of its child elements.
|
||||
- When a product is clicked, the event bubbles up through the category section, reaching the `categoriesContainer`.
|
||||
- The listener checks if the clicked element has the class `product`. If it does, it extracts the category and product information and performs the necessary action.
|
||||
- This code efficiently handles clicks on products within any category, demonstrating the combined usage of event delegation and event bubbling.
|
||||
|
||||
With this setup, regardless of the number of categories or products, you only need one event listener to handle all clicks, making your code more maintainable and efficient.
|
||||
|
||||
Let's create an example where event delegation is used to change the background color of elements by clicking on them. In this example, we'll create a set of colored boxes, and clicking on any box will change its background color using event delegation.
|
||||
|
||||
**HTML Structure:**
|
||||
```html
|
||||
<div id="colorPalette">
|
||||
<div class="color-box" style="background-color: red;"></div>
|
||||
<div class="color-box" style="background-color: green;"></div>
|
||||
<div class="color-box" style="background-color: blue;"></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**JavaScript:**
|
||||
```javascript
|
||||
const colorPalette = document.getElementById('colorPalette');
|
||||
|
||||
colorPalette.addEventListener('click', (event) => {
|
||||
const clickedElement = event.target;
|
||||
|
||||
// Check if the clicked element is a color box
|
||||
if (clickedElement.classList.contains('color-box')) {
|
||||
const color = clickedElement.style.backgroundColor;
|
||||
document.body.style.backgroundColor = color;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `colorPalette` element is the common ancestor for all color boxes.
|
||||
- The event listener is attached to the `colorPalette` to capture clicks on any of its child elements.
|
||||
- When a color box is clicked, the event bubbles up to the `colorPalette`.
|
||||
- The listener checks if the clicked element has the class `color-box`. If it does, it extracts the background color of the clicked color box.
|
||||
- The background color of the `body` element is then set to the extracted color, effectively changing the page's background color.
|
||||
|
||||
This example demonstrates how event delegation can be used to efficiently manage interactions across a set of elements, in this case, color boxes. By using event delegation, you handle all color box clicks with a single event listener, making the code cleaner and more maintainable.
|
||||
|
||||
Here are the problem statements for each of the machine coding round problems you mentioned:
|
||||
|
||||
1. **Star Rating Component:**
|
||||
Design a star rating component that allows users to rate something using stars. The component should display a visual representation of the rating using filled and empty stars. Users can click on the stars to select a rating.
|
||||
|
||||
2. **Counter Component:**
|
||||
|
||||
3. **Nested Comment System:**
|
||||
Build a nested comment system where users can leave comments on a post. Each comment can have replies, creating a nested structure. Users should be able to reply to comments and collapse/expand comment threads.
|
||||
|
||||
4. **Product Card Component:**
|
||||
Design a product card component that displays information about a product. It should include details like the product name, image, price, and a "Add to Cart" button. Users can click the button to add the product to their cart.
|
||||
|
||||
5. **OTP Input Section:**
|
||||
Implement an OTP (One-Time Password) input section where users receive an OTP via SMS or email and need to enter it to verify their identity. The component should provide a field for each digit of the OTP and handle the validation process.
|
||||
|
||||
### Nested Comment System
|
||||
Firstly we will be discussing the problem statement of building a nested comment system where users can leave comments on a post. Each comment can have replies, creating a nested structure. Users should be able to reply to comments and collapse/expand comment threads.
|
||||
|
||||
**Nested Comment System: Overview**
|
||||
|
||||
A nested comment system allows users to leave comments on a post, and each comment can have replies, forming a threaded or hierarchical structure. Users should also be able to collapse and expand comment threads for better readability. This is commonly seen on social media platforms and discussion forums.
|
||||
|
||||
- **Nested Structure:** Comments are organized hierarchically, where each comment can have zero or more child comments (replies).
|
||||
- **Collapse/Expand:** Users can collapse or expand comment threads to show or hide replies, improving readability for lengthy discussions.
|
||||
- **Event Delegation:** Since comments can be added dynamically, event delegation is useful for handling interactions like replying and collapsing.
|
||||
|
||||
**HTML Structure:**
|
||||
|
||||
```<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<title>Nested Comments Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="comments">
|
||||
<div class="comment">
|
||||
<p>User A: This is a great post!</p>
|
||||
<button class="reply-btn">Reply</button>
|
||||
<button class="collapse-btn">Collapse</button>
|
||||
<div class="replies">
|
||||
<div class="comment">
|
||||
<p>User B: I agree!</p>
|
||||
<button class="reply-btn">Reply</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
**CSS:**
|
||||
|
||||
```css
|
||||
.comment {
|
||||
margin: 10px;
|
||||
border: 1px solid #ccc;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.reply-btn,
|
||||
.collapse-btn {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.all-comment:not(:first-child) {
|
||||
margin-left: 4rem;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**JavaScript:**
|
||||
|
||||
```javascript
|
||||
const commentsContainer = document.getElementById('comments');
|
||||
|
||||
commentsContainer.addEventListener('click', (event) => {
|
||||
const clickedElement = event.target;
|
||||
|
||||
// Handle replying to comments
|
||||
if (clickedElement.classList.contains('reply-btn')) {
|
||||
const comment = clickedElement.closest('.comment');
|
||||
const replyBox = document.createElement('div');
|
||||
replyBox.className = 'comment reply';
|
||||
replyBox.innerHTML = `
|
||||
<p><input type="text" placeholder="Your reply..."></p>
|
||||
<button class="submit-btn">Submit</button>
|
||||
`;
|
||||
comment.querySelector('.replies').appendChild(replyBox);
|
||||
}
|
||||
|
||||
// Handle collapsing/expanding comment threads
|
||||
if (clickedElement.classList.contains('collapse-btn')) {
|
||||
const comment = clickedElement.closest('.comment');
|
||||
const replies = comment.querySelector('.replies');
|
||||
replies.style.display = replies.style.display === 'none' ? 'block' : 'none';
|
||||
}
|
||||
});
|
||||
|
||||
commentsContainer.addEventListener('click', (event) => {
|
||||
const clickedElement = event.target;
|
||||
|
||||
// Handle submitting replies
|
||||
if (clickedElement.classList.contains('submit-btn')) {
|
||||
const replyInput = clickedElement.closest('.comment.reply').querySelector('input');
|
||||
const replyText = replyInput.value;
|
||||
const newReply = document.createElement('div');
|
||||
newReply.className = 'comment';
|
||||
newReply.innerHTML = `<p>User: ${replyText}</p>`;
|
||||
clickedElement.closest('.comment.reply').appendChild(newReply);
|
||||
replyInput.value = '';
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Explanation:**
|
||||
|
||||
- The HTML structure represents a simple comment system with reply and collapse buttons.
|
||||
- The CSS provides basic styling for comments and buttons.
|
||||
- The JavaScript code uses event delegation on the `commentsContainer`.
|
||||
- When the "Reply" button is clicked, a new reply box is dynamically added under the corresponding comment.
|
||||
- When the "Collapse" button is clicked, the replies are toggled to show or hide.
|
||||
|
||||
This example demonstrates a basic nested comment system. Depending on your requirements, you can expand this system to include user authentication, data storage, and more advanced features.
|
||||
|
||||
Assuming you integrate the provided HTML, CSS, and JavaScript code and open the HTML file in a web browser, here's what you can expect:
|
||||
|
||||
1. The page will display a comment with a "Reply" button and a "Collapse" button.
|
||||
2. Clicking the "Reply" button will create a new reply box beneath the comment where users can input their replies.
|
||||
3. Clicking the "Collapse" button will toggle the visibility of the replies.
|
||||
|
||||
For the sake of visualization, imagine that you see a page with a comment, and when you click the "Reply" button, a new reply box appears under the comment. If you click the "Collapse" button, the replies will be hidden, and clicking it again will show them again.
|
||||
|
||||
Please note that you'll need to create an HTML file and include the provided HTML, CSS, and JavaScript code within appropriate sections (HTML, `<style>` for CSS, and `<script>` for JavaScript) for this to work as intended.
|
||||
|
||||
In this example, the CSS rule .all-comment:not(:first-child) targets all elements with the class .all-comment except for the first one, and applies a left margin of 4rem to create an indentation effect. However, I noticed that your HTML structure uses the class .comment for comments, so I've updated the rule in the CSS accordingly.
|
||||
``` css
|
||||
.all-comment:not(:first-child){
|
||||
margin-left:4rem;
|
||||
}
|
||||
```
|
||||
You can place this CSS rule in your styles.css file to achieve the desired indentation for nested comments. Just ensure that the structure of your HTML matches the example provided.
|
Reference in New Issue
Block a user